I had a nice PM exchange with chysn and as a result I'd like to showcase the debugging capabilites of MINIMON in this thread here. Actually, the routine in question works as expected, but I want to take a look at the intermediary values it calculates, in BASIC, in floating point. Here's the annotated source:
Code: Select all
.Sqrt
JSR $DC1B ; round FAC#1
JSR $DC2B ; check sign of FAC#1
BEQ Sqrt_03 ; =0? Then end immediately! (SQR(0)=0)
BPL Sqrt_00 ; continue, if positive, else
JMP $D248 ; flag ?ILLEGAL QUANTITY ERROR
.Sqrt_00
LDA $61
STA $FB ; remember exponent byte of argument
AND #$01
ORA #$80
STA $61 ; reduce argument X to range [0.5,2.0[
LDA #$04
STA $FC
LDX #Sqrt_04 MOD 256
LDY #Sqrt_04 DIV 256
JSR $DBD4 ; store FAC#1 (X: reduced argument) to Sqrt_04
LDA #$BC
LDY #$D9
BNE Sqrt_02 ; start with Y=1 as first approximation,
.Sqrt_01 ; and loop 4 times, calculating Y=(Y+X/Y)/2.0 each turn
LDX #Sqrt_05 MOD 256
LDY #Sqrt_05 DIV 256
JSR $DBD4 ; store FAC#1 (Y: intermediate value) to Sqrt_05
LDA #Sqrt_04 MOD 256
LDY #Sqrt_04 DIV 256
JSR $DB0F ; FAC#1 = X/Y
LDA #Sqrt_05 MOD 256
LDY #Sqrt_05 DIV 256
.Sqrt_02
JSR $D867 ; FAC#1 = Y+X/Y (=1+X on first entry)
DEC $61 ; divide FAC#1 by 2.0
DEC $FC
BNE Sqrt_01
LDA $FB ; calculate exponent of result
LSR A
ADC #$40
STA $61
.Sqrt_03
RTS
.Sqrt_04
EQUB 0:EQUB 0:EQUB 0:EQUB 0:EQUB 0
.Sqrt_05
EQUB 0:EQUB 0:EQUB 0:EQUB 0:EQUB 0
First, the batch assembly. You see this in action with the movie linked to in the OP of the WIP: MINIMON thread. The input of MINIMON is temporarily redirected to come from a SEQ file:
When the batch assembly has completed, a small helper routine in $0140 restores the default I/O, closes the file and returns to BASIC:
We take a deeper look at the assembled code to search for the equivalent of the line "JSR $DBD4 ; store FAC#1 (Y: intermediate value) to Sqrt_05" ...
... and find it at $02CD:
The intermediate value Y goes to $02F1. We now instrument the code, so we can take a look at the stored floating point value at $02F1 on each loop iteration. A copy of JSR $DBD4 is placed somewhere else as begin of a "knapsack", and followed by a BRK/NOP/RTS sequence. That knapsack in turn is called by a JSR that takes the place of the original JSR $DBD4 at $02CB:
After exiting to BASIC, we do a PRINTUSR(2) to calculate the square root of 2. The print command is preceded by a row of colons, as MINIMON also uses the BASIC line input buffer for its own command line, and we don't want the whole thing to end with a ?SYNTAX error.
During execution, the routine reduces the argument X into the range [0.5,2.0[, so it actually internally calculates the square root of 0.5 and corrects the exponent of the result at the end.
The breakpoint has been called the first time and we see "$80 $40 $00 $00 $00" is stored at $02F1. With G and M, we display the next intermediary values until the routine has finished its calculation and hands control back to the BASIC interpreter:
... with the PRINT result neatly appended to the last G command.
The three intermediary floating point values correspond to the annotated decimal fractions.
>02F1 80 40 00 00 00 ^= 0.75
>02F1 80 35 55 55 55 ^= 0.708333333
>02F1 80 35 05 05 05 ^= 0.707107843
After those three iterations, the next value in FAC #1 is already exact within the floating point accuracy and after correction of the exponent, the result is printed as 1.41421356.
Cheers,
Michael