Double-Number word set
Double-Number word set
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
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
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 ;
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Double-Number word set
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.
For D2/ :
For D2* :
Note also that fig-Forth had bugs in the division and multiplication routines. Here's a copy-and-paste from my website:
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 NEXTFor 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 NEXTNote 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)
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Double-Number word set
SamCoVT wrote:
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 ;
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Double-Number word set
This should work,
but if you use them a lot, you'll want to make them primitives (ie, defined in assembly language) for performance.
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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Double-Number word set
SamCoVT wrote:
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 ;
Code: Select all
12345. OK
5. OK
D2/ OK
D. 2 OK
10000. OK
10. OK
D2/ D. 5 OK
Re: Double-Number word set
GARTHWILSON wrote:
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.
For D2/ :
For D2* :
Note also that fig-Forth had bugs in the division and multiplication routines. Here's a copy-and-paste from my website:
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 NEXTFor 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 NEXTNote 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)
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 NEXTRe: Double-Number word set
Powersoft wrote:
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 NEXTJ.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Double-Number word set
Powersoft wrote:
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
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
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.
Here's an example run: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.
.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 ;
DECIMALCode: 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
Re: Double-Number word set
SamCoVT wrote:
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
DECIMALSome versions of fig Forth had SP! to clear the data stack, so how about:
Code: Select all
SP! SP@ CONSTANT STACKBOTTOM