Hi,
I've been disassembling the code from an LA3 ('88 Turbo Coupe). So far I've identified the interrupt code, some of the tables and some of the functions. Currently I'm trying to figure out a function that does something with the tables. It's accessing a 2 dimensional table at location calculated with "((r52 * r51) + r49) + r57:r56". What I can't figure out is why the three passes through the multiply at the end. Here's the routine, anybody recognize it?
func5943: mulub r54, R52, R51
addb r54, R49
jnc L594E
incb r55
L594E: add r56, R54
ldb r49, [r56]+
ldb r51, [R56]
scall func5972
add r56, R52
ldb r51, [R56]
dec r56
ldb r49, [R56]
ldb r52, R59
scall func5972
ldb r51, R59
ldb r49, R52
ldb r48, R50
func5972: mulub r58, R48, R51
mulub r54, R48, R49
sub r58, R54
addb r59, R49
add r58, #0x0080
ret
Chris
Moderators: EDS50, cgrey8, 2Shaker, Jon 94GT
Re: Disassembling a Math Function
Think about how you would do linear interpolation in a 2D table.
A 1D table, you interpolate between 2 values.
What do you have to do when the value you want lies in the middle of a 2D grid of 4 values?
Understanding the 1D interpolation at 0x589B and how that value is used in 0x5943 would help you also. It's quite simple but clever.
A 1D table, you interpolate between 2 values.
What do you have to do when the value you want lies in the middle of a 2D grid of 4 values?
Understanding the 1D interpolation at 0x589B and how that value is used in 0x5943 would help you also. It's quite simple but clever.
cprhodin wrote:Hi,
I've been disassembling the code from an LA3 ('88 Turbo Coupe). So far I've identified the interrupt code, some of the tables and some of the functions. Currently I'm trying to figure out a function that does something with the tables. It's accessing a 2 dimensional table at location calculated with "((r52 * r51) + r49) + r57:r56". What I can't figure out is why the three passes through the multiply at the end. Here's the routine, anybody recognize it?
func5943: mulub r54, R52, R51
addb r54, R49
jnc L594E
incb r55
L594E: add r56, R54
ldb r49, [r56]+
ldb r51, [R56]
scall func5972
add r56, R52
ldb r51, [R56]
dec r56
ldb r49, [R56]
ldb r52, R59
scall func5972
ldb r51, R59
ldb r49, R52
ldb r48, R50
func5972: mulub r58, R48, R51
mulub r54, R48, R49
sub r58, R54
addb r59, R49
add r58, #0x0080
ret
Chris
Re: Disassembling a Math Function
I'll explain it as explained to me.....
The tables actually represent a 2D to 1D conversion (2 variables to 1 answer).
So imagine BOTH your input variables fall part way between defined points (=cells) in the table.
In effect this means the true answer lies between FOUR cells in the table (those 4 cells surround the point the 2 input variables reference). If you don't get this, STOP and reread it a few times, because it's crucial to understand before going on.
So then all the calc has to do is interpolate the two pairs of cells vertically, and then interpolate the two answers from the two pairs to get the final answer....= 3 interpolates. So that second block of code is simply a math 'interpolate' function.
here's the early version from my box -
3277: 5c,33,34,36 ml3b R36,R34,R33 R36W = R34B * R33B; # Y*cols. Get into correct column.
327b: 74,31,36 ad2b R36,R31 R36 += R31; # (Y*cols)+X. = Correct (lower) cell offset.
327e: d3,02 jnc 3282 if ((uns) R36 >= R31) {
3280: 17,37 incb R37 R37++;} # Add carry if byte o/flow.
3282: 64,36,38 ad2w R38,R36 R38 += R36; # Real cell address, table+offset
3285: b2,39,31 ldb R31,[R38++] R31 = [R38++]; # R31 = [0,0] BASE cell, below input value.
3288: b2,38,33 ldb R33,[R38] R33 = [R38]; # R33 = [1,0] cell, [ next X value]
328b: 28,1c scall 32a9 TabInterp(); # R3b = Interpolated X,0 (R31, R33) by fract X
328d: 64,34,38 ad2w R38,R34 R38 += R34;
3290: b2,38,33 ldb R33,[R38] R33 = [R38]; # R33 = [1,1] cell (next x, next y)
3293: 05,38 decw R38 R38--;
3295: b2,38,31 ldb R31,[R38] R31 = [R38]; # R31 = [0,1] cell (this x, next y)
3298: b0,3b,34 ldb R34,R3b R34 = R3b; # save interpolated X
329b: 28,0c scall 32a9 TabInterp(); # Interpolated (X,1) value by fract X.
329d: b0,3b,33 ldb R33,R3b R33 = R3b; # intpolated (X,1)
32a0: b0,34,31 ldb R31,R34 R31 = R34; # intpolated (X,0)
32a3: b0,32,30 ldb R30,R32 R30 = R32; # set interpolate fraction to Y value
32a6: 28,01 scall 32a9 TabInterp(); # Interpolate intpld(x,0), intpld(x,1) in fraction Y
32a8: f0 ret return
TabInterp:
32a9: 5c,33,30,3a ml3b R3a,R30,R33 R3aW = R30B * R33B; # R3a = fraction * high val
32ad: 5c,31,30,36 ml3b R36,R30,R31 R36W = R30B * R31B; # R36 = fraction * low val
32b1: 68,36,3a sb2w R3a,R36 R3a -= R36; # R3a = (fract*high)-(fract*low) [= increment*fract]
32b4: 74,31,3b ad2b R3b,R31 R3b += R31; # R3b = increment*fract/256 + low
32b7: 65,80,00,3a ad2w R3a,80 R3a += 128; # round up for answer in R3b
32bb: f0 ret return
The tables actually represent a 2D to 1D conversion (2 variables to 1 answer).
So imagine BOTH your input variables fall part way between defined points (=cells) in the table.
In effect this means the true answer lies between FOUR cells in the table (those 4 cells surround the point the 2 input variables reference). If you don't get this, STOP and reread it a few times, because it's crucial to understand before going on.
So then all the calc has to do is interpolate the two pairs of cells vertically, and then interpolate the two answers from the two pairs to get the final answer....= 3 interpolates. So that second block of code is simply a math 'interpolate' function.
here's the early version from my box -
3277: 5c,33,34,36 ml3b R36,R34,R33 R36W = R34B * R33B; # Y*cols. Get into correct column.
327b: 74,31,36 ad2b R36,R31 R36 += R31; # (Y*cols)+X. = Correct (lower) cell offset.
327e: d3,02 jnc 3282 if ((uns) R36 >= R31) {
3280: 17,37 incb R37 R37++;} # Add carry if byte o/flow.
3282: 64,36,38 ad2w R38,R36 R38 += R36; # Real cell address, table+offset
3285: b2,39,31 ldb R31,[R38++] R31 = [R38++]; # R31 = [0,0] BASE cell, below input value.
3288: b2,38,33 ldb R33,[R38] R33 = [R38]; # R33 = [1,0] cell, [ next X value]
328b: 28,1c scall 32a9 TabInterp(); # R3b = Interpolated X,0 (R31, R33) by fract X
328d: 64,34,38 ad2w R38,R34 R38 += R34;
3290: b2,38,33 ldb R33,[R38] R33 = [R38]; # R33 = [1,1] cell (next x, next y)
3293: 05,38 decw R38 R38--;
3295: b2,38,31 ldb R31,[R38] R31 = [R38]; # R31 = [0,1] cell (this x, next y)
3298: b0,3b,34 ldb R34,R3b R34 = R3b; # save interpolated X
329b: 28,0c scall 32a9 TabInterp(); # Interpolated (X,1) value by fract X.
329d: b0,3b,33 ldb R33,R3b R33 = R3b; # intpolated (X,1)
32a0: b0,34,31 ldb R31,R34 R31 = R34; # intpolated (X,0)
32a3: b0,32,30 ldb R30,R32 R30 = R32; # set interpolate fraction to Y value
32a6: 28,01 scall 32a9 TabInterp(); # Interpolate intpld(x,0), intpld(x,1) in fraction Y
32a8: f0 ret return
TabInterp:
32a9: 5c,33,30,3a ml3b R3a,R30,R33 R3aW = R30B * R33B; # R3a = fraction * high val
32ad: 5c,31,30,36 ml3b R36,R30,R31 R36W = R30B * R31B; # R36 = fraction * low val
32b1: 68,36,3a sb2w R3a,R36 R3a -= R36; # R3a = (fract*high)-(fract*low) [= increment*fract]
32b4: 74,31,3b ad2b R3b,R31 R3b += R31; # R3b = increment*fract/256 + low
32b7: 65,80,00,3a ad2w R3a,80 R3a += 128; # round up for answer in R3b
32bb: f0 ret return
TVR, kit cars, classic cars. Ex IT geek, development and databases.
https://github.com/tvrfan/EEC-IV-disassembler
https://github.com/tvrfan/EEC-IV-disassembler
Re: Disassembling a Math Function
Thanks, it's much easier to understand once the intent is made clear. Now I can see that the X,Y points in the table are placed at fixed intervals (256) and the inputs are scaled to the table.
ChrisR
ChrisR
Re: Disassembling a Math Function
Often the tables are set at regular intervals, but not always. That math 'interpolate' strategy still works however, even if the table parameters are not linear.
Note that some of the function lookups are used solely to map variables (like engine temp, rpm, etc) into a scale (say 0-11) which is then used in a lookup table. These aren't always linear (on input), and allow the table scale to be more detailed in some places (like around idle).
It's a very clever and neat solution. Whoever programmed these boxes certainly wasn't dumb !!
Note that some of the function lookups are used solely to map variables (like engine temp, rpm, etc) into a scale (say 0-11) which is then used in a lookup table. These aren't always linear (on input), and allow the table scale to be more detailed in some places (like around idle).
It's a very clever and neat solution. Whoever programmed these boxes certainly wasn't dumb !!
TVR, kit cars, classic cars. Ex IT geek, development and databases.
https://github.com/tvrfan/EEC-IV-disassembler
https://github.com/tvrfan/EEC-IV-disassembler
Who is online
Users browsing this forum: No registered users and 11 guests