I wrote a little routine to convert a float to 'woz' format, and it gives me:
Code: Select all
@elysium xtal % wozf 1
f: 80:400000
@elysium xtal % wozf 2
f: 81:400000
I set up space in ZP for three 4-byte FP "registers" at $80 (flt_{x,m}2), $84 (flt_{x,m}1) and $88 (flt_e) - where each one is laid out as {1-byte exponent (x), 3 byte mantissa (m) inc sign bit}. After loading in the representation for '1' into flt2 and '2' into flt1, I see:
Code: Select all
0080: 80 40 00 00 81 40 00 00 ;·@···@··
0088: 00 00 00 00 00 00 00 00 ;········
Code: Select all
jsr fcompl ; create the -ve of flt1
jsr alignsw ; align flt1 and swap flt1,flt2 if needed
... (fall through into fadd) Code: Select all
┌─────────────┐
│ f_sub │
└─────────────┘
│
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
├─▶│ fcompl │────▶│ addend │────▶│ norm │
│ └─────────────┘ └─────────────┘ └─────────────┘
│
│
│ ┌─────────────┐ ┌─────────────┐
├─▶│ alignsw │────▶│ swap │
│ └─────────────┘ └─────────────┘
│
│
│ ┌─────────────┐
└─▶│ fadd │
└─────────────┘ Code: Select all
sec ; set the carry
ldx #$03 ; set up for 3 byte subtraction
compl1:
lda #0 ; clear A
sbc flt_x1,x ; subtract byte of exp1
sta flt_x1,x ; restore it
dex ; next byte
bne compl1 ; loop until done
compdone:
beq addend ; normalise (or shift right on overflow)
Code: Select all
0080: 80 40 00 00 81 C0 00 00 ;·@······
0088: 00 00 00 00 00 00 00 00 ;········
80:400000 is "1", and
81:C00000 is "-2"
However, the next call is to addend, which is implemented as either a branch to 'norm' (normalize the mantissa) or 'rtlog' (shift the 6 bytes of flt1/e mantissas one bit to the right):
Code: Select all
addend:
bvc norm ; no overflow, normalise results
bvs rtlog ; ov: shift mant1 right, note carry is correct sign
Code: Select all
norm1:
lda flt_m1 ; high order mantissa-1 byte
cmp #$c0 ; upper 2 bits unequal ?
bmi rts1 ; y: return
dec flt_x1 ; decrement exponent-1
asl flt_m1+2 ; 3-byte shift of mantissa-1 left
rol flt_m1+1
rol flt_m1
norm:
lda flt_x1 ; Mantissa-1 high-byte
bne norm1 ; no, continue normalising
rts1:
rts ; all done
- load A with contents of $84 (set to $81) as above,
- it's not 0, so we run through the norm1 code.
- On the first pass, flt_m1 (the first byte of flt1's mantissa) is $C0 (sign bit, $80, and the top mantissa bit both set), so we fail the BMI test
- then we decrement the exponent (old value of $81 -> $80)
- then do the asl/rol sequence,
- loop around again because $80 isn't 0,
- this time we pass the CMP test and return.
Code: Select all
0080: 80 40 00 00 80 80 00 00 ;·@······
0088: 00 00 00 00 00 00 00 00 ;········
Code: Select all
algnsw:
bcc swap ; swap if carry clear, else shift right
...
Code: Select all
swap:
ldx #$04 ; set up for 4-byte swap
swap1:
sty flt_e-1,x ; copy to E
lda flt_x1-1,x ; swap a byte of exp/mant1 with..
ldy flt_x2-1,x ; exp/mant2 and leave a copy of..
sty flt_x1-1,x ; mant1 in E (3 bytes). E+3 used
sta flt_x2-1,x
dex ; next byte
bne swap1 ; loop until done
rts
Code: Select all
0080: 80 80 00 00 80 40 00 00 ;·····@··
0088: 40 00 00 00 00 00 00 00 ;@·······
flt2 (@$80) = 80:800000 or "-0" [this started off as 2]
flt1 (@$84) = 80:400000 or "1" [this is unchanged, just swapped from the other register]
unsurprisingly the add routine returns the wrong results... I have checked and re-checked that this code accurately represents the code in the afore-linked PDF (and I used the second (later) version, assuming the one burnt into the Apple ][ ROM would be "good"), so I'm a bit confused over what I'm doing wrong here. I'm assuming [grin] that there isn't a mistake in code that's almost 50 years old and has had a lot of eyes on it - so perhaps there's some setup I'm not aware of, or something similar ? I did try to keep the register-layout order the same in case there was rol/asl from one register into another...
The test with $C0 looks "iffy" to me, because (ignoring the no-errors-in-code-this-used credo for a moment), the test is supposed to be (as I understand it) that "the top two bits of the mantissa ought not be the same", but the test against $C0 is testing the top-bit of the mantissa with the sign bit of the mantissa, and I didn't *think* the sign bit counted. If that is a bug, then an ASL A inserted before the CMP $C0 would fix it, I think.
Yeah, scratch that. Inserting an ASL A in there causes the addition of 1 to 2 to break, whereas it previously worked.
Any advice gratefully received