We all know the 65c816 has broken the 64K memory barrier. That opens the door to some serious, "big computer" applications.
But, assuming we prefer to code in Forth, the question arises of how an '816 Forth implementation ought to access the wide open spaces above $FFFF. For the sake of discussion I decided to volunteer my $.02 worth, accompanied by some equally valuable code snips. (Corrections & comments welcome -- I'm new to the '816.)
The Forth for my KimKlone computer dealt with the 16 MByte challenge by including @ and ! variants that used 32-bit stack items -- doubles -- to receive the long (aka Far) 24-bit addresses. I had words called FAR@ and FAR! not to mention FAR2@ FAR2! FARC@ FARC!. These were reasonably fast, but a pain to code with due to the constant intermingling of 16- and 32-bit values on stack. Also there was a lot of dictionary clutter from all the double- and mixed-precision operators that turned out to be required.
What I propose here is a different tradeoff -- friendlier to code with, and a more powerful Forth overall. There's a major clock-cycle penalty, but modern '816s are pretty quick... You'll have to choose for yourself what's best. (But address calculations will involve extended precision no matter what.)
In the '816 Forth I envisage, stack items always occupy 32 bits, and @ and ! use Long addresses and access 32-bit data. But the Dictionary resides within 64K, and tokens are 16 bit. It's probably easier to show than to explain, so here are some key code snippets I've scoped out. Take a look and see if this doesn't start to get intriguing!
CONDITIONS:
Double-indirect interpreter
Y is the Forth IP; S is the ParameterStack Ptr.; R_PTR is the ReturnStack ptr.
The P-Stack and the the Dictionary reside in Bank 0.
Addresses on stack are 24-bit (padded to 32 bits).
The P-stack and R-Stack grow and shrink in 4-byte increments
Code: Select all
FETCH: PLX ;adrLo in X LS 2 bits of adr must =0 (ie, DWORD aligned)
PLB ;adrHi in DBR
PHB ;keep S word-aligned
LDA 2,X ;fetch hi word from DBR:X+2
STA 1,S ;hi word to stack
LDA 0,X ;fetch lo word from DBR:X
PHA ;lo word to stack
_NEXTCode: Select all
STORE: PLX ;adrLo in X LS 2 bits of adr must =0 (ie, DWORD aligned)
PLB ;adrHi in DBR
PHB ;keep S word-aligned
PLA ;
PLA ;lo word from stack
STA 0,X ;store lo word to DBR:X
PLA ;hi word from stack
STA 2,X ;store hi word to DBR:X+2
_NEXTCode: Select all
NEXT: LDX 0,Y ;5~ fetch via IP
INY ;2~ bump IP
INY ;2~
JMP (0,X) ;6~ X is Forth's "W"Code: Select all
BRANCH: CLC ;
TYA ;IP in A
ADC 0,Y ;add offset at (IP)
TAY ;IP in Y
_NEXT
0BRANCH:
PLA ;lo word of TOS
ORA 0,S ;tested with hi word
PLA ;drop hi word
BEQ BRANCH ;result 0? Branch.
INY ;Else step
INY ; over offset
_NEXTCode: Select all
NEST: TYA ;IP in A
STA [R_PTR] ;copy IP to R (Bank per 3rd byte of ptr, eg: 0)
TXY ;copy W to Y
INY ;
INY ;W+2 will be new IP
LDA R_PTR ;adjust R Ptr to point to next free loc'n
SEC
SBC #4
STA R_PTR ;R_Ptr indicates next free loc'n
_NEXTCode: Select all
UNNEST: LDA R_PTR ;adjust R Ptr
CLC
ADC #4
STA R_PTR
LDA [R_PTR] ;copy R to A (Bank per 3rd byte of ptr, eg: 0)
TAY ;copy A to "IP"
_NEXTCode: Select all
DUP: LDA 3,S ;fetch hi word
PHA ;store hi word
LDA 3,S ;fetch lo word
PHA ;store lo word
_NEXTCode: Select all
PLUS: CLC ;
PLA ;
ADC 3,S ;compute lo result
STA 3,S ;save lo result
PLA ;
ADC 3,S ;compute hi result
STA 3,S ;save hi result
_NEXTCode: Select all
SWAP: TSX ;
PHY ;save Y (the Forth IP)
LDA 1,X ;fetch lo word of TOS
LDY 5,X ;fetch lo word of NOS
STA 5,X ;store to NOS
STY 1,X ;store to TOS
LDA 3,X ;fetch hi word of TOS
LDY 7,X ;fetch hi word of NOS
STA 7,X ;store to NOS
STY 3,X ;store to TOS
PLY ;restore Y
_NEXT