The COG-EX Forth Word
Thursday, 22 November 2012 11:32
Shael
This article explains the use and implementation of the forth word, COG-EX. The word COG-EX was added to the dictionary starting with version 0.93 of MV4th16.The COG-EX word is intended to simplify the use of a secondary COG to implement forth words.
The interface between the COG running MV4th16 forth and a second COG running some extension software is implemented using a single 4 byte long global memory location. The address of the long memory location is passed to the second COG at startup using the PAR register. Thus the memory address must be long aligned.
The upper 16 bits of the memory location is used to pass the current forth stack pointer address, and the lower 16 bits contains a command index to be executed by the second COG. A non zero value for the command index indicates a command waiting to be executed.
When the COG running MV4th16 forth calls a function in another COG, the current stack pointer and command index are written to the shared long memory location. All parameters are passed to the called function on the forth stack. The called function returns the results on the forth stack. When the called function completes the new stack pointer value is written back to the shared memory location setting the command index to 0 to let the COG running MV4th16 forth know the function has completed. The new value for the stack pointer is loaded from the shared memory location to update the forth data stack.
The syntax of the forth word is: COG-EX ( uMemAdr uCmdIdx -- )
Where: uMemAdr = address of shared long memory location. uCmdIdx = 16 bit command index to execute.
The following code snippet shows the code required to implement the COG-EX interface in a COG. The code was taken from the CogPins.spin example file included in the CogPins example folder. See the CogPins.forth file for an example of using the COG-EX forth word.
'*********************************[ FORTH system command support routines]*********************************
'
' Variables used by forth SYSTEMEX interface
ForthTmp long 0
ForthCmd long 0
ForthStackPtr long 0
ForthScratch long 0
' Constants
ForthWordMask long $FFFF
' Remove top 16 bit value from forth stack.T1 = 16 bit value on return
'make sure we are in a command and stack pointer is valid
F_PopStack tjz ForthStackPtr, #F_PopStack_Ret
'We are in a command OK to pop value from stack
rdword ForthTmp, ForthStackPtr
add ForthStackPtr, #2
F_PopStack_Ret ret
'
' Add 16 bit value to top of forth stack.T1 = 16 bit value to write.
'make sure we are in a command and stack pointer is valid
F_PushStack tjz ForthStackPtr, #F_PushStack_Ret
'We are in a command OK to push a value to the stack
sub ForthStackPtr, #2
wrword ForthTmp, ForthStackPtr
F_PushStack_Ret ret
'
'Pop a 32 bit value from the forth stack in Low word high word order.
'Read High 16 bits from the stack
F_PopStack32 call #F_PopStack
mov ForthScratch, ForthTmp
shl ForthScratch, #16
'Read low 16 bits from stack
call #F_PopStack
or ForthTmp, ForthScratch
F_PopStack32_ret ret
'
'Push a 32 bit value to the stack in Low word high word order.
'write low 16 bits to stack
F_PushStack32 call #F_PushStack
'write high 16 bits to stack
shr ForthTmp, #16
call #F_PushStack
F_PushStack32_ret ret
'
'
'Wait for a system command to be requested by forth engine
F_WaitForCmd rdlong ForthCmd, par
test ForthCmd, ForthWordMask wz
if_z jmp #F_WaitForCmd
'Seperate stack address from command number
mov ForthStackPtr, ForthCmd
shr ForthStackPtr, #16
and ForthCmd, ForthWordMask
'see if we have a valid command
cmp ForthCmd, #c_ForthCmdCount wc
if_c jmp #F_WaitForCmd_ret
' we have an invalid command
call #F_CompleteCommand
jmp #F_WaitForCmd
' we have a valid command, get the stack pointer address
F_WaitForCmd_Ret ret
'
'Update stack pointer then exit
F_SaveStackptr mov ForthTmp, par
add ForthTmp, #2
wrword ForthStackPtr, ForthTmp
'Indicate system command requested by forth engine is completed
F_CompleteCommand mov ForthCmd, #0
wrword ForthCmd, par
mov ForthStackPtr, #0
F_SaveStackptr_ret
F_CompleteCommand_ret ret
'
'
'Wait for a command and execute it
F_Do_Cmds call #F_WaitForCmd
'we have a cmd index 1..XX
mov ForthTmp, #F_JUMP_TABLE
add ForthTmp, ForthCmd
movs :F_Set_Cmd_Jump, ForthTmp
nop
:F_Set_Cmd_Jump mov :F_Do_Cmd_Jump, (ForthTmp)
nop
:F_Do_Cmd_Jump nop
'The called function will return here
F_Do_Cmds_Return call #F_SaveStackptr
jmp #F_Do_Cmds
'
'
'Table of Jump opcodes for each of the supported forth functions
F_JUMP_TABLE nop '(0)
call #F_CMD_RdIna '(1)
call #F_CMD_RdOuta '(2)
' *********************************[ Forth Commands ]*********************************
'
' 1) Read the I/O pins input register ina@ ( -- dAllPins )
F_CMD_RdIna mov ForthTmp, INA
call #F_PushStack32
F_CMD_RdIna_ret ret
'
' 2) Read the I/O pins output register
' outa@ ( -- dRegValue )
F_CMD_RdOuta mov ForthTmp, OUTA
call #F_PushStack32
F_CMD_RdOuta_ret ret