6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 12:16 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: Double-Number word set
PostPosted: Tue Jun 22, 2021 5:17 pm 
Offline

Joined: Thu May 13, 2021 8:56 am
Posts: 31
Location: Hellevoetsluis-NL
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


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 22, 2021 8:33 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 255
Only lightly tested. Do you need 2@ and 2! as well?
Code:
: 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 ;


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 22, 2021 10:27 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.

For D2/ :
Code:
        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:
        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)

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 6:56 am 
Offline

Joined: Thu May 13, 2021 8:56 am
Posts: 31
Location: Hellevoetsluis-NL
SamCoVT wrote:
Only lightly tested. Do you need 2@ and 2! as well?
Code:
: 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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 7:09 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
This should work,
Code:
: 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?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 10:08 am 
Offline

Joined: Thu May 13, 2021 8:56 am
Posts: 31
Location: Hellevoetsluis-NL
SamCoVT wrote:
Only lightly tested. Do you need 2@ and 2! as well?
Code:
: 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:
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!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 10:28 am 
Offline

Joined: Thu May 13, 2021 8:56 am
Posts: 31
Location: Hellevoetsluis-NL
GARTHWILSON wrote:
Writing the D2* and D2/ as primitives will make them extremely fast compared to using the division and multiplication routines.

For D2/ :
Code:
        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:
        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:
;
; 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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 1:05 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Powersoft wrote:
This is my testcode:
Code:
;
; 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. :wink:

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 1:11 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 255
Powersoft wrote:
I have tested the code, the multiply seems correct, but the D2/ not see my results.
Code:
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 23, 2021 5:12 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 255
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:
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:
.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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 06, 2021 12:34 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
SamCoVT wrote:
Code:
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:
Code:
SP! SP@ CONSTANT STACKBOTTOM



Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: