We've just updated MediaWiki and its underlying software. If anything doesn't look or work quite right, please mention it to us. --RanAS

Bithacks: Difference between revisions

From SnesLab
Jump to: navigation, search
Line 11: Line 11:
<u>outputs:</u> A
<u>outputs:</u> A
<pre>
<pre>
STA $00
STA $00
ASL $00
ASL $00
ROR
ROR
</pre>
</pre>


Line 32: Line 32:
?end:
?end:
endmacro
endmacro
</pre>
'''Absolute Value''' ''(5 bytes / 6 cycles)''
<br>
<u>inputs:</u> A
<br>
<u>outputs:</u> A
<pre>
macro abs()
BPL ?plus
EOR #$FF
INC
?plus: ; only 3 cycles if branch taken
endmacro
</pre>
'''Absolute Value (SEC)''' ''(4 bytes / 4 cycles)''
<br>
<u>inputs:</u> A, (Carry Set)
<br>
<u>outputs:</u> A
<pre>
; compared to the branching version this is 1 byte smaller
; it's either 2 cycles slower/faster depending on branch taken
EOR #$7F
; SEC ; the instant you add this in it becomes worse than the branching version
SBC #$7F
</pre>
'''Magnitude/Extents Check''' ''(~7 bytes / 12 cycles)''
<br>
<u>inputs:</u> A
<br>
<u>outputs:</u> (none)
<pre>
; asks "Is [A] on the zero-side of value [X] or the far side?"
; good for magnitude checks, smaller *AND* faster than alternatives
; NOTE: in the event that it is exactly [X] it will have that value at branch
; doesn't need to be an indexed CMP but is most useful this way
; this can be used to combine the BPL and BMI checks for both signs into one
SEC : SBC Extents,x
EOR Extents,x
BMI .zero_side
.far_side:
; do things
.zero_side:
; do things
Extents:
db -$23, $23
</pre>
</pre>



Revision as of 10:43, 12 April 2021

Bithacks are optimization tricks that utilize information in bits and bit manipulation to accomplish their tasks. Usually they work in a slightly non-obvious way, (the most famous being the fast inverse sqrt), and bit manipulation in general is harder on the 65c816. To that end here is a collection of some useful tricks.
Note: cycle counts are intended to be a worst case measure.

Math Bithacks

Signed Division By 2 (5 bytes / 10 cycles)
inputs: A
outputs: A

	STA $00
	ASL $00
	ROR

Signed Division By 2n (6+2n bytes / 5+2n cycles)
inputs: A, n
outputs: A

; signed division by two, n times
macro SignedDiv_2N(n)
	BMI ?negative
	LSR #<n>
	BRA ?end
?negative:
	LSR #<n>
	ORA #($FF<<(8-<n>))	; sign extension
?end:
endmacro

Absolute Value (5 bytes / 6 cycles)
inputs: A
outputs: A

macro abs()
	BPL ?plus
	EOR #$FF
	INC
?plus:		; only 3 cycles if branch taken
endmacro

Absolute Value (SEC) (4 bytes / 4 cycles)
inputs: A, (Carry Set)
outputs: A

; compared to the branching version this is 1 byte smaller
; it's either 2 cycles slower/faster depending on branch taken
	EOR #$7F
;	SEC		; the instant you add this in it becomes worse than the branching version
	SBC #$7F

Magnitude/Extents Check (~7 bytes / 12 cycles)
inputs: A
outputs: (none)

; asks "Is [A] on the zero-side of value [X] or the far side?"
; good for magnitude checks, smaller *AND* faster than alternatives
; NOTE: in the event that it is exactly [X] it will have that value at branch
; doesn't need to be an indexed CMP but is most useful this way
; this can be used to combine the BPL and BMI checks for both signs into one
	SEC : SBC Extents,x
	EOR Extents,x
	BMI .zero_side
.far_side:
	; do things
.zero_side:
	; do things

Extents:
	db -$23, $23

Misc. Tricks

As this list grows tricks here will be consolidated into their own sections. Clever optimization tricks that aren't necessarily what someone might personally call a "bithack" are okay here as well!

Direction As Index (4 bytes / 6 cycles)
inputs: A
outputs: A

; Ever wonder why facing flags are 0=right and 1=left? This is why. It's incredibly cheap.
ASL : ROL : AND #$01	; get facing as index