Page 1 of 1
Double-Number word set
Posted: Tue Jun 22, 2021 5:17 pm
by Powersoft
Hello,
Is it possible to implement the complete double word set in fig-forth?
I think about code written for the 6502.
Is this code maybe available?
I looking for the words { 2constant,2variable,d2*,d2/ and dnegate }
Thanks for any help.
Cheers,
Jan
Re: Double-Number word set
Posted: Tue Jun 22, 2021 8:33 pm
by SamCoVT
Only lightly tested. Do you need 2@ and 2! as well?
Code: Select all
: 2CONSTANT <BUILDS , , DOES> dup 2 + @ swap @ ;
: 2VARIABLE <BUILDS 0 , 0 , DOES> ;
( These next two would be better as CODE words but )
( FIG doesn't have the assembler loaded by default. )
( MSW = Most Significant Word of a double )
( LSW = Least Significant Word of a double )
( MSb = Most Significant bit )
HEX
: D2* ( d1 -- d2 ) ( Shift double left by one bit )
( See if bit needs to be shifted from LSW to MSW)
swap dup 8000 and ( MSW LSW flag )
>r ( save the flag )
2 * swap 2 * ( FIG doesn't have 2* )
r> ( bring back the flag )
if 1+ then ; ( adjust the MSW if needed )
: D2/ ( d1 -- d2 ) ( Shift double right with sign extend )
( See if bit needs to be shifted from MSW to LSW )
dup 0001 and ( LSW MSW flag )
>r ( save the flag )
2 / ( FIG doesn't have 2/ )
( 2 / already does sign extend for negative numbers )
swap 2 / ( deal with the LSW )
r> ( bring back the flag )
if 8000 or else 7fff and then ( force MSb of LSW )
swap ; ( put back in double order )
DECIMAL
: DNEGATE DMINUS ; ( FIG just has a different name for this )
( FIG also doesn't have 2DUP, which is handy for testing )
: 2DUP ( d1 -- d1 d1 ) OVER OVER ;
Re: Double-Number word set
Posted: Tue Jun 22, 2021 10:27 pm
by GARTHWILSON
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.
For D2/ :
Code: Select all
LDA 1,X ; Get the highest byte and
ASL A ; shift left (to preserve the sign)
ROR 1,X
ROR 0,X
ROR 3,X
ROR 2,X
JMP NEXT
For D2* :
Code: Select all
ASL 2,X ; Start with the lowest byte.
ROL 3,X
ROL 0,X
ROL 1,X ; End with the highest byte.
JMP NEXT
Note also that fig-Forth had bugs in the division and multiplication routines. Here's a copy-and-paste from my website:
- unsigned division of a 32-bit dividend by a 16-bit divisor, resulting in a 16-bit quotient and a 16-bit remainder. Presented for the 65C02 (with changes for use on 6502) and 65816, with notes of interest to Forth users (for UM/MOD).
- unsigned multiplication (on forum), with 16-bit factors and 32-bit result, correcting a bug in the public-domain 6502 Forth multiplication, as the division article above. Others offered efficiency improvements in the subsequent posts.
- D< bug in common Forths, plus a fix (on forum)
Re: Double-Number word set
Posted: Wed Jun 23, 2021 6:56 am
by Powersoft
Only lightly tested. Do you need 2@ and 2! as well?
Code: Select all
: 2CONSTANT <BUILDS , , DOES> dup 2 + @ swap @ ;
: 2VARIABLE <BUILDS 0 , 0 , DOES> ;
( These next two would be better as CODE words but )
( FIG doesn't have the assembler loaded by default. )
( MSW = Most Significant Word of a double )
( LSW = Least Significant Word of a double )
( MSb = Most Significant bit )
HEX
: D2* ( d1 -- d2 ) ( Shift double left by one bit )
( See if bit needs to be shifted from LSW to MSW)
swap dup 8000 and ( MSW LSW flag )
>r ( save the flag )
2 * swap 2 * ( FIG doesn't have 2* )
r> ( bring back the flag )
if 1+ then ; ( adjust the MSW if needed )
: D2/ ( d1 -- d2 ) ( Shift double right with sign extend )
( See if bit needs to be shifted from MSW to LSW )
dup 0001 and ( LSW MSW flag )
>r ( save the flag )
2 / ( FIG doesn't have 2/ )
( 2 / already does sign extend for negative numbers )
swap 2 / ( deal with the LSW )
r> ( bring back the flag )
if 8000 or else 7fff and then ( force MSb of LSW )
swap ; ( put back in double order )
DECIMAL
: DNEGATE DMINUS ; ( FIG just has a different name for this )
( FIG also doesn't have 2DUP, which is handy for testing )
: 2DUP ( d1 -- d1 d1 ) OVER OVER ;
When it is posibele yes, and tanks for your help.
Re: Double-Number word set
Posted: Wed Jun 23, 2021 7:09 am
by GARTHWILSON
This should work,
Code: Select all
: 2@ ( adr -- d ) DUP 2+ @ SWAP @ ;
: 2! ( d adr -- ) DUP >R ! R> 2+ ! ;
but if you use them a lot, you'll want to make them primitives (ie, defined in assembly language) for performance.
Re: Double-Number word set
Posted: Wed Jun 23, 2021 10:08 am
by Powersoft
Only lightly tested. Do you need 2@ and 2! as well?
Code: Select all
: 2CONSTANT <BUILDS , , DOES> dup 2 + @ swap @ ;
: 2VARIABLE <BUILDS 0 , 0 , DOES> ;
( These next two would be better as CODE words but )
( FIG doesn't have the assembler loaded by default. )
( MSW = Most Significant Word of a double )
( LSW = Least Significant Word of a double )
( MSb = Most Significant bit )
HEX
: D2* ( d1 -- d2 ) ( Shift double left by one bit )
( See if bit needs to be shifted from LSW to MSW)
swap dup 8000 and ( MSW LSW flag )
>r ( save the flag )
2 * swap 2 * ( FIG doesn't have 2* )
r> ( bring back the flag )
if 1+ then ; ( adjust the MSW if needed )
: D2/ ( d1 -- d2 ) ( Shift double right with sign extend )
( See if bit needs to be shifted from MSW to LSW )
dup 0001 and ( LSW MSW flag )
>r ( save the flag )
2 / ( FIG doesn't have 2/ )
( 2 / already does sign extend for negative numbers )
swap 2 / ( deal with the LSW )
r> ( bring back the flag )
if 8000 or else 7fff and then ( force MSb of LSW )
swap ; ( put back in double order )
DECIMAL
: DNEGATE DMINUS ; ( FIG just has a different name for this )
( FIG also doesn't have 2DUP, which is handy for testing )
: 2DUP ( d1 -- d1 d1 ) OVER OVER ;
I have tested the code, the multiply seems correct, but the D2/ not see my results.
Code: Select all
12345. OK
5. OK
D2/ OK
D. 2 OK
10000. OK
10. OK
D2/ D. 5 OK
Have taken over the code line by line to avoid typo's!
Re: Double-Number word set
Posted: Wed Jun 23, 2021 10:28 am
by Powersoft
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.
For D2/ :
Code: Select all
LDA 1,X ; Get the highest byte and
ASL A ; shift left (to preserve the sign)
ROR 1,X
ROR 0,X
ROR 3,X
ROR 2,X
JMP NEXT
For D2* :
Code: Select all
ASL 2,X ; Start with the lowest byte.
ROL 3,X
ROL 0,X
ROL 1,X ; End with the highest byte.
JMP NEXT
Note also that fig-Forth had bugs in the division and multiplication routines. Here's a copy-and-paste from my website:
- unsigned division of a 32-bit dividend by a 16-bit divisor, resulting in a 16-bit quotient and a 16-bit remainder. Presented for the 65C02 (with changes for use on 6502) and 65816, with notes of interest to Forth users (for UM/MOD).
- unsigned multiplication (on forum), with 16-bit factors and 32-bit result, correcting a bug in the public-domain 6502 Forth multiplication, as the division article above. Others offered efficiency improvements in the subsequent posts.
- D< bug in common Forths, plus a fix (on forum)
Thanks for the code, but is this a part of a bigger code?
When I try this notting is change on the stack.
This is my testcode:
Code: Select all
;
; D2*
;
L9160 .BYTE $83,"D2",'*'+$80
.WORD L9150
D2MULT .WORD D2MULT+2
LDA 1,X ; Get the highest byte and
ASL A ; shift left (to preserve the sign)
ROR 1,X
ROR 0,X
ROR 3,X
ROR 2,X
JMP NEXT
Thanks for any help.
Re: Double-Number word set
Posted: Wed Jun 23, 2021 1:05 pm
by Dr Jefyll
This is my testcode:
Code: Select all
;
; D2*
;
L9160 .BYTE $83,"D2",'*'+$80
.WORD L9150
D2MULT .WORD D2MULT+2
LDA 1,X ; Get the highest byte and
ASL A ; shift left (to preserve the sign)
ROR 1,X
ROR 0,X
ROR 3,X
ROR 2,X
JMP NEXT
There appears to be a mixup here -- a copy/paste error, perhaps. Your header is for
D2* but the code is that which Garth suggested for
D2/.
J.

Re: Double-Number word set
Posted: Wed Jun 23, 2021 1:11 pm
by SamCoVT
I have tested the code, the multiply seems correct, but the D2/ not see my results.
Code: Select all
12345. OK
5. OK
D2/ OK
D. 2 OK
10000. OK
10. OK
D2/ D. 5 OK
Based on your example session, it looks like you're expecting
D2/ to divide two doubles.
D2/ takes only one double and divides it by two (just like
D2* multiplies one double by two). It's the "double" version of the word
2/ (which FIG does not come with) that does the same thing for regular size numbers. In your results above, the printed result is simply the 5. divided by two and the 10. divided by two (the other numbers you put on the stack are still there).
If you need a word that divides two double numbers with a double result, that isn't part of any Forth standard that I am aware of, but could be built using words like
M/MOD.
Re: Double-Number word set
Posted: Wed Jun 23, 2021 5:12 pm
by SamCoVT
Because it looks like you are trying to port some code from another Forth to FIG, I'll also give you my version of
.S (print stack) for FIG to print the number of items currently on the stack and their values without changing anything on the stack. This is my most-used word as I am developing Forth code or playing with someone else's code. It's included in many of the Forth standards, but doesn't come with FIG.
.S will print both the number of items on the stack and the values using the current BASE, but do be aware it is using
. to print the values so they will be negative if their most significant bit is set. You can make it print them as unsigned by changing the
. inside the
DO loop to
U. instead. Also, it doesn't know which items on the stack are doubles, so it will count and print each half separately.
Code: Select all
HEX
( .S for FIG Forth )
( Adjust this constant to where the bottom of the stack is )
( on your system. If you do not know, you can use: )
( HEX SP@ . with an empty stack to find out. )
9E CONSTANT STACKBOTTOM
: .S ( -- ) ( Print stack debugging info )
( Print number and items on stack with TOS at right )
SP@ DUP STACKBOTTOM SWAP - 2 / ( determine # of items )
DUP ." <" 1 .R ." > " ( print # of items )
( Only print the list if there is a non-zero number of items )
IF 2 - STACKBOTTOM 2 - DO
I @ . -2 +LOOP
ELSE DROP THEN ;
DECIMAL
Here's an example run:
Code: Select all
.s <0> OK
1 2 3 OK
.s <3> 1 2 3 OK
5. OK
.s <5> 1 2 3 5 0 OK
65535 OK
.s <6> 1 2 3 5 0 -1 OK
The number in angle brackets is how many numbers are on the stack and then the stack values are printed with the top of stack on the right. Note the double 5 is printed as 5 and 0 (most significant word ends up on top of stack for a double) and then 65535 (decimal) is the same bit pattern as -1 and this version always prints the signed value.
Re: Double-Number word set
Posted: Tue Jul 06, 2021 12:34 am
by JimBoyd
Code: Select all
HEX
( .S for FIG Forth )
( Adjust this constant to where the bottom of the stack is )
( on your system. If you do not know, you can use: )
( HEX SP@ . with an empty stack to find out. )
9E CONSTANT STACKBOTTOM
DECIMAL
Some versions of fig Forth had SP! to clear the data stack, so how about: