Users browsing this thread: 1 Guest(s)
Expansion of Treasure Chest subroutine

#6
Posts: 48
Threads: 7
Thanks Received: 0
Thanks Given: 0
Joined: Dec 2017
Reputation: 0
Status
None
Update: I started the expansion with gold treasure chests.

[Image: new_chest_subroutine_00000.png]

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! Tongue )

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! Tongue
  Find
Quote  



Messages In This Thread
RE: Expansion of Treasure Chest subroutine - by NPCnextdoor - 07-14-2018, 11:42 PM

Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite