Errata - Software - FIG-Forth

Bugs in 6502 FIG-Forth:

## U/ (a.k.a. UM/MOD in ANS Forth)

U/ divides a 32-bit unsigned integer dividend by a 16-bit unsigned integer divisor to produce a 16-bit unsigned integer quotient and a 16-bit unsigned integer remainder. Note that:

dividend = divisor * quotient + remainder

• Inputs:
• 0,X = bits 7-0 of the divisor
• 1,X = bits 15-8 of the divisor
• 4,X = bits 7-0 of the dividend
• 5,X = bits 15-8 of the dividend
• 2,X = bits 23-16 of the dividend
• 3,X = bits 31-24 of the dividend
• Output (when it JuMPs to POP):
• 2,X = bits 7-0 of the quotient
• 3,X = bits 15-8 of the quotient
• 4,X = bits 7-0 of the remainder
• 5,X = bits 15-8 of the remainder

The original (buggy) code follows. With this routine, dividing \$80000000 by \$8001 returns the quotient
\$0000 and the remainder \$0000, which is incorrect. The correct quotient is \$FFFE and the correct remainder is \$0002.

``````     LDA 4,X
LDY 2,X
STY 4,X
ASL A
STA 2,X
LDA 5,X
LDY 3,X
STY 5,X
ROL A
STA 3,X
LDA #16
STA N
L433 ROL 4,X
ROL 5,X
SEC
LDA 4,X
SBC 0,X
TAY
LDA 5,X
SBC 1,X
BCC L444
STY 4,X
STA 5,X
L444 ROL 2,X
ROL 3,X
DEC N
BNE L433
JMP POP```
```

The problem is that when a one is shifted into the carry by the ROL 5,X instruction, it must be accounted for and the routine above does not do so.

The corrected routine follows.

``````;
LDA 4,X
LDY 2,X
STY 4,X
ASL A
STA 2,X
LDA 5,X
LDY 3,X
STY 5,X
ROL A
STA 3,X
LDA #16
STA N
L433  ROL 4,X
ROL 5,X
LDA 4,X
BCS L0446
SEC
SBC 0,X
TAY
LDA 5,X
SBC 1,X
BCC L444
STY 4,X
L0442 STA 5,X
L444  ROL 2,X
ROL 3,X
DEC N
BNE L433
JMP POP
L0446 SBC 0,X
STA 4,X
LDA 5,X
SBC 1,X
SEC
BCS L0442 ; branch always```
```

With this routine, dividing \$80000000 by \$8001 returns the quotient \$FFFE and the remainder \$0002, which is correct.

## U* (a.k.a. UM* in ANS Forth)

U* mulitplies two 16-bit unsigned integers (the mulitplicand and the multiplier) to produce a 32-bit result.

• Inputs:
• 0,X = bits 7-0 of the multiplier (TOS)
• 1,X = bits 15-8 of the multiplier (TOS)
• 2,X = bits 7-0 of the multiplicand (second-on-stack)
• 3,X = bits 15-8 of the multiplicand (second-on-stack)
• Output:
• 2,X = bits 7-0 of the product
• 3,X = bits 15-8 of the product
• 0,X = bits 23-16 of the product
• 1,X = bits 31-24 of the product

The original (buggy) routine follows; note that FIG-Forth calls this code with Y=\$00. With this routine, multiplying \$16A1 by \$16A1 returns the product \$01001141, which is incorrect. The correct product is \$02001141.

``````;
LDA 2,X
STA N
STY 2,X
LDA 3,X
STA N+1
STY 3,X
LDY #16 ; for 16 bits
L396 ASL 2,X
ROL 3,X
ROL 0,X
ROL 1,X
BCC L411
CLC
LDA N
STA 2,X
LDA N+1
STA 3,X
LDA #0
STA 0,X
L411 DEY
BNE L396```
```

The problem is that when there is a carry from the ADC 0,X instruction, the carry must be added to 1,X (to update bits 31-23 of the product), but the routine above does not do this.

A simple solution is to insert the necessary instructions between the STA 0,X and DEY instructions. However, the following multiplication can be used instead; it shifts the product right (rather than left, as the original routine does), is slightly smaller, and is faster for most cases.

``````;
TYA
STA N
LDY #16
LSR 3,X
ROR 2,X
L396 BCC L411
CLC
PHA
LDA N
STA N
PLA
L411 ROR
ROR N
ROR 3,X
ROR 2,X
DEY
BNE L396
STA 1,X
LDA N
STA 0,X```
```

With this routine, multiplying \$16A1 by \$16A1 returns the product \$02001141 which is correct.

For Forths where Y will not be \$00 when U* is called, the TYA instruction can be replaced by LDA #0

page revision: 2, last edited: 18 Dec 2010 20:13