Neat programming trick for optional operations

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
OrangyTang
Interested
Posts: 26
Joined: Tue Feb 23, 2016 4:45 pm

Neat programming trick for optional operations

Post by OrangyTang » Tue Sep 18, 2018 3:16 pm

Since work is now less crunchy, I actually managed to find some time to work on my Gunstar Heroes disassem, and stumbled across a neat trick (apologies if this is already known but I thought it was cool):

Code: Select all

MOVE.w	$FFFF8002.w, D0 ; var indicating which processing to perform
							; 0 will never overflow (so will skip all processing)
							; 8000 will overflow once (and afterwards be 0)
							; C000 will overflow twice (and afterwards be 0)
							; E000 will overflow three times (and afterwards be 0)
							; F000 will overflow four times (and afterwards be 0)
	
	ADD.w	D0, D0
	BCC.w	@skipPaletteFunc_000036C6	; skip palette processing if D0 add didn't cause overflow
	
	; palette processing here
	
@skipPaletteFunc_000036C6:
	ADD.w	D0, D0
	BCC.w	@loc_000036DC
	
	; optional processing 2
	
@loc_000036DC:
	ADD.w	D0, D0
	BCC.w	@loc_000036F2
	
	; optional processing 3
	
@loc_000036F2:
	ADD.w	D0, D0
	BCC.w	@loc_00003708
	
	; optional processing 4
	
@loc_00003708:
	RTS
So a single variable controls which out of the four optional bits of code get run, always starting with the first. The first is some kind of palette update and I haven't figured out the rest yet, but it seems like a neat method for doing partial updates depending on a dirty flag. Neat!

User avatar
Sik
Very interested
Posts: 732
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Neat programming trick for optional operations

Post by Sik » Tue Sep 18, 2018 4:33 pm

Yep, ADD D0, D0 pushes the high bit of D0 into carry flag, which then can be checked with a branch. If you know the next bit to check is on the MSB and don't mind modifying the value it's faster than doing BTST (ADD.W is 4 cycles, BTST is 8 off the top of my head).

The trick is normally used when reading arrays compacted into bitfields though (e.g. the token types in LZ-style compression formats, or when expanding 1bpp graphics to 4bpp), it didn't occur to me to also use that to check separate flags that get processed in a row.
Sik is pronounced as "seek", not as "sick".

User avatar
Miquel
Very interested
Posts: 360
Joined: Sat Jul 30, 2016 12:33 am

Re: Neat programming trick for optional operations

Post by Miquel » Thu Sep 20, 2018 1:21 am

OrangyTang wrote:
Tue Sep 18, 2018 3:16 pm
The first is some kind of palette update and I haven't figured out the rest yet, but it seems like a neat method for doing partial updates depending on a dirty flag.
Another advantage to bit operands is you can perform a test and then a set/reset in one operation. Since palette manipulation is going to be once in a while operation makes sense too.

I do something like this (I simplified it a bit, hope there is no mistake):

Code: Select all

	move.l	g_flags.w, d0
	jeq		0f
		lea		RebuildPaletteASM(pc), a0
		bclr.l	#0, d0
		jeq		1f
			moveq.l	#0, d1		/* num palette */
			jsr	(a0)
		1:
		bclr.l	#1, d0
		jeq		2f
			moveq.l	#1, d1
			jsr	(a0)
		2:
		/* ... the same for palette 2 & 3 */
		move.l	d0, g_flags.w
0:
My point is that is convenient to clear the flag to save cpu, significant time in my case since I recalculate each component of every color.
I suppose in the case of “Gunstar Heroes” it dedicates a byte to the 4 palette flags and erases it all together at the end.
All methods are ok as long as don’t do unnecessary somewhat costly palette updates.

User avatar
Miquel
Very interested
Posts: 360
Joined: Sat Jul 30, 2016 12:33 am

Re: Neat programming trick for optional operations

Post by Miquel » Thu Sep 20, 2018 7:15 pm

One more thing, it’s of trivial importance but since is completely correlated with this thread, here we go:

Most data operations check the most significant bit (those are 7, 15 or 31 depending on the operation size) so you don’t need to use the carry flag at all, it will be end up being used due to how ADD operation works but for example you can use tst or move ops instead in other cases.

Lets cut the jumbo jambo, and go for an example:

Code: Select all

	move.b g_flags.w, d0		/* bit 7 is in sign flag */
	jge 0f
		/* Do palette 0 */
	0:
	add.b d0, d0			/* original bit 6 is in sign flag */
	jge 1f
		/* Do palette 1 */
	1:
	add.b d0, d0			/* original bit 5 is in sign flag */
	jge 2f
		/* Do palette 2 */
	2:
	add.b d0, d0			/* original bit 4 is in sign flag */
	jge 3f
		/* Do palette 3 */
	3:
	clr.b g_flags.w

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 3 guests