dawnFORTH: Yet another crude Forth for the 65C02.

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
electricdawn
Posts: 34
Joined: 23 Nov 2025

Re: dawnFORTH: Yet another crude Forth for the 65C02.

Post by electricdawn »

BigDumbDinosaur wrote:
However, I am mindful of an old adage which says just because you can do something doesn’t mean you should do it.
And you would be absolutely in the right. :|

I'm torn on this. I don't NEED this. I just wanted to do it, because I thought it would be cool to have. I have already started implementing a data stack with fixed four byte cells using Garth's method.

It's not as easy and a slam dunk as I'd expected. Sometimes it's still preferable to have loops to avoid chains of

Code: Select all

lda 1,X
sta somewhere
lda 2,X
sta elsweyr
...
Sometimes you still need to calculate an offset, since you really only have TWO index registers, and one is already taken. And you can't index something like

Code: Select all

lda (Y),X
That would be nice to have, though. ;)

Working on it. Let's see where I can take this. This would be no longer dawnFORTH, of course... Oh well, the only constant in life is change, they say. :mrgreen:
leepivonka
Posts: 167
Joined: 15 Apr 2016

Re: dawnFORTH: Yet another crude Forth for the 65C02.

Post by leepivonka »

Another option is to use more traditional fixed 2 or 4 byte cell size for the primary
FORTH parameter stack & to define additional words & stack for the large integer cells.
Sort of like what ANSI FORTH does for floating point words.

Here is sample set of definitions for separate large integers (aka multibyte or M cells):

Variable MCellBytes 32 MCellBytes ! \ # of bytes in an M cell
Create MStack MCellBytes @ 8 * Allot \ separate M stack
Here Constant MSEmpty \ empty MSPtr value
Variable MSPtr MSEmpty MSPtr ! \ MStack pointer

: MEmpty-Stack ( M: .. -- ) \ empty the MStack
: MDepth ( -- n ) \ # of entrys on MStack
: MSwap ( M: m1 m2 -- m2 m1 ) \ swap MStack NOS & TOS
: MDup ( M: m -- m m ) \ push MStack TOS
: MOver ( M: m1 m2 -- m1 m2 m1 ) \ push MStack NOS
: MDrop ( M: m1 m2 -- m1 ) \ drop m2, Tmp1=^m2, Tmp2=^m1
: MNip ( M: m1 m2 -- m2 ) \ remove MStack NOS
: MMax ( M: m1 m2 -- m3 ) \ return signed max of m1 & m2
: MMin ( M: m1 m2 -- m3 ) \ return signed min of m1 & m2
: M= ( M: m1 m2 -- ) ( -- f ) \ return m1==m2
: M<> ( M: m1 m2 -- ) ( -- f ) \ return m1!=m2
: M< ( M: m1 m2 -- ) ( -- f ) \ return signed m1<m2
: M<= ( M: m1 m2 -- ) ( -- f ) \ return signed m1<=m2
: MU< ( M: m1 m2 -- ) ( -- f ) \ return unsigned m1<m2
: MU<= ( M: m1 m2 -- ) ( -- f ) \ return unsigned m1<=m2
: M0= ( M: m -- ) ( -- f ) \ return m==0
: M0< ( M: m -- ) ( -- f ) \ return signed m<0
: S>M ( n -- ) ( M: -- m ) \ convert signed n to m
: U>M ( u -- ) ( M: -- um ) \ convert unsigned u to um
: MU>D ( M: um1 -- um1 0 ) \ convert unsigned um1 to double unsigned m
: MS>D ( M: m1 -- m1 mhi ) \ convert signed m1 to double m
: M>S ( M: m -- ) ( -- n ) \ convert m to n
: MRol ( M: m1 P.C -- m2 P.C ) \ Rotate the bits of m1 left through the carry bit.
: M2* ( M: m1 -- m2 ) \ return m1*2
: MRor ( M: m1 P.C -- m2 P.C ) \ Rotate the bits of m1 right through the carry bit.
: MU2/ ( M: m1 -- m2 ) \ return unsigned m1/2
: M2/ ( M: m1 -- m2 ) \ return signed m1/2
: M1+ ( M: m1 -- m2 ) \ Increment m1
: M1- ( M: m1 -- m2 ) \ decrement m1
: MOr ( M: m1 m2 -- m3 ) \ Bitwise logical or
: MAnd ( M: m1 m2 -- m3 ) \ Bitwise logical and
: MXor ( M: m1 m2 -- m3 ) \ Bitwise logical xor
: MInvert ( M: m1 -- m2 ) \ bitwise invert
: M+1 ( M: m1 m2 -- m3 ) \ Add m1 to m2 giving m3, name collision with M+
: M-1 ( M: m1 m2 -- m3 ) \ Subtract m2 from m1 giving m3, name collision with M-
: MNegate ( M: m1 -- m2 ) \ return the two's complement of m1
: MAbs ( M: m1 -- m2 ) \ return absolute value of m1
: MDNegate ( M: mlo1 mhi1 -- mlo2 mhi2 ) \ return two's complement of double M.
: Hex>M ( uhi ... ulo -- ) ( M: -- m ) \ convert words to M
: M.Hex ( M: m -- ) \ type m in hex
: MU*ByteA ( A -- ) ( M: m1 -- m2 ) \ return unsigned m1*A
: MUM* ( M: um1 um2 -- umlo umhi ) \ Multiply unsigned giving double
: MU* ( M: um1 um2 -- um3 ) \ unsigned muliply
: M*1 ( M: m1 m2 -- m3 ) \ signed multiply, name collision with M*
: MM* ( M: m1 m2 -- mlo mhi ) \ signed multiply giving double
: MU/ModByteA ( M: umdividend -- umquotient ) ( udivisor -- A=uremainder )
: MUM/Mod ( M: umlo umhi umdivisor -- umremainder umquotient ) \ division
: MU/Mod ( M: um-dividend um-divisor -- um-remainder um-quotient ) \ Divide unsigned
: MUMod ( M: mu-dividend mu-divisor -- mu-remainder ) \ Divide unsigned
: MU/ ( M: mu-dividend mu-divisor -- mu-quotient ) \ Divide unsigned
\ : MFM/Mod ( M: mlo mhi mdivisor -- mremainder mquotient ) \ Floored signed division
: MSM/Rem ( M: mlo mhi mdivisor -- mremainder mquotient ) \ Symmetric signed division
: M@ ( adr -- ) ( M: -- m ) \ fetch m from adr
: M! ( adr -- ) ( M: m -- ) \ store m at adr
: M, ( M: m -- ) \ compile m
: MVariable ( "name" -- ) \ Compile an M variable word
: MConstant ( M: m -- ) ( "name" -- ) \ compile an M constant word
: M.Fmt1 ( M: m -- ) \ 1st part of format m into hold buffer
: M.Pad ( n -- ) \ add padding spaces to Hold
: MU.R ( M: um -- ) ( n -- ) \ type unsigned m, at least n chars
: MU. ( M: um -- ) \ type unsigned m, minimum length
: M.R ( M. m -- ) ( n -- ) \ type signed m, at least n chars
: M. ( M. m -- ) \ type signed m, minimum length
: M.S \ Print the MStack
: >M ( M: -- m ) ( c-addr u -- true | false) \ Convert a string to an m
: MLiteral ( M: m -- ) \ compile inline m literal
: M' ( "string" -- ) ( M: -- m ) \ convert inline string to m

A worked example for a hacked version of Tali FORTH is at https://github.com/leepivonka/TaliForth ... sM%201.lst
( skip to "@wordssm.fs" for definitions, "@..\wordsmtest.fs" for testing )
A powers of 2 application is at the bottom.
Post Reply