Users browsing this thread: 1 Guest(s)
Expansion of Treasure Chest subroutine
07-14-2018, 11:42 PM
(This post was last modified: 07-15-2018, 12:33 AM by NPCnextdoor.)
Update: I started the expansion with gold treasure chests.
When I asked about how Final Fantasy VI handled 16 by 8-bit multiplication, Assassin wrote to look at C2/47B7. I must admit, I did not fully understand how it worked. Also, I noticed that the division process I used to get the chest ID did not work properly. By the time I arrive at the Returner's Hideout, most of the chests and pots are already empty. So, I decided to wrote my own subroutines instead of relying of the special registers that may or may not be used by something else. I have yet to write the long division, but here is my multiplication subroutine. (I love to say subroutine, I feel like I'm in Star Trek! )
I first experimented with hardcoding the multiplier, 10 in this case.
So, of course, I wanted to automate the process for any 16-bit value so that I can reuse this subroutine. Here is what I got:
I still don't understand why DEC $1C seems to be a 16-bit operation but INC $24 is only a 8-bit one. Does JSR has something to do with it? Feel free to propose code optimization. This is the result of moving pieces of code back and forth, hence the messy look. Also, is it possible to insert tables? I spend so much time trying to get the formatting right, but the tabulation in the editor doesn't act the same once it's published!
When I asked about how Final Fantasy VI handled 16 by 8-bit multiplication, Assassin wrote to look at C2/47B7. I must admit, I did not fully understand how it worked. Also, I noticed that the division process I used to get the chest ID did not work properly. By the time I arrive at the Returner's Hideout, most of the chests and pots are already empty. So, I decided to wrote my own subroutines instead of relying of the special registers that may or may not be used by something else. I have yet to write the long division, but here is my multiplication subroutine. (I love to say subroutine, I feel like I'm in Star Trek! )
I first experimented with hardcoding the multiplier, 10 in this case.
Code:
C2 21 REP #$21 16-bit mode + clear Carry bit
64 24 STZ $24 Store zeroes in bytes 4 ($24) and 3 ($25)
A5 1A LDA $1A Load multiplicand (base GP value) in A
0A -- ASL -- Left-shift A, therefore doubling base GP value
90 02 BCC 2ND_MULT If the multiplication doesn't set the Carry bit (or, does the multiplication of the first two-bytes smear into byte 3?), skip next operation
E6 25 INC $25 Add one to byte 3
06 25 ASL $25 -=2ND_MULT=- Left-shift byte 3 (No left-shift of byte 4 is made, because there is no need when multiplying a 16-bit value by 10.)
0A -- ASL -- Left-shift A, multiplication factor is now 4.
90 02 BCC ADDITION If the multiplication doesn't set the Carry bit, skip next operation
E6 25 INC $25 Add one to byte 3
C2 01 REP #$01 -=ADDITION=- Clear Carry bit, making sure it doesn't mess the next operation, an addition
65 1A ADC $1A Add base GP value to A, multiplication factor is now 5.
90 02 BCC 3RD_MULT If the addition doesn't set the Carry bit, skip next operation
E6 25 INC $25 Add one to byte 3
06 25 ASL $25 -=3RD_MULT=- Left-shift byte 3
0A -- ASL -- Left-shift A, multiplication factor is now 10.
90 02 BCC END If multiplication doesn't set the Carry bit, skip next operation
E6 25 INC $25 Add one to byte 3
85 22 STA $22 Store A back into $22
60 -- RTS -- -=END=-
So, of course, I wanted to automate the process for any 16-bit value so that I can reuse this subroutine. Here is what I got:
Code:
C0/D700 C2 31 -- REP #$31 16-bit accumulator mode, 16-bit X and Y registers and clear Carry bit
C0/D702 64 22 -- STZ $22 Store zeroes in byte 2 and 1
C0/D704 64 24 -- STZ $24 Store zeroes in byte 4 and 3
C0/D706 A4 1A -- LDY $1A Load base GP value (multiplicand) into Y
C0/D708 A6 1C -- LDX $1C Load multiplier in X
C0/D70A F0 37 -- BEQ END If X = 0, skip to the end
C0/D70C A9 10 00 LDA #$000F Load (15) into A, the maximum amount of left-shifts possible of a 16-bit value minus 1 before is it guaranteed to become 0
C0/D70F 85 1C -- STA $1C Store A into $1C
C0/D711 8A -- -- TXA -- Transfer X to A
C0/D712 0A -- -- ASL -- -=FIRST_LOOP_START=- Left-shift A
C0/D713 B0 04 -- BCS ADD_ONCE If the Carry bit is set (or, was the previous bit we lost due to left-shifting an 1?), continue into the subroutine
C0/D715 C6 1C -- DEC $1C Decrement $1C, the number of left-shifts remaining.
C0/D717 80 F9 -- BRA FIRST_LOOP_START Go back to the start of the loop.
C0/D719 C6 1C -- DEC $1C -=ADD_ONCE=- Decrement $1C.
C0/D71B 84 22 -- STY $22 Store base GP value into $22, the multiplication factor is now 1.
C0/D71D AA -- -- TAX -- Transfer A to X
C0/D71E A5 1C -- LDA $1C -=SECOND_LOOP_START=- Load remaining number of left-shifts into A, setting or clearing the Zero bit
C0/D720 F0 21 -- BEQ END If A = 0, skip to the end
###MULTIPLICATION BY 2##
C0/D722 A5 24 -- LDA $24 Load bytes 4 and 3 (high bytes) into A
C0/D724 0A -- -- ASL -- Left-shift the high bytes
C0/D725 85 24 -- STA $24 Store the high bytes back into $24
C0/D727 A5 22 -- LDA $22 Load bytes 2 and 1 (low bytes) into A
C0/D729 0A -- -- ASL -- Left-shift the low bytes
C0/D72A 85 22 -- STA $22 Store the low bytes back into $22
########################
C0/D72C B0 16 -- BCS INC_HIGH_BYTE1 If the Carry bit is set (or was the high bit of the low bytes before the left-shifting an 1?), increment the high bytes
C0/D72E 8A -- -- TXA -- -=LSHIFT=- Transfer X to A
C0/D72F 0A -- -- ASL -- Left-shift the multiplier, doubling the multiplication factor
C0/D730 B0 03 -- BCS ADD_MULTIPLICAND If the Carry bit is set, add the multiplicand, incrementing the multiplication factor by 1
C0/D732 AA -- -- TAX -- Transfer A back to X
C0/D733 80 0A -- BRA SECOND_LOOP_END Skip the addition of the multiplicand
###ADDING THE MULTIPLICAND###
C0/D735 AA -- -- TAX -- -=ADD MULTIPLICAND=- Transfer A back to X
C0/D736 98 -- -- TYA -- Transfer the base GP value to A
C0/D737 C2 01 -- REP #$01 Clear the Carry bit
C0/D739 65 22 -- ADC $22 Add to the base GP value the current GP value
C0/D73B 85 22 -- STA $22 Store the sum back into $22
C0/D73D B0 0A -- BCS INC_HIGH_BYTE2 If the Carry bit is set, increment the high bytes
#############################
C0/D73F C6 1C -- DEC $1C -=SECOND_LOOP_END=- Decrement the number of remaining left-shifts
C0/D741 80 DB -- BRA SECOND_LOOP_START Go back to the start of the loop
C0/D743 60 -- -- RTS -- -=END=-
C0/D744 20 4E D7 JSR INC_HIGH_BYTE_START -=INC_HIGH_BYTE1=- Jump to the "Increment the high bytes subroutine"
C0/D747 80 E5 -- BRA LSHIFT Goes back to where we were in the code
C0/D749 20 4E D7 JSR INC_HIGH_BYTE_START -=INC_HIGH_BYTE2=- Jump to the "Increment the high bytes subroutine"
C0/D74C 80 F1 -- BRA SECOND_LOOP_END Goes back to where we were in the code
C0/D74E E6 25 -- INC $25 -=INC_HIGH_BYTE_START=- Increment byte 3
C0/D750 90 02 -- BCC INC_HIGH_BYTE_END If the Carry bit is clear, skip the next operation
C0/D752 E6 24 -- INC $24 Increment byte 4
C0/D754 60 -- -- RTS -- -=INC_HIGH_BYTE_END=-
I still don't understand why DEC $1C seems to be a 16-bit operation but INC $24 is only a 8-bit one. Does JSR has something to do with it? Feel free to propose code optimization. This is the result of moving pieces of code back and forth, hence the messy look. Also, is it possible to insert tables? I spend so much time trying to get the formatting right, but the tabulation in the editor doesn't act the same once it's published!
« Next Oldest | Next Newest »
|
||||
Users browsing this thread: 1 Guest(s)