barrym95838 wrote:
Camel Forth (thanks to Dr. Brad):
Code:
: UD/MOD ( ud1 u2 -- u3 ud4 ) \ 32/16->32 divide
>R 0 R@ UM/MOD ROT ROT R> UM/MOD ROT
;
Wouldn't it be better to do it the other way around?
ie.
Code:
: UM/MOD UD/MOD DROP ;
My own UM/MOD routine (shown below) pretty much did 32-bit division although it only pushed the lower 16-bit result on the stack. It would be a simple matter to make it a UD/MOD instead (and I am thinking of doing that).
BTW with Forth-79, Forth-83, Fig Forth and ANSI Forth (not to mention all the individuals who make up their own standards) there are too many standards to make it worth while to just pick one. I prefer to just provide UM* and UM/MOD (or UD/MOD) and leave it to the user to deal with signed multiplication and division.
Code:
;
; UM/MOD - ( ud u1 -- u2 u3)
; An unsigned division of the 32 bit IACC (ud)
; by the 32 bit IOPR (u1 extended to 32 bits)
; REMAINDER IS u2 (IACCl)
; AND QUOTIENT IS u3 (IQUOTl moved to IACCh)
;
UMDMOD TXA ; +---------------+
SEC ; +12 | h udl |
SBC #6 ; +11 | l u2 | IACCl
TAX ; +---------------+
LDA #0 ; +10 | h udh |
STA STACK+1,X ; +9 | l | IACCh
STA STACK+2,X ; +---------------+
STA STACK+3,X ; +8 | h u1 |
STA STACK+4,X ; +7 | l | IOPRh
STA STACK+5,X ; +---------------+
STA STACK+6,X ; +6 | h 0 |
LDY #16 ; +5 | l | IOPRl
; IOPR shifted 16 bits already ; +---------------+
_SHIFTL LDA STACK+8,X ; +4 | h u3 |
BMI _LOOP ; +3 | l | IQUOTl
ASL STACK+7,X ; +---------------+
ROL STACK+8,X ; +2 | h 0 |
INY ; +1 | l | IQUOTh
BNE _SHIFTL ; +---------------+
_LOOP LDA STACK+10,X ; X-->| |
CMP STACK+8,X ;
; Check if IOPR > IACC ;
BCC _SHIFTR ;
BNE _SUBTR ;
LDA STACK+9,X ;
CMP STACK+7,X
BCC _SHIFTR
BNE _SUBTR
LDA STACK+12,X
CMP STACK+6,X
BCC _SHIFTR
BNE _SUBTR
LDA STACK+11,X
CMP STACK+5,X
BCC _SHIFTR
_SUBTR SEC ; If IOPR <= IACC THEN
LDA STACK+11,X ; subtract IOPR from IACC
SBC STACK+5,X ; and shift 1 into IQUOT
STA STACK+11,X
LDA STACK+12,X
SBC STACK+6,X
STA STACK+12,X
LDA STACK+9,X
SBC STACK+7,X
STA STACK+9,X
LDA STACK+10,X
SBC STACK+8,X
STA STACK+10,X
_SHIFTR ROL STACK+3,X ; else shift 0 into IQUOT
ROL STACK+4,X
ROL STACK+1,X
ROL STACK+2,X
LSR STACK+8,X ; shift IOPR right
ROR STACK+7,X
ROR STACK+6,X
ROR STACK+5,X
DEY ; continue counted shifts and subtracts
BPL _LOOP
LDA STACK+3,X ; copy IQUOT(L) TO right spot on stack
STA STACK+9,X ; (remainder already in right place)
LDA STACK+4,X
STA STACK+10,X
TXA ; CLEAN UP STACK
CLC
ADC #8
TAX
RTS