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.