1133 lines
36 KiB
FortranFixed
1133 lines
36 KiB
FortranFixed
|
|
||
|
|
||
|
FL
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
\ these variables are the current dictionary limits
|
||
|
\ cannot really easily redefine these variable on a running forth system, it really screws things up
|
||
|
\ to redefine requires multiple steps and caution, not worth the bother usually
|
||
|
|
||
|
\ mswMemend w@ wvariable mswMemend mswMemend w!
|
||
|
\ mswHere w@ wvariable mswHere mswHere w!
|
||
|
\ mswDictend w@ wvariable mswDictend mswDictend w!
|
||
|
|
||
|
\ constants which reference the cogdata space are effectively variables with
|
||
|
\ a level of indirection. refedinition of these, if the base variable is the same
|
||
|
\ is reasonable and can be done on a running system
|
||
|
|
||
|
\ caution with other variables
|
||
|
|
||
|
\ these constants are all intialized to the running values, so any following words compile correctly
|
||
|
\ if you add constants that are used by the base compiler, follow the practice
|
||
|
\ any word constant which begins with cm_xxx is compiled with the value @xxxPFA + $10 - which is the exection address
|
||
|
\ any word constant which begins with ca_xxx is copiled with the value (@xxx - @a_base)/4 - execution address
|
||
|
|
||
|
\ cogid if the cog had an over/underflow
|
||
|
-1 wvariable vxcog vxcog w!
|
||
|
|
||
|
\ first forth cog
|
||
|
ffcog w@ wvariable ffcog ffcog w!
|
||
|
|
||
|
\ the last forth cog
|
||
|
lfcog w@ wvariable lfcog lfcog w!
|
||
|
|
||
|
cm_serentry wconstant cm_serentry
|
||
|
cm_entry wconstant cm_entry
|
||
|
|
||
|
\ this is a pointer to the main cogdata area
|
||
|
cm_cogdata wconstant cm_cogdata
|
||
|
\ this is ' cq - the routine which handles the word c"
|
||
|
cm_cq wconstant cm_cq
|
||
|
\ this is ' dq - the routine which handles the word ."
|
||
|
cm_dq wconstant cm_dq
|
||
|
|
||
|
\ these constants are all assembler addresses
|
||
|
ca_a_exit wconstant ca_a_exit
|
||
|
ca_a_dovarw wconstant ca_a_dovarw
|
||
|
ca_a_doconw wconstant ca_a_doconw
|
||
|
ca_a_branch wconstant ca_a_branch
|
||
|
ca_a_litw wconstant ca_a_litw
|
||
|
ca_a_2>r wconstant ca_a_2>r
|
||
|
ca_a_(loop) wconstant ca_a_(loop)
|
||
|
ca_a_(+loop) wconstant ca_a_(+loop)
|
||
|
ca_a_0branch wconstant ca_a_0branch
|
||
|
ca_a_dovar wconstant ca_a_dovar
|
||
|
ca_a_docon wconstant ca_a_docon
|
||
|
ca_a_literal wconstant ca_a_literal
|
||
|
ca_a_debugonoff wconstant ca_a_debugonoff
|
||
|
ca_a_reset wconstant ca_a_reset
|
||
|
ca_a_ifunc wconstant ca_a_ifunc
|
||
|
ca_a_ifunc1 wconstant ca_a_ifunc1
|
||
|
ca_a_ifunc2 wconstant ca_a_ifunc2
|
||
|
ca_a_umstarlp wconstant ca_a_umstarlp
|
||
|
ca_a_umslashmodlp wconstant ca_a_umslashmodlp
|
||
|
ca_a_cstreqlp wconstant ca_a_cstreqlp
|
||
|
ca_a_finlp wconstant ca_a_finlp
|
||
|
|
||
|
\ addresses for the stack routines
|
||
|
ca_a_stPush wconstant ca_a_stPush
|
||
|
ca_a_stPush_ret wconstant ca_a_stPush_ret
|
||
|
ca_a_rsPush wconstant ca_a_rsPush
|
||
|
ca_a_rsPush_ret wconstant ca_a_rsPush_ret
|
||
|
ca_a_stPop wconstant ca_a_stPop
|
||
|
ca_a_stPoptreg wconstant ca_a_stPoptreg
|
||
|
ca_a_stPop_ret wconstant ca_a_stPop_ret
|
||
|
ca_a_stPoptreg_ret wconstant ca_a_stPoptreg_ret
|
||
|
ca_a_rsPop wconstant ca_a_rsPop
|
||
|
ca_a_rsPop_ret wconstant ca_a_rsPop_ret
|
||
|
|
||
|
\ address for the a_next routine
|
||
|
ca_a_next wconstant ca_a_next
|
||
|
|
||
|
\ this group of words needs to align with the assembler code
|
||
|
ca_varStart wconstant ca_varStart
|
||
|
ca_varEnd wconstant ca_varEnd
|
||
|
: _cv ca_varStart + ;
|
||
|
\ : aCondMask 0 _cv ;
|
||
|
: fMask 0 _cv ;
|
||
|
: fAddrMask 1 _cv ;
|
||
|
: fLongMask 2 _cv ;
|
||
|
: resetDreg 3 _cv ;
|
||
|
: IP 4 _cv ;
|
||
|
: stPtr 5 _cv ;
|
||
|
: rsPtr 6 _cv ;
|
||
|
: stTOS 7 _cv ;
|
||
|
|
||
|
: treg1 8 _cv ;
|
||
|
\ : treg2 9 _cv ;
|
||
|
\ : treg3 a _cv ;
|
||
|
\ : treg4 b _cv ;
|
||
|
\ : treg5 c _cv ;
|
||
|
\ : treg6 d _cv ;
|
||
|
: stBot e _cv ;
|
||
|
: stTop 2e _cv ;
|
||
|
: rsBot stTop ;
|
||
|
: rsTop 4e _cv ;
|
||
|
|
||
|
\ this is space constant
|
||
|
bl wconstant bl
|
||
|
\ -1 or true, used frequently
|
||
|
-1 constant -1
|
||
|
\ 0 or false, used frequently
|
||
|
0 wconstant 0
|
||
|
\ this is the par register, always initalized to point to this cogs section of cogdata
|
||
|
1F0 wconstant par
|
||
|
\ the other cog special registers
|
||
|
1F1 wconstant cnt
|
||
|
1F2 wconstant ina
|
||
|
\ 1F3 wconstant inb
|
||
|
1F4 wconstant outa
|
||
|
\ 1F5 wconstant outb
|
||
|
1F6 wconstant dira
|
||
|
\ 1F7 wconstant dirb
|
||
|
1F8 wconstant ctra
|
||
|
1F9 wconstant ctrb
|
||
|
1FA wconstant frqa
|
||
|
1FB wconstant frqb
|
||
|
1FC wconstant phsa
|
||
|
1FD wconstant phsb
|
||
|
1FE wconstant vcfg
|
||
|
1FF wconstant vscl
|
||
|
|
||
|
\ this variable define the number of loops for a key timeout
|
||
|
\ used by keyTO, fast_load, f_write, and after an undefined word
|
||
|
mswKeyTO w@ wvariable mswKeyTO mswKeyTO w!
|
||
|
|
||
|
\ use in the ifuncs to get rid of litw word
|
||
|
: cnip mswHere w@ 2- dup w@ over 2- w! mswHere w! ; immediate
|
||
|
|
||
|
\ ifunc ( n1 n2 -- n ) \ the assembler operation is specified by the literal which follows (replaces the i field)
|
||
|
|
||
|
' ifunc asmlabel ifunc
|
||
|
|
||
|
\ ifunc1 ( n -- n ) \ the assembler operation is specified by the literal which follows (replaces the i field)
|
||
|
|
||
|
' ifunc1 asmlabel ifunc1
|
||
|
|
||
|
\ ifunc2 ( n1 n2 -- ) \ the assembler operation is specified by the literal which follows (replaces the i field)
|
||
|
|
||
|
' ifunc2 asmlabel ifunc2
|
||
|
|
||
|
\ fin ( nfa cstr -- n1) the nfa match in the dictionary, or 0 if not found
|
||
|
' fin asmlabel fin
|
||
|
|
||
|
\ mpx ( n -- t/f ) n is the bit mask to read in
|
||
|
' mpx asmlabel mpx
|
||
|
|
||
|
\ mpxl ( n -- ) set the bits in n low
|
||
|
' mpxl asmlabel mpxl
|
||
|
|
||
|
\ mpxh ( n -- ) set the bits in n hi
|
||
|
' mpxh asmlabel mpxh
|
||
|
|
||
|
\ name= ( nfa cstr -- t/f)
|
||
|
' name= asmlabel name=
|
||
|
|
||
|
\ cstr= ( cstr cstr -- t/f)
|
||
|
' cstr= asmlabel cstr=
|
||
|
|
||
|
\ abs ( n1 -- abs_n1 ) \ absolute value of n1
|
||
|
: abs ifunc1 151 cnip ;
|
||
|
|
||
|
\ and ( n1 n2 -- n1 ) \ bitwise and n1 n2
|
||
|
: and ifunc 0C1 cnip ;
|
||
|
|
||
|
\ andn ( n1 n2 -- n1 ) \ bitwise and n1 invert n2
|
||
|
: andn ifunc 0C9 cnip ;
|
||
|
|
||
|
\ !d ( n1 n2 -- n1 ) set the d field of n1 with n2
|
||
|
: !d ifunc 0A9 cnip ;
|
||
|
|
||
|
\ !i ( n1 n2 -- n1 ) set the i field of n1 with n2
|
||
|
: !i ifunc 0B1 cnip ;
|
||
|
|
||
|
\ !s ( n1 n2 -- n1 ) set the s field of n1 with n2
|
||
|
: !s ifunc 0A1 cnip ;
|
||
|
|
||
|
\ m@ ( addr -- n1 ) \ fetch 32 bit value at main memory addr
|
||
|
: m@ ifunc1 011 cnip ;
|
||
|
|
||
|
\ c@ ( addr -- c1 ) \ fetch 8 bit value at main memory addr
|
||
|
: c@ ifunc1 001 cnip ;
|
||
|
|
||
|
\ w@ ( addr -- h1 ) \ fetch 16 bit value at main memory addr
|
||
|
: w@ ifunc1 009 cnip ;
|
||
|
|
||
|
\ @ ( addr -- n1 ) \ fetch 32 bit value at cog addr
|
||
|
' @ asmlabel @
|
||
|
|
||
|
\ m! ( n1 addr -- ) \ store 32 bit value (n1) at main memory addr
|
||
|
: m! ifunc2 010 cnip ;
|
||
|
|
||
|
\ c! ( c1 addr -- ) \ store 8 bit value (c1) main memory at addr
|
||
|
: c! ifunc2 000 cnip ;
|
||
|
|
||
|
\ w! ( h1 addr -- ) \ store 16 bit value (h1) main memory at addr
|
||
|
: w! ifunc2 008 cnip ;
|
||
|
|
||
|
\ ! ( n1 addr -- ) \ store 32 bit value (n1) at cog addr
|
||
|
' ! asmlabel !
|
||
|
|
||
|
\ branch \ 16 bit branch offset follows - -2 is to itself, +2 is next word
|
||
|
' branch asmlabel branch
|
||
|
|
||
|
\ hubop ( n1 n2 -- n3 t/f ) n2 specifies which hubop (0 - 7), n1 is the source data, n3 is returned,
|
||
|
\ t/f is the 'c' flag is set from the hubop
|
||
|
|
||
|
' hubop asmlabel hubop
|
||
|
|
||
|
\ doconw ( -- h1 ) \ push 16 bit constant which follows on the stack - implicit a_exit
|
||
|
' doconw asmlabel doconw
|
||
|
|
||
|
\ docon ( -- n1 ) \ push a 32 bit constant which follows the stack - implicit a_exit
|
||
|
' docon asmlabel docon
|
||
|
|
||
|
\ dovarw ( -- addr ) \ push address of 16 bit variable which follows on the stack - implicit a_exit
|
||
|
' dovarw asmlabel dovarw
|
||
|
|
||
|
\ dovar ( -- addr ) \ push address of 32 bit variable which follows the stack - implicit a_exit
|
||
|
' dovar asmlabel dovar
|
||
|
|
||
|
\ drop ( n1 -- ) \ drop the value on the top of the stack
|
||
|
' drop asmlabel drop
|
||
|
|
||
|
\ dup ( n1 -- n1 n1 )
|
||
|
' dup asmlabel dup
|
||
|
|
||
|
\ = ( n1 n2 -- t/f ) \ compare top 2 32 bit stack values, true if they are equal
|
||
|
' = asmlabel =
|
||
|
|
||
|
\ exit \ exit the current forth word, and back to the caller
|
||
|
' exit asmlabel exit
|
||
|
|
||
|
\ > ( n1 n2 -- t/f ) \ flag is true if and only if n1 is less than n2
|
||
|
' > asmlabel >
|
||
|
|
||
|
\ litw ( -- h1 ) \ push a 16 bit literal on the stack
|
||
|
' litw asmlabel litw
|
||
|
|
||
|
\ literal ( -- n1 ) \ push a 32 bit literal on the stack
|
||
|
' literal asmlabel literal
|
||
|
|
||
|
\ lshift (n1 n2 -- n3) \ n3 = n1 shifted left n2 bits
|
||
|
: lshift ifunc 059 cnip ;
|
||
|
|
||
|
\ < ( n1 n2 -- t/f ) \ flag is true if and only if n1 is greater than n2
|
||
|
' < asmlabel <
|
||
|
|
||
|
\ max ( n1 n2 -- n1 ) \ signed max of top 2 stack values
|
||
|
: max ifunc 081 cnip ;
|
||
|
|
||
|
\ min ( n1 n2 -- n1 ) \ signed min of top 2 stack values
|
||
|
: min ifunc 089 cnip ;
|
||
|
|
||
|
\ - ( n1 n2 -- n1-n2 )
|
||
|
: - ifunc 109 cnip ;
|
||
|
|
||
|
\ or ( n1 n2 -- n1_or_n2 ) \ bitwise or
|
||
|
: or ifunc 0D1 cnip ;
|
||
|
|
||
|
\ over ( n1 n2 -- n1 n2 n1 ) \ duplicate 2 value down on the stack to the top of the stack
|
||
|
' over asmlabel over
|
||
|
|
||
|
\ + ( n1 n2 -- n1+n2 ) \ sum of n1 & n2
|
||
|
: + ifunc 101 cnip ;
|
||
|
|
||
|
\ rot ( n1 n2 n3 -- n2 n3 n1 ) \ rotate top 3 value on the stack
|
||
|
' rot asmlabel rot
|
||
|
|
||
|
\ r@ ( -- n1 ) \ copy top of RS to stack
|
||
|
: r@ rsPtr @ 2+ @ ;
|
||
|
|
||
|
\ rshift ( n1 n2 -- n3) \ n3 = n1 shifted right logically n2 bits
|
||
|
: rshift ifunc 51 cnip ;
|
||
|
|
||
|
\ rashift ( n1 n2 -- n3) \ n3 = n1 shifted right arithmetically n2 bits
|
||
|
: rashift ifunc 071 cnip ;
|
||
|
|
||
|
\ r> ( -- n1 ) \ pop top of RS to stack
|
||
|
' r> asmlabel r>
|
||
|
|
||
|
\ >r ( n1 -- ) \ pop stack top to RS
|
||
|
' >r asmlabel >r
|
||
|
|
||
|
\ 2>r ( n1 n2 -- ) \ pop top 2 stack top to RS
|
||
|
' 2>r asmlabel 2>r
|
||
|
|
||
|
\ 0branch ( t/f -- ) \ branch it top of stack value is zero 16 bit branch offset follows,
|
||
|
\ -2 is to itself, +2 is next word
|
||
|
' 0branch asmlabel 0branch
|
||
|
|
||
|
\ (loop) ( -- ) \ add 1 to loop counter, branch if count is below limit offset follows,
|
||
|
\ -2 is to itself, +2 is next word
|
||
|
' (loop) asmlabel (loop)
|
||
|
|
||
|
\ (+loop) ( n1 -- ) \ add n1 to loop counter, branch if count is below limit, offset follows,
|
||
|
\ -2 is to itself, +2 is next word
|
||
|
' (+loop) asmlabel (+loop)
|
||
|
|
||
|
\ swap ( n1 n2 -- n2 n1 ) \ swap top 2 stack values
|
||
|
' swap asmlabel swap
|
||
|
|
||
|
\ um* ( u1 u2 -- u1*u2L u1*u2H ) \ unsigned 32bit * 32bit -- 64bit result
|
||
|
' um* asmlabel um*
|
||
|
|
||
|
\ um/mod ( u1lo u1hi u2 -- remainder quotient ) \ unsigned divide & mod u1 divided by u2
|
||
|
' um/mod asmlabel um/mod
|
||
|
|
||
|
\ u/mod ( u1 u2 -- remainder quotient ) \ unsigned divide & mod u1 divided by u2
|
||
|
: u/mod 0 swap um/mod ;
|
||
|
|
||
|
\ xor ( n1 n2 -- n1_xor_n2 ) \ bitwise xor
|
||
|
: xor ifunc 0D9 cnip ;
|
||
|
|
||
|
\ waitcnt ( n1 n2 -- n1 ) \ wait until n1, add n2 to n1
|
||
|
: waitcnt ifunc 1F1 cnip ;
|
||
|
|
||
|
\ waitpeq ( n1 n2 -- ) \ wait until state n1 is equal to ina anded with n2
|
||
|
: waitpeq ifunc2 1E0 cnip ;
|
||
|
|
||
|
\ waitpne ( n1 n2 -- ) \ wait until state n1 is not equal to ina anded with n2
|
||
|
: waitpne ifunc2 1E8 cnip ;
|
||
|
|
||
|
\ vfcog ( n -- n ) makes sure n is a valid forth cog
|
||
|
: vfcog dup ffcog w@ lfcog w@ between 0= if drop ffcog w@ then ;
|
||
|
|
||
|
\ reboot ( -- ) reboot the propellor chip
|
||
|
: reboot FF 0 hubop ;
|
||
|
|
||
|
\ cogstop ( n -- )
|
||
|
: cogstop 3 hubop 2drop ;
|
||
|
|
||
|
\ cogreset ( n1 -- ) reset the forth cog
|
||
|
: cogreset 7 and dup cogstop dup dup cogd dup 100 0 fill 10 lshift cm_entry
|
||
|
2 lshift or or 2 hubop 2drop
|
||
|
\ wait for the cog to come alive
|
||
|
cogDebugvalue 8000 0 do dup m@ if leave then loop drop ;
|
||
|
|
||
|
\ reset ( -- ) reset this cog
|
||
|
: reset mydictlock w@ 0> if 1 mydictlock w! freedict then cogid cogreset ;
|
||
|
|
||
|
\ disio ( n -- ) disconnect the output of cog n
|
||
|
: disio cogEmitptr 0 swap w! ;
|
||
|
|
||
|
\ connio ( n1 n2 -- ) connect the output from cog n1 to the input of cog n2
|
||
|
: connio 7 and cogInbyte swap 7 and cogEmitptr w! ;
|
||
|
|
||
|
\ >cog ( n1 -- ) connect the console to the forth cog
|
||
|
: >cog cogCON w@ disio inCON over cogEmitptr w! dup cogInbyte outCON w! cogCON w! ;
|
||
|
|
||
|
\ these variables need to be defined after >cog to operate properly when forth is being rebuilt
|
||
|
|
||
|
\ the cog connected to the console
|
||
|
cogCON w@ wvariable cogCON cogCON w!
|
||
|
|
||
|
\ data to the console, a cogs mcwEmitptr points to inCON when it is connected
|
||
|
inCON w@ wvariable inCON inCON w!
|
||
|
|
||
|
\ data from the console, points to a cogs mcwInbyte when it is connected
|
||
|
outCON w@ wvariable outCON outCON w!
|
||
|
|
||
|
\ the CTLa CTLb and CTLc input from the console
|
||
|
ctlCON w@ wvariable ctlCON ctlCON w!
|
||
|
|
||
|
\ clkfreq ( -- u1 ) the system clock frequency
|
||
|
: clkfreq 0 m@ ;
|
||
|
|
||
|
\ parat ( offset -- addr ) the offset is added to the contents of the par register, giving an address references
|
||
|
\ the cogdata
|
||
|
: parat par @ + ;
|
||
|
|
||
|
\ cogd ( n -- addr) the address of the data area for cog n
|
||
|
: cogd 7 and 8 lshift cm_cogdata + ;
|
||
|
|
||
|
\ mcwInbyte ( -- addr ) the address of the character input as a word, $100 means no char is ready, otherwise the
|
||
|
\ next char is in the lo byte, write $100 after the char is read
|
||
|
: mcwInbyte 0 parat ;
|
||
|
|
||
|
: cogInbyte cogd ;
|
||
|
|
||
|
\ mcwEmitptr ( -- addr ) address of the word for memory based emit
|
||
|
: mcwEmitptr 2 parat ;
|
||
|
: cogEmitptr cogd 2+ ;
|
||
|
|
||
|
\ mcwState ( -- addr ) access as a word, the address of a variable which is
|
||
|
\ 0 - interpret mode
|
||
|
\ 1 - forth compile mode
|
||
|
: mcwState 4 parat ;
|
||
|
|
||
|
\ compile? ( -- t/f ) true if we are in a compile
|
||
|
: compile? mcwState w@ 0<> ;
|
||
|
|
||
|
\ mcwDebugcmd ( -- addr ) the address of the debugcmd as a word, used to commincate from forth cog to request a reset,
|
||
|
\ or for traces
|
||
|
: mcwDebugcmd 6 parat ;
|
||
|
: cogDebugcmd cogd 6 + ;
|
||
|
|
||
|
\ mcwDebugvalue ( -- addr ) the address of the debugvalue as a long, used in conjuction with debugcmd
|
||
|
: mcwDebugvalue 8 parat ;
|
||
|
: cogDebugvalue cogd 8 + ;
|
||
|
|
||
|
\ mcwBase ( -- addr ) access as a word, the address of the base variable
|
||
|
: mcwBase C parat ;
|
||
|
|
||
|
\ mcwAhere ( -- addr ) access as a word, the first unused register address in this cog
|
||
|
: mcwAhere E parat ;
|
||
|
|
||
|
\ execword ( -- addr ) a long, an area where the current word for execute is stored
|
||
|
: execword 10 parat ;
|
||
|
|
||
|
\ execute ( addr -- ) execute the word - pfa address is on the stack
|
||
|
: execute dup fMask @ and if IP ! else execword w! ca_a_exit execword 2+ w! execword IP ! then ;
|
||
|
|
||
|
\ mcw>out ( -- addr ) access as a word, the offset to the current output byte
|
||
|
: mcw>out 14 parat ;
|
||
|
|
||
|
\ mcw>in ( -- addr ) access as a word, addr is the var the offset in characters from the start of the input buffer to
|
||
|
\ the parse area.
|
||
|
: mcw>in 16 parat ;
|
||
|
|
||
|
\ mydictlock ( -- addr ) access as a word, the number of times dictlock has been executed in the cog minus the freedict
|
||
|
: mydictlock 18 parat ;
|
||
|
|
||
|
\ mcwFsliceptr ( -- ) if this is not zero it is called in the key routine
|
||
|
: mcwFsliceptr 1A parat ;
|
||
|
|
||
|
\ the negative of the last time the _fSlice routine was called
|
||
|
: mcLastcnt 1C parat ;
|
||
|
|
||
|
\ the maximum count between calls of _fSlice
|
||
|
: mcFslicecnt 20 parat ;
|
||
|
|
||
|
: _fSlicer cnt @ dup mcLastcnt m@ + mcFslicecnt m@ max mcFslicecnt m! negate mcLastcnt m! ;
|
||
|
|
||
|
\ _fSlice ( -- ) if the fSLicePtr is set
|
||
|
: _fSlice mcwFsliceptr w@ dup if execute else drop then ;
|
||
|
|
||
|
\ mcPad ( -- addr ) access as bytes, or words and long, the address of the pad area - used by accept for keyboard input,
|
||
|
\ can be used carefully by other code
|
||
|
: mcPad 24 parat ;
|
||
|
: cogPad cogd 24 + ;
|
||
|
|
||
|
\ _pclr ( addr -- ) fill padsize / 4 longs with blanks, addr must be long aligned
|
||
|
: _pclr dup padsize + swap do 20202020 i m! 4 +loop ;
|
||
|
|
||
|
\ cogPadclr ( n -- ) clear out the pad on cog n
|
||
|
: cogPadclr cogPad _pclr ;
|
||
|
|
||
|
\ pad>in ( -- addr ) addr is the address to the start of the parse area.
|
||
|
: pad>in mcw>in w@ mcPad + ;
|
||
|
|
||
|
\ namemax ( -- n1 ) the maximum name length allowed must be 1F
|
||
|
: namemax 1F ;
|
||
|
|
||
|
\ padsize ( -- n1 ) the size of the pad area
|
||
|
: padsize 80 ;
|
||
|
|
||
|
\ these are temporay variables, and by convention are only used within a word
|
||
|
\ caution, make sure you know what words you are calling
|
||
|
: mcwT0 A4 parat ;
|
||
|
: mcwT1 A6 parat ;
|
||
|
: mcT A8 parat ; \ 40 byte array overflows into mcNumpad
|
||
|
|
||
|
\ mcNumpad ( -- addr ) the of the area used by the numeric output routines, can be used carefully by other code
|
||
|
: mcNumpad C0 parat ;
|
||
|
|
||
|
\ pad>out ( -- addr ) addr is the address to the the current output byte
|
||
|
: pad>out mcw>out w@ mcNumpad + ;
|
||
|
|
||
|
\ numpadsize ( -- n1 ) the size of the numpad
|
||
|
: numpadsize 30 ;
|
||
|
|
||
|
\ keyto ( -- c1 true | false ) a key or a timeout
|
||
|
: keyto 0 mswKeyTO w@ 0 do key? if drop key -1 leave then loop ;
|
||
|
|
||
|
\ emit? ( -- t/f) true if the output is ready for a char
|
||
|
: emit? _fSlice mcwEmitptr w@ dup if w@ 100 and 0<> else drop -1 then ;
|
||
|
|
||
|
\ emit ( c1 -- ) emit the char on the stack
|
||
|
: emit begin emit? until FF and mcwEmitptr w@ dup if w! else 2drop then ;
|
||
|
|
||
|
\ key? ( -- t/f) true if there is a key ready for input
|
||
|
: key? _fSlice mcwInbyte w@ 100 and 0= ;
|
||
|
|
||
|
\ key ( -- c1 ) get a key
|
||
|
: key begin key? until mcwInbyte w@ 100 mcwInbyte w! ;
|
||
|
|
||
|
\ fkey? ( -- c1 t/f ) fast nonblocking key routine
|
||
|
: fkey? mcwInbyte w@ dup 100 and if 0 else 100 mcwInbyte w! -1 then ;
|
||
|
|
||
|
\ nip ( x1 x2 -- x1 )
|
||
|
: nip swap drop ;
|
||
|
|
||
|
\ tuck ( x1 x2 -- x2 x1 x2 )
|
||
|
: tuck swap over ;
|
||
|
|
||
|
\ 2dup ( n1 n2 -- n1 n2 n1 n2 ) copy top 2 items on the stack
|
||
|
: 2dup over over ;
|
||
|
|
||
|
\ 2drop ( n1 n2 -- ) drop top 2 items on the stack
|
||
|
: 2drop drop drop ;
|
||
|
|
||
|
\ 3drop ( n1 n2 n3 -- ) drop top 3 items on the stack
|
||
|
: 3drop drop drop drop ;
|
||
|
|
||
|
\ u/ ( u1 u2 -- u1/u2) u1 divided by u2
|
||
|
: u/ u/mod nip ;
|
||
|
|
||
|
\ u* ( u1 u2 -- u1*u2) u1 multiplied by u2
|
||
|
: u* um* drop ;
|
||
|
|
||
|
\ invert ( n1 -- n2 ) bitwise invert n1
|
||
|
: invert -1 xor ;
|
||
|
|
||
|
\ negate ( n1 -- 0-n1 ) the negative of n1
|
||
|
: negate ifunc1 149 cnip ;
|
||
|
|
||
|
\ 0= ( n1 -- t/f ) true if n1 is zero
|
||
|
: 0= 0 = ;
|
||
|
|
||
|
\ <> ( x1 x2 -- flag ) flag is true if and only if x1 is not bit-for-bit the same as x2.
|
||
|
: <> = invert ;
|
||
|
|
||
|
\ 0 <> ( n1 -- t/f ) true if n1 is not zero
|
||
|
: 0<> 0= invert ;
|
||
|
|
||
|
\ 0< ( n1 -- t/f ) true if n1 < 0
|
||
|
: 0< 0 < ;
|
||
|
|
||
|
\ 0> ( n1 -- t/f ) true if n1 > 0
|
||
|
: 0> 0 > ;
|
||
|
|
||
|
\ 1+ ( n1 -- n1+1 )
|
||
|
: 1+ 1 + ;
|
||
|
|
||
|
\ 1- ( n1 -- n1-1 )
|
||
|
: 1- 1 - ;
|
||
|
|
||
|
\ 2+ ( n1 -- n1+2 )
|
||
|
: 2+ 2 + ;
|
||
|
|
||
|
\ 4+ ( n1 -- n1+4 )
|
||
|
: 4+ 4 + ;
|
||
|
|
||
|
\ 2- ( n1 -- n1-2 )
|
||
|
: 2- 2 - ;
|
||
|
|
||
|
\ 2* ( n1 -- n1<<1 ) n2 is shifted logically left 1 bit
|
||
|
: 2* 1 lshift ;
|
||
|
|
||
|
\ 2/ ( n1 -- n1>>1 ) n2 is shifted arithmetically right 1 bit
|
||
|
: 2/ 1 rashift ;
|
||
|
|
||
|
\ rot2 ( x1 x2 x3 -- x3 x1 x2 )
|
||
|
: rot2 rot rot ;
|
||
|
|
||
|
\ >= ( n1 n2 -- t/f) true if n1 >= n2
|
||
|
: >= 2dup > rot2 = or ;
|
||
|
|
||
|
\ <= ( n1 n2 -- t/f) true if n1 <= n2
|
||
|
: <= 2dup < rot2 = or ;
|
||
|
|
||
|
\ 0>= ( n1 -- t/f ) true if n1 >= 0
|
||
|
: 0>= dup 0 > swap 0= or ;
|
||
|
|
||
|
\ w+! ( n1 addr -- ) add n1 to the word contents of address
|
||
|
: w+! dup w@ rot + swap w! ;
|
||
|
|
||
|
\ orc! ( c1 addr -- ) or c1 with the contents of address
|
||
|
: orc! dup c@ rot or swap c! ;
|
||
|
|
||
|
\ andc! ( c1 addr -- ) and c1 with the contents of address
|
||
|
: andc! dup c@ rot and swap c! ;
|
||
|
|
||
|
\ between ( n1 n2 n3 -- t/f ) true if n2 <= n1 <= n3
|
||
|
: between rot2 over <= rot2 >= and ;
|
||
|
|
||
|
\ cr ( -- ) emits a carriage return
|
||
|
: cr D emit ;
|
||
|
|
||
|
\ space ( -- ) emits a space
|
||
|
: space bl emit ;
|
||
|
|
||
|
\ spaces ( n -- ) emit n spaces
|
||
|
: spaces dup if 0 do space loop else drop then ;
|
||
|
|
||
|
\ .hex ( n -- ) emit a single hex digit
|
||
|
: .hex F and 30 + dup 39 > if 7 + then emit ;
|
||
|
|
||
|
\ .byte ( n -- ) emit 2 hex digits
|
||
|
: .byte dup 4 rshift .hex .hex ;
|
||
|
|
||
|
\ .word ( n -- ) emit 4 hex digits
|
||
|
: .word dup 8 rshift .byte .byte ;
|
||
|
|
||
|
\ .long ( n -- ) emit 8 hex digits
|
||
|
: .long dup 10 rshift .word .word ;
|
||
|
|
||
|
\ bounds ( x n -- x+n x )
|
||
|
: bounds over + swap ;
|
||
|
|
||
|
\ alignl ( n1 -- n1) aligns n1 to a long (32 bit) boundary
|
||
|
: alignl 3 + FFFFFFFC and ;
|
||
|
|
||
|
\ alignw ( n1 -- n1) aligns n1 to a halfword (16 bit) boundary
|
||
|
: alignw 1+ FFFFFFFE and ;
|
||
|
|
||
|
\ c@++ ( c-addr -- c-addr+1 c1 ) fetch the character and increment the address
|
||
|
: c@++ dup c@ swap 1+ swap ;
|
||
|
|
||
|
\ ctolower ( c1 -- c1 ) if c is A-Z converts it to lower case
|
||
|
: ctolower dup 41 5A between if 20 or then ;
|
||
|
|
||
|
\ ctoupper ( c1 -- c1 ) if c is a-z converts it to upper case
|
||
|
: ctoupper dup 61 7A between if DF and then ;
|
||
|
|
||
|
\ todigit ( c1 -- n1 ) converts character to a number
|
||
|
: todigit ctoupper 30 - dup 9 > if 7 - dup A < if -1 then then ;
|
||
|
|
||
|
\ isdigit ( c1 -- t/f ) true if is it a valid digit according to base
|
||
|
: isdigit todigit dup 0>= swap mcwBase w@ < and ;
|
||
|
|
||
|
\ isunumber ( c-addr len -- t/f ) true if the string is numeric
|
||
|
: isunumber bounds -1 rot2 do i c@ isdigit and loop ;
|
||
|
|
||
|
\ unumber ( c-addr len -- u1 ) convert string to an unsigned number
|
||
|
: unumber bounds 0 rot2 do mcwBase w@ u* i c@ todigit + loop ;
|
||
|
|
||
|
\ number ( c-addr len -- n1 ) convert string to a signed number
|
||
|
: number over c@ 2D = if 1- 0 max swap 1+ swap unumber negate else unumber then ;
|
||
|
|
||
|
\ isnumber ( c-addr len -- t/f ) true if the string is numeric
|
||
|
: isnumber over c@ 2D = if 1- 0 max swap 1+ swap then isunumber ;
|
||
|
|
||
|
\ .str ( c-addr u1 -- ) emit u1 characters at c-addr
|
||
|
: .str dup if bounds do i c@ 20 max 7F min emit loop else 2drop then ;
|
||
|
|
||
|
\ npfx ( c-addr1 c-addr2 -- t/f ) -1 if c-addr2 is prefix of c-addr1, 0 otherwise
|
||
|
: npfx namelen rot namelen rot 2dup > if min bounds do c@++ i c@ <> if drop 0 leave then loop 0<> else 2drop 2drop 0 then ;
|
||
|
|
||
|
\ namelen ( c-addr -- c-addr+1 len ) returns c-addr+1 and the length of the name at c-addr
|
||
|
: namelen c@++ namemax and ;
|
||
|
|
||
|
\ cmove ( c-addr1 c-addr2 u -- ) If u is greater than zero, copy u consecutive characters from the data space starting
|
||
|
\ at c-addr1 to that starting at c-addr2, proceeding character-by-character from lower addresses to higher addresses.
|
||
|
: cmove dup 0= if 3drop else bounds do c@++ i c! loop then drop ;
|
||
|
|
||
|
\ namecopy ( c-addr1 c-addr2 -- ) Copy the name from c-addr1 to c-addr2
|
||
|
: namecopy over namelen 1+ nip cmove ;
|
||
|
|
||
|
\ ccopy ( c-addr1 c-addr2 -- ) Copy the cstr from c-addr1 to c-addr2
|
||
|
: ccopy over c@ 1+ cmove ;
|
||
|
|
||
|
\ cappend ( c-addr1 c-addr2 -- ) addpend the cstr from c-addr1 to c-addr2
|
||
|
: cappend dup dup c@ + 1+ rot2 over c@ over c@ + swap c! dup c@ swap 1+ rot2 cmove ;
|
||
|
|
||
|
\ cappendc ( c cstr -- ) append c the cstr
|
||
|
: cappendc dup c@ 1+ over c! dup c@ + c! ;
|
||
|
|
||
|
\ cappendn ( n cstr -- ) print the number n and append to cstr
|
||
|
: cappendn swap <# #s #> swap cappend ;
|
||
|
|
||
|
\ cappendnc ( n cstr -- ) print the number n and append to cstr and then append a blank
|
||
|
: cappendnc swap <# #s #> over cappend bl swap cappendc ;
|
||
|
|
||
|
\ cogX ( cstr n -- ) execute cstr on cog n
|
||
|
: cogX vfcog dup cogInbyte begin dup w@ 100 and until rot2 dup cogPadclr cogPad 1+ swap c@++ rot swap cmove d swap w! ;
|
||
|
|
||
|
\ cogXO ( cstr -- ) disconnect console input, execute cstr on the next available cog, directing output back to this cog
|
||
|
: cogXO 0 outCON w! cogid dup 1+ vfcog dup rot connio cogX ;
|
||
|
|
||
|
\ ??? ( -- ) prints out ???
|
||
|
: ??? ." ???" ;
|
||
|
|
||
|
\ .strname ( c-addr -- ) c-addr point to a forth name field, print the name
|
||
|
: .strname dup if namelen .str else drop ??? then ;
|
||
|
|
||
|
\ .cstr ( addr -- ) emit a counted string at addr
|
||
|
: .cstr c@++ .str ;
|
||
|
|
||
|
\ dq ( -- ) emit a counted string at the IP, and increment the ip past it and word align it
|
||
|
: dq r> c@++ 2dup + alignw >r .str ;
|
||
|
|
||
|
\ i ( -- n1 ) the most current loop counter
|
||
|
: i rsPtr @ 3 + @ ;
|
||
|
|
||
|
\ j ( -- n1 ) the second most current loop counter
|
||
|
: j rsPtr @ 5 + @ ;
|
||
|
|
||
|
\ ibound ( -- n1 ) the upper bound of i
|
||
|
: ibound rsPtr @ 2+ @ ;
|
||
|
|
||
|
\ jbound ( -- n1 ) the upper bound of j
|
||
|
: jbound rsPtr @ 4+ @ ;
|
||
|
|
||
|
\ lasti? ( -- t/f ) true if this is the last value of i in this loop
|
||
|
: lasti? rsPtr @ 2+ @ 1- rsPtr @ 3 + @ = ;
|
||
|
|
||
|
\ lastj? ( -- t/f ) true if this is the last value of j in this loop
|
||
|
: lastj? rsPtr @ 4+ @ 1- rsPtr @ 5 + @ = ;
|
||
|
|
||
|
\ seti ( n1 -- ) set the most current loop counter
|
||
|
: seti rsPtr @ 3 + ! ;
|
||
|
|
||
|
\ setj ( n1 -- ) set the second most current loop counter
|
||
|
: setj rsPtr @ 5 + ! ;
|
||
|
|
||
|
\ eol? ( c1 -- c1 t/f ) true if c1 == LF or CR
|
||
|
: eol? dup A = over D = or ;
|
||
|
|
||
|
\ bs? ( c1 -- c1 t/f ) true if c1 == BS or DEL
|
||
|
: bs? dup 8 = over 7F = or ;
|
||
|
|
||
|
\ fill ( c-addr u char -- )
|
||
|
: fill rot2 bounds do dup i c! loop drop ;
|
||
|
|
||
|
\ nfa>lfa ( addr -- addr ) go from the nfa (name field address) to the lfa (link field address)
|
||
|
: nfa>lfa 2- ;
|
||
|
|
||
|
\ nfa>pfa ( addr -- addr ) go from the nfa (name field address) to the pfa (parameter field address)
|
||
|
|
||
|
: nfa>pfa 7FFF and namelen + alignw ;
|
||
|
|
||
|
\ nfa>next ( addr -- addr ) go from the current nfa to the prev nfa in the dictionary
|
||
|
|
||
|
: nfa>next nfa>lfa w@ ;
|
||
|
|
||
|
\ lastnfa ( -- addr ) gets the last NFA
|
||
|
|
||
|
: lastnfa mswlastnfa w@ ;
|
||
|
|
||
|
\ fnamechar? ( c1 -- t/f ) true if c1 is a valif name char > $20 < $7F
|
||
|
|
||
|
: fnamechar? dup 20 > swap 7F < and ;
|
||
|
|
||
|
\ fpfa>nfa ( addr -- addr ) pfa>nfa for a forth word
|
||
|
|
||
|
: fpfa>nfa 7FFF and 1- begin 1- dup c@ fnamechar? 0= until ;
|
||
|
|
||
|
\ apfa>nfa ( addr -- addr ) pfa>nfa for an asm word
|
||
|
|
||
|
: apfa>nfa lastnfa begin 2dup nfa>pfa w@ = over c@ 80 and 0= and if -1 else nfa>next dup 0= then until nip ;
|
||
|
|
||
|
\ pfa>nfa ( addr -- addr ) gets the name field address (nfa) for a parameter field address (pfa)
|
||
|
|
||
|
: pfa>nfa dup fMask @ and if fpfa>nfa else apfa>nfa then ;
|
||
|
|
||
|
\ accept ( c-addr +n1 -- +n2 ) collect n1 -2 characters or until eol, ctl characters, tab included are converted to space,
|
||
|
\ pad with 1 space at start & end. For parsing ease, and for the length byte when we make cstrs
|
||
|
|
||
|
: accept 3 max 2dup bl fill 1- swap 1+ swap bounds 0
|
||
|
|
||
|
begin key eol?
|
||
|
if cr drop -1
|
||
|
else bs?
|
||
|
if drop dup
|
||
|
if 8 emit bl emit 8 emit 1- swap 1- bl over c! swap then 0
|
||
|
else bl max dup emit swap >r over c! 1+ 2dup 1+ = r> 1+ swap then
|
||
|
then
|
||
|
until nip nip ;
|
||
|
|
||
|
\ parse ( c1 -- +n2 ) parse the word delimited by c1, or the end of buffer is reached, n2 is the length >in is the offset
|
||
|
\ in the pad of the start of the parsed word
|
||
|
|
||
|
: parse padsize mcw>in w@ = if 0 else 0 begin 2dup pad>in + c@ = if -1 else 1+ 0 then until then nip ;
|
||
|
|
||
|
\ skipbl ( -- ) increment >in past blanks or until it equals padsize
|
||
|
: skipbl begin pad>in c@ bl = if mcw>in w@ 1+ dup mcw>in w! padsize = else -1 then until ;
|
||
|
|
||
|
\ nextword ( -- ) increment >in past current counted string
|
||
|
: nextword padsize mcw>in w@ > if pad>in c@ mcw>in w@ + 1+ mcw>in w! then ;
|
||
|
|
||
|
\ parseword ( c1 -- +n2 ) skip blanks, and parse the following word delimited by c1, update to be a counted string in
|
||
|
\ the pad
|
||
|
|
||
|
: parseword skipbl parse dup if mcw>in w@ 1- 2dup mcPad + c! mcw>in w! then ;
|
||
|
|
||
|
\ parsebl ( -- t/f) parse the next word in the pad delimited by blank, true if there is a word
|
||
|
|
||
|
: parsebl bl parseword 0<> ;
|
||
|
|
||
|
\ padnw ( -- t/f ) move past current word and parse the next word, true if there is a next word
|
||
|
|
||
|
: padnw nextword parsebl ;
|
||
|
|
||
|
\ parsenw ( -- cstr ) parse and move to the next word, str ptr is zero if there is no next word
|
||
|
: parsenw parsebl if pad>in nextword else 0 then ;
|
||
|
|
||
|
\ padclr ( -- )
|
||
|
: padclr begin padnw 0= until ;
|
||
|
|
||
|
\ find ( c-addr -- c-addr 0 | xt 2 | xt 1 | xt -1 ) c-addr is a counted string, 0 - not found, 2 eXecute word,
|
||
|
\ 1 immediate word, -1 word NOT ANSI
|
||
|
|
||
|
: find lastnfa over fin dup
|
||
|
if nip dup nfa>pfa over c@ 80 and 0= if w@ then
|
||
|
swap c@ dup 40 and
|
||
|
if 20 and if 2 else 1 then
|
||
|
else drop -1 then
|
||
|
then ;
|
||
|
|
||
|
\ <# ( -- ) initialize the output area
|
||
|
: <# numpadsize mcw>out w! ;
|
||
|
|
||
|
\ #> ( -- caddr ) address of a counted string representing the output, NOT ANSI
|
||
|
: #> drop numpadsize mcw>out w@ - -1 mcw>out w+! pad>out c! pad>out ;
|
||
|
|
||
|
\ tochar ( n1 -- c1 ) convert c1 to a char
|
||
|
: tochar 1F and 30 + dup 39 > if 7 + then ;
|
||
|
|
||
|
\ # ( n1 -- n2 ) divide n1 by mcwBase and convert the remainder to a char and append to the output
|
||
|
: # mcwBase w@ u/mod swap tochar -1 mcw>out w+! pad>out c! ;
|
||
|
|
||
|
\ #s ( n1 -- 0 ) execute # until the remainder is 0
|
||
|
: #s begin # dup 0= until ;
|
||
|
|
||
|
\ . ( n1 -- )
|
||
|
: . dup 0< if 2D emit negate then <# #s #> .cstr 20 emit ;
|
||
|
|
||
|
\ cogid ( -- n1 ) return id of the current cog ( 0 - 7 )
|
||
|
: cogid -1 1 hubop drop ;
|
||
|
|
||
|
\ locknew ( -- n2 ) allocate a lock, result is in n2, -1 if unsuccessful
|
||
|
: locknew -1 4 hubop -1 = if drop -1 then ;
|
||
|
|
||
|
\ lockret ( n1 -- ) deallocate a lock, previously allocated via locknew
|
||
|
: lockret 5 hubop 2drop ;
|
||
|
|
||
|
\ lockset ( n1 -- n2 ) set lock n1, result is in n2, -1 if the lock was set as per 'c' flag, lock ( n1 ) must have
|
||
|
\ been allocated via locknew
|
||
|
: lockset 6 hubop nip ;
|
||
|
|
||
|
\ lockclr ( n1 -- n2 ) set lock n1, result is in n2, -1 if the lock was set as per 'c' flag, lock ( n1 ) must have
|
||
|
\ been allocated via locknew
|
||
|
|
||
|
: lockclr 7 hubop nip ;
|
||
|
|
||
|
\ lockdict? ( -- t/f ) attempt to lock the forth dictionary, 0 if unsuccessful -1 if successful
|
||
|
|
||
|
: lockdict? mydictlock w@ if 1 mydictlock w+! -1 else 0 lockset 0= if 1 mydictlock w! -1 else 0 then then ;
|
||
|
|
||
|
\ freedict ( -- ) free the forth dictionary, if I have it locked
|
||
|
|
||
|
: freedict mydictlock w@ dup if 1- dup mydictlock w! 0= if 0 lockclr drop then else drop then ;
|
||
|
|
||
|
\ lockdict ( -- ) lock the forth dictionary
|
||
|
|
||
|
: lockdict begin lockdict? until ;
|
||
|
|
||
|
: _eoom ." Out of memory" cr ;
|
||
|
\ checkdict ( n -- ) make sure there are at least n bytes available in the dictionary
|
||
|
: checkdict mswHere w@ + mswDictend w@ >=
|
||
|
if cr mswHere w@ . mswDictend . _eoom clearkeys reset then ;
|
||
|
|
||
|
: _c1 lockdict
|
||
|
mswlastnfa w@ mswHere w@ dup 2+ mswlastnfa w! swap over w! 2+ ;
|
||
|
|
||
|
: _c2 over namecopy namelen + alignw mswHere w! freedict ;
|
||
|
|
||
|
\ ccreate ( cstr -- ) create a dictionary entry
|
||
|
: ccreate _c1 swap _c2 ;
|
||
|
|
||
|
\ create ( -- ) skip blanks parse the next word and create a dictionary entry
|
||
|
: create bl parseword if _c1 pad>in _c2 nextword then ;
|
||
|
|
||
|
\ clabel ( cstr -- ) create an assembler constant at the current cog mcwAhere
|
||
|
: clabel lockdict ccreate ca_a_doconw w, mcwAhere w@ w, forthentry freedict ;
|
||
|
|
||
|
\ herelal ( -- ) align contents of here to a long boundary, 4 byte boundary
|
||
|
: herelal lockdict 4 checkdict mswHere w@ alignl mswHere w! freedict ;
|
||
|
|
||
|
\ herewal ( -- ) align contents of here to a word boundary, 2 byte boundary
|
||
|
: herewal lockdict 2 checkdict mswHere w@ alignw mswHere w! freedict ;
|
||
|
|
||
|
\ allot ( n1 -- ) add n1 to here, allocates space on the data dictionary or release it
|
||
|
: allot lockdict dup checkdict mswHere w+! freedict ;
|
||
|
|
||
|
\ aallot ( n1 -- ) add n1 to aHere, allocates space in the cog or release it, n1 is # of longs
|
||
|
: aallot mcwAhere w+! mcwAhere w@ par >= if _eoom reset then ;
|
||
|
|
||
|
\ , ( x -- ) allocate 1 long, 4 bytes in the dictionary and copy x to that location
|
||
|
|
||
|
: , lockdict herelal mswHere w@ m! 4 allot freedict ;
|
||
|
|
||
|
\ a, ( x -- ) allocate 1 long in the cog and copy x to that location
|
||
|
: a, mcwAhere w@ ! 1 aallot ;
|
||
|
|
||
|
\ w, ( x -- ) allocate 1 halfword 2 bytes in the dictionary and copy x to that location
|
||
|
: w, lockdict herewal mswHere w@ w! 2 allot freedict ;
|
||
|
|
||
|
\ c, ( x -- ) allocate 1 byte in the dictionary and copy x to that location
|
||
|
: c, lockdict mswHere w@ c! 1 allot freedict ;
|
||
|
|
||
|
\ orlnfa ( c1 -- ) ors c1 with the nfa length of the last name field entered
|
||
|
: orlnfa lockdict lastnfa orc! freedict ;
|
||
|
|
||
|
\ forthentry ( -- ) marks last entry as a forth word
|
||
|
: forthentry lockdict 80 orlnfa freedict ;
|
||
|
|
||
|
\ immediate ( -- ) marks last entry as an immediate word
|
||
|
: immediate lockdict 40 orlnfa freedict ;
|
||
|
|
||
|
\ exec ( -- ) marks last entry as an eXecute word, executes always
|
||
|
: exec lockdict 60 orlnfa freedict ;
|
||
|
|
||
|
\ leave ( -- ) exits at the next loop or +loop, i is placed to the max loop value
|
||
|
: leave r> r> r> drop dup 2>r >r ;
|
||
|
|
||
|
\ clearkeys ( -- ) clear the input keys
|
||
|
: clearkeys 0 mcwState w!
|
||
|
begin -1 mswKeyTO w@ 0 do key? if key drop drop 0 leave then loop until ;
|
||
|
|
||
|
\ w>l ( n1 n2 -- n1n2 ) consider only lower 16 bits
|
||
|
: w>l FFFF and swap 10 lshift or ;
|
||
|
|
||
|
\ l>w ( n1n2 -- n1 n2) break into 16 bits
|
||
|
: l>w dup 10 rshift swap FFFF and ;
|
||
|
|
||
|
|
||
|
: : lockdict create 3741 1 mcwState w! ;
|
||
|
|
||
|
: _mmcs ." MISMATCHED CONTROL STRUCTURE(S)" cr clearkeys ;
|
||
|
|
||
|
: _; w, 0 mcwState w! forthentry 3741 <> if _mmcs then freedict ;
|
||
|
\ to prevent ; from using itself while it is defining itself
|
||
|
: ;; ca_a_exit _; ; immediate
|
||
|
|
||
|
: ; ca_a_exit _; ;; immediate
|
||
|
|
||
|
: dothen l>w dup 1235 = swap 1239 = or if dup mswHere w@ swap - swap w! else _mmcs then ;
|
||
|
|
||
|
: then dothen ; immediate
|
||
|
|
||
|
: thens begin dup FFFF and dup 1235 = swap 1239 = or if dothen 0 else -1 then until ; immediate
|
||
|
|
||
|
: if ca_a_0branch w, mswHere w@ 1235 w>l 0 w, ; immediate
|
||
|
|
||
|
: else ca_a_branch w, 0 w, dothen mswHere w@ 2- 1239 w>l ; immediate
|
||
|
|
||
|
: until l>w 1317 = if ca_a_0branch w, mswHere w@ - w, else _mmcs then ; immediate
|
||
|
|
||
|
: begin mswHere w@ 1317 w>l ; immediate
|
||
|
|
||
|
: doloop swap l>w 2329 = if swap w, mswHere w@ - w, else _mmcs then ;
|
||
|
|
||
|
: loop ca_a_(loop) doloop ; immediate
|
||
|
|
||
|
: +loop ca_a_(+loop) doloop ; immediate
|
||
|
|
||
|
: do ca_a_2>r w, mswHere w@ 2329 w>l ; immediate
|
||
|
|
||
|
: _ecs 3A emit space ;
|
||
|
: _udf ." UNDEFINED WORD " ;
|
||
|
|
||
|
: ." cm_dq w, 1 mcw>in w+! 22 parse dup c, dup pad>in mswHere w@ rot cmove dup allot 1+ mcw>in w+! herewal ; immediate
|
||
|
|
||
|
\ fisnumber ( -- ) dummy routine s for indirection when float package is loaded
|
||
|
: fisnumber isnumber ;
|
||
|
: fnumber number ;
|
||
|
|
||
|
\ interpretpad ( -- ) interpret the contents of the pad
|
||
|
: interpretpad 0 mcw>in w!
|
||
|
begin bl parseword
|
||
|
if pad>in nextword find dup
|
||
|
if dup -1 =
|
||
|
if drop compile? if w, else execute then 0
|
||
|
else 2 =
|
||
|
if execute 0 else
|
||
|
compile? if execute 0 else pfa>nfa ." IMMEDIATE WORD " .strname clearkeys cr -1 then
|
||
|
then
|
||
|
then
|
||
|
else drop dup c@++ fisnumber
|
||
|
if
|
||
|
c@++ fnumber compile? if dup 0 FFFF between if ca_a_litw w, w, else ca_a_literal w, , then then 0
|
||
|
else
|
||
|
0 mcwState w! freedict _udf .strname cr clearkeys -1
|
||
|
then
|
||
|
then
|
||
|
else -1 then until ;
|
||
|
|
||
|
\ [0m ( -- ) a dummy word, fast load echos this so...
|
||
|
: [0m ;
|
||
|
|
||
|
\ interpret ( -- ) the main interpreter loop
|
||
|
: interpret
|
||
|
\ ansi red
|
||
|
1b emit 5b emit 33 emit 31 emit 6d emit
|
||
|
mcPad padsize accept drop
|
||
|
\ ansi normal
|
||
|
1b emit 5b emit 30 emit 6d emit
|
||
|
interpretpad ;
|
||
|
|
||
|
|
||
|
\ variable ( -- ) skip blanks parse the next word and create a variable, allocate a long, 4 bytes
|
||
|
: variable lockdict create ca_a_dovar w, 0 , forthentry freedict ;
|
||
|
|
||
|
\ _wc1 ( x -- nfa ) skip blanks parse the next word and create a constant, allocate a word, 2 bytes
|
||
|
: _wc1 lockdict create ca_a_doconw w, w, forthentry lastnfa freedict ;
|
||
|
|
||
|
\ wconstant ( x -- ) skip blanks parse the next word and create a constant, allocate a word, 2 bytes
|
||
|
: wconstant _wc1 drop ;
|
||
|
|
||
|
\ avariable ( -- ) skip blanks parse the next word and create a cog variable, allocate a long
|
||
|
: avariable mcwAhere w@ _wc1 1 aallot ;
|
||
|
|
||
|
\ wvariable ( -- ) skip blanks parse the next word and create a variable, allocate a word, 2 bytes
|
||
|
: wvariable lockdict create ca_a_dovarw w, 0 w, forthentry freedict ;
|
||
|
|
||
|
\ constant ( x -- ) skip blanks parse the next word and create a constant, allocate a long, 4 bytes
|
||
|
: constant lockdict create ca_a_docon w, , forthentry freedict ;
|
||
|
|
||
|
\ asmlabel ( x -- ) skip blanks parse the next word and create an assembler entry
|
||
|
: asmlabel lockdict create w, freedict ;
|
||
|
|
||
|
\ hex ( -- ) set the base for hexadecimal
|
||
|
: hex 10 mcwBase w! ;
|
||
|
|
||
|
\ decimal ( -- ) set the mcwBase for decimal
|
||
|
: decimal A mcwBase w! ;
|
||
|
|
||
|
|
||
|
\ words ( cstr -- ) prints the words in the forth dictionary starting with cstr, 0 prints all
|
||
|
|
||
|
: _words 0 >r lastnfa ." NFA (Forth/Asm Immediate eXecute) Name"
|
||
|
begin
|
||
|
2dup swap dup if npfx else 2drop -1 then
|
||
|
if
|
||
|
r> dup 0= if cr then 1+ 3 and >r
|
||
|
dup .word space dup c@ dup 80 and
|
||
|
if 46 else 41 then emit dup 40 and
|
||
|
if 49 else 20 then emit 20 and
|
||
|
if 58 else 20 then emit
|
||
|
space dup .strname dup c@ namemax and 15 swap - 0 max spaces
|
||
|
then nfa>next dup 0=
|
||
|
until r> 3drop cr ;
|
||
|
|
||
|
\ words ( -- ) prints the words in the forth dictionary, if the pad has another string following, with that prefix
|
||
|
: words parsenw _words ;
|
||
|
|
||
|
|
||
|
|
||
|
\ del_ms ( n1 -- ) for 80Mhz 68DB max
|
||
|
: del_ms 7FFFFFFF clkfreq 3e8 u/ u/ min 1 max clkfreq 3E8 u/ u* cnt @ + begin dup cnt @ - 0< until drop ;
|
||
|
: del_sec 10 u/mod dup if 0 do 3e80 del_ms loop else drop then dup if 0 do 3e8 del_ms loop else drop then ;
|
||
|
|
||
|
\ >m ( n1 -- n2 ) produce a 1 bit mask n2 for position n
|
||
|
: >m 1 swap lshift ;
|
||
|
|
||
|
\ eeprom read and write routine for the prop proto board AT24CL256 eeprom on pin 28 sclk, 29 sda
|
||
|
\ pxi ( n1 -- ) set pin # n1 to an input
|
||
|
: pxi >m invert dira @ and dira ! ;
|
||
|
|
||
|
\ pxo ( n1 -- ) set pin # n1 to an input
|
||
|
: pxo >m dira @ or dira ! ;
|
||
|
|
||
|
\ pxl ( n1 -- ) set pin # n1 to lo
|
||
|
: pxl >m mpxl ;
|
||
|
|
||
|
\ pxh ( n1 -- ) set pin # n1 to hi
|
||
|
: pxh >m mpxh ;
|
||
|
|
||
|
\ px ( t/f n1 -- ) set pin # n1 to h - true or l false
|
||
|
: px swap if pxh else pxl then ;
|
||
|
|
||
|
\ px? ( n1 -- t/f) true if pin n1 is hi
|
||
|
: px? >m mpx ;
|
||
|
|
||
|
1C wconstant _scl \ SCL
|
||
|
1D wconstant _sda \ SDA
|
||
|
|
||
|
1 _scl lshift constant _sclm
|
||
|
1 _sda lshift constant _sdam
|
||
|
|
||
|
: _sdai _sda pxi ;
|
||
|
: _sdao _sda pxo ;
|
||
|
: _scli _scl pxi ;
|
||
|
: _sclo _scl pxo ;
|
||
|
|
||
|
: _sdal _sdam mpxl ;
|
||
|
: _sdah _sdam mpxh ;
|
||
|
: _scll _sclm mpxl ;
|
||
|
: _sclh _sclm mpxh ;
|
||
|
: _sda? _sdam mpx ;
|
||
|
|
||
|
\ _eeInit ( -- ) initialize the eeprom in case it is in a weird state
|
||
|
: _eeInit _sclh _sclo _sdai 9 0 do _scll _sclh _sda? if leave then loop ;
|
||
|
|
||
|
\ _eeStart ( -- ) start the data transfer
|
||
|
: _eeStart _sclh _sclo _sdah _sdao _sdal _scll ;
|
||
|
|
||
|
\ _eeStop ( -- ) stop the data transfer
|
||
|
: _eeStop _sclh _sdah _scli _sdai ;
|
||
|
|
||
|
\ _eeWrite ( c1 -- t/f ) write a byte to the eeprom, returns ack bit
|
||
|
: _eeWrite 80 8 0
|
||
|
do 2dup and if _sdah else _sdal then _sclh _scll 1 rshift loop
|
||
|
2drop _sdai _sclh _sda? _scll _sdal _sdao ;
|
||
|
|
||
|
\ _eeRead ( t/f -- c1 ) read a byte from the eeprom, ackbit in, byte out
|
||
|
: _eeRead _sdai 0 8 0
|
||
|
do 1 lshift _sclh _sda? _scll if 1 or then loop
|
||
|
swap _sda px _sdao _sclh _scll _sdal ;
|
||
|
|
||
|
\ the eeReadPage and eeWritePage words assume the eeprom are 64kx8 and will address up to
|
||
|
\ 8 sequential eeproms
|
||
|
\ eeReadPage ( eeAddr addr u -- t/f ) return true if there was an error, use lock 1
|
||
|
: eeReadPage begin 1 lockset 0= until
|
||
|
1 max rot dup ff and swap dup 8 rshift ff and swap 10 rshift 7 and 1 lshift dup >r
|
||
|
_eeStart A0 or _eeWrite swap _eeWrite or swap _eeWrite or
|
||
|
_eeStart r> A1 or _eeWrite or
|
||
|
rot2 bounds
|
||
|
do lasti? _eeRead i c! loop _eeStop 1 lockclr drop ;
|
||
|
|
||
|
\ eeWritePage ( eeAddr addr u -- t/f ) return true if there was an error, use lock 1
|
||
|
: eeWritePage begin 1 lockset 0= until
|
||
|
1 max rot dup ff and swap dup 8 rshift ff and swap 10 rshift 7 and 1 lshift
|
||
|
_eeStart A0 or _eeWrite swap _eeWrite or swap _eeWrite or
|
||
|
rot2 bounds
|
||
|
do i c@ _eeWrite or loop _eeStop 10 del_ms 1 lockclr drop ;
|
||
|
: eeErr ." eeProm error" ;
|
||
|
|