Hello
I have long wanted to start studying and testing FlashForth.
I prepared a board with a PIC18F26K22 and flash it with a FF-5 to it, but it stayed pending, and finally at the end of last March I finally started his study.
First of all, my thanks and acknowledgment to Mikael Nordman for such a great job.
Once I studied how it works, I thought about implementing an application written in flash-forth.
I missed a high level and low level disassembler, to check how the code looks, as well as a forth debugger to detect problems of programnig.
I have started to implement them.
This work has been developed for PIC18.
I would like to provide the code.
I'm looking at how to make a new wiki topic.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The 'see' of forth is complex of programing since this forth is direct-threading or rather subroutine-threaded code, with in-line expansion. In this way a call to a forth word can be compiled as a 'call', a 'goto', or correspond to a serie of inline cpu instructions.
As for the low-level disassembler, I found it important to give the option to interpret the ram bank in use, and present the symbolic name of the SFR, as well as the name of the routine (forth-word) called for each call or each goto.
The names of some SFRs are in a table of constants, to be used by the disassembler and also the assembler.
The names of the cpu instructions are in a table of the disassembler, which in the future could be grouped with the assembler, to take up less space on the flashrom.
Disassembly is done with forth words to be called for each instruction to see (which will use the debug) or by blocks of instrucctions to see from the 'forth' console.
see ( - | word ) see word code on a line
seel ( - | word ) see word code by lines
seea ( - | word ) see word on assembler
(.uasm) ( addr – addr' ) print instruction, returns address to next
disassembly variables are updated
(.fw) ( addr – addr' ) print a word, returns address to next word
disassembly variables are updated
As an example (copied from the window of a serial terminal ):
**see within
within over - >r - r> u< ;
ok<#,ram>
seel within
UnDec: within
$10b2: over
$10b4: -
$10b6: >r
$10b8: -
$10ba: r>
$10bc: u< ;
ok<#,ram>
seea within
UnDec: within
$10b2: df35 over rcall,
$10b4: df88 - rcall,
$10b6: df44 >r rcall,
$10b8: df86 - rcall,
$10ba: df4f r> rcall,
$10bc: ef8b.f008 u< goto,
ok<#,ram>**
For a branched word:
**: ss $12 0= if dup else $3456 then begin dup until drop ; ok<#,ram>
see ss
ss $0012 (0=?bra>$5fce) dup (bra>$5fd6) $3456 (dup?bra<$5fd6) drop ;
ok<#,ram>
seel ss
UnDec: ss
$5fbc: (lit:$0012)
$5fc2: (0=?bra>$5fce)
$5fc8: dup
$5fcc: (bra>$5fd6)
$5fce: (lit:$3456)
$5fd6: (dup?bra<$5fd6)
$5fdc: drop
$5fe0: ;
ok<#,ram>
seea ss
UnDec: ss
$5fbc: 0e12 $12 movlw,
$5fbe: 6eec PREINC0 a, movwf,
$5fc0: 6aec PREINC0 a, clrf,
$5fc2: 50ed POSTDEC0 w, a, movf,
$5fc4: 10ed POSTDEC0 w, a, iorwf,
$5fc6: e103 $5fce bnz,
$5fc8: ecc4.f007 dup call,
$5fcc: d004 $5fd6 bra,
$5fce: 0e56 $56 movlw,
$5fd0: 6eec PREINC0 a, movwf,
$5fd2: 0e34 $34 movlw,
$5fd4: 6eec PREINC0 a, movwf,
$5fd6: 50ed POSTDEC0 w, a, movf,
$5fd8: 10ee POSTINC0 w, a, iorwf,
$5fda: e0fd $5fd6 bz,
$5fdc: 6eed POSTDEC0 a, movwf,
$5fde: 6eed POSTDEC0 a, movwf,
$5fe0: 0012 return,
ok<#,ram>**
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
To implement the debugger, the approach has been to start from the original FF, without modifying anything of the source, in such a way that compiling the forth code from forth it can be operative.
This does not take advantage of the debugging capabilities of the cpu.
In a later version it would be interesting to use the debugging capabilities, but this would imply including code for this purpose in the source file of the forth.
This implementation is made for 18FxxK22 and obviously has dependencies.
I have proposed a debug that executes forth words step by step and that also allows go to assembler, executing instruction to instruction.
The debugger is activated on a forth-word, like "debug -word-". Once in step-by-step execution, it supports instructions by means of a key, which are:
'a'sm 'b'ack 'c'ontinue 'd'ec 'f'orth 'n'est 'h'eaders 'q'uit he'x'
With 'a' it goes to assembler mode, following cpu instructions, and with 'f' it goes on forth words mode.
The forth mode presents the data-stack after executing the instruction.
The assembly mode presents after executing the instruction, the STATUS flags, the bank and the W register, and then the return-stack.
With 'x' and 'd' the presentation of the data-stack is changed to hexadecimal or decimal.
The step-by-step execution in forth is always inside the word that is being traced, to enter a level in the execution we can use the command 'n'est, and go back in the debug nesting using the 'b'ack command.
With the space the current instruction under debubbing is executed, and with 'c' the execution continues until a key is pressed.
In assembler, instruction by instruction is always executed, following the thread of execution.
The debug is based on the trigger of the Timer5 that interrupts the execution, and is installed through the method provided by "[i ... i] ;i" to start executing forth from the interrupt. The interrupt code 'dbgirq' changes the return address of the interrupt to the forth-word 'dbgstep' which processes the 'menu' and debug screen outputs, to finally push on the return-stack the original return address, and after resetting the timer emulate the return of the interrupt. For speed reasons, the word 'dbgirq' compares the breakpoints in use, or if we are debugging in assembler mode, and leaves it in a variable-flag, to avoid entering the debug forth menu again if it will be exited immediately.
The debug is executed on the forth itself, using the same data-stack as the forth that is being traced ('operator' task).
At first, it appears that the 'tick' timer could interact with the trace timer5 interrupt, so, pending analysis at another time, it is canceled during the debug.
There also appears to be a 'pause' related system corruption problem. Since 'pause' is called from rx1 ?, rx1, and tx1, and cannot be overridden, finally I choose to put some routines of 'rx1?', 'rx1.', and 'tx1.', which do not call pause, and point them in their corresponding key?, key, and emit. I have to study the implementation and operation of multi-tasking and 'pause'.
It is necessary to access the records saved in the interruption, to save and restore them before returning. Since the same data-stack is used, it is also necessary to save the byte above the pointer, since there are times when the forth primitives use the POSTDEC0-POSTINC0 instructions followed.
The words that process the interrupt and the entry in the debug process, seen from the disassembler itself, are as follows:
I repeat the second of the 'post', to give the text of the terminal a monospace format.
The 'see' of forth is complex of programing since this forth is direct-threading or rather subroutine-threaded code, with in-line expansion. In this way a call to a forth word can be compiled as a 'call', a 'goto', or correspond to a serie of inline cpu instructions.
As for the low-level disassembler, I found it important to give the option to interpret the ram bank in use, and present the symbolic name of the SFR, as well as the name of the routine (forth-word) called for each call or each goto.
The names of some SFRs are in a table of constants, to be used by the disassembler and also the assembler.
The names of the cpu instructions are in a table of the disassembler, which in the future could be grouped with the assembler, to take up less space on the flashrom.
Disassembly is done with forth words to be called for each instruction to see (which will use the debug) or by blocks of instrucctions to see from the 'forth' console.
see ( - | word ) see word code on a line
seel ( - | word ) see word code by lines
seea ( - | word ) see word on assembler
(.uasm) ( addr – addr' ) print instruction, returns address to next
disassembly variables are updated
(.fw) ( addr – addr' ) print a word, returns address to next word
disassembly variables are updated
As an example (copied from the window of a serial terminal ):
Hello
I have long wanted to start studying and testing FlashForth.
I prepared a board with a PIC18F26K22 and flash it with a FF-5 to it, but it stayed pending, and finally at the end of last March I finally started his study.
First of all, my thanks and acknowledgment to Mikael Nordman for such a great job.
Once I studied how it works, I thought about implementing an application written in flash-forth.
I missed a high level and low level disassembler, to check how the code looks, as well as a forth debugger to detect problems of programnig.
I have started to implement them.
This work has been developed for PIC18.
I would like to provide the code.
I'm looking at how to make a new wiki topic.
Hi Pablo.
There should be a create page button on the left side of the wiki.
You need to be logged into sourceforge to see it.
Did you notice that the word see already exists in flashforth ?
Maybe you want a better or different one than this one ?
https://sourceforge.net/p/flashforth/code/ci/master/tree/pic18/forth/see.txt
The 'see' of forth is complex of programing since this forth is direct-threading or rather subroutine-threaded code, with in-line expansion. In this way a call to a forth word can be compiled as a 'call', a 'goto', or correspond to a serie of inline cpu instructions.
As for the low-level disassembler, I found it important to give the option to interpret the ram bank in use, and present the symbolic name of the SFR, as well as the name of the routine (forth-word) called for each call or each goto.
The names of some SFRs are in a table of constants, to be used by the disassembler and also the assembler.
The names of the cpu instructions are in a table of the disassembler, which in the future could be grouped with the assembler, to take up less space on the flashrom.
Disassembly is done with forth words to be called for each instruction to see (which will use the debug) or by blocks of instrucctions to see from the 'forth' console.
see ( - | word ) see word code on a line
seel ( - | word ) see word code by lines
seea ( - | word ) see word on assembler
(.uasm) ( addr – addr' ) print instruction, returns address to next
disassembly variables are updated
(.fw) ( addr – addr' ) print a word, returns address to next word
disassembly variables are updated
As an example (copied from the window of a serial terminal ):
ok<#,ram>
seel within
UnDec: within
$10b2: over
$10b4: -
$10b6: >r
$10b8: -
$10ba: r>
$10bc: u< ;
ok<#,ram>
seea within
UnDec: within
$10b2: df35 over rcall,
$10b4: df88 - rcall,
$10b6: df44 >r rcall,
$10b8: df86 - rcall,
$10ba: df4f r> rcall,
$10bc: ef8b.f008 u< goto,
ok<#,ram>**
For a branched word:
ok<#,ram>
seel ss
UnDec: ss
$5fbc: (lit:$0012)
$5fc2: (0=?bra>$5fce)
$5fc8: dup
$5fcc: (bra>$5fd6)
$5fce: (lit:$3456)
$5fd6: (dup?bra<$5fd6)
$5fdc: drop
$5fe0: ;
ok<#,ram>
seea ss
UnDec: ss
$5fbc: 0e12 $12 movlw,
$5fbe: 6eec PREINC0 a, movwf,
$5fc0: 6aec PREINC0 a, clrf,
$5fc2: 50ed POSTDEC0 w, a, movf,
$5fc4: 10ed POSTDEC0 w, a, iorwf,
$5fc6: e103 $5fce bnz,
$5fc8: ecc4.f007 dup call,
$5fcc: d004 $5fd6 bra,
$5fce: 0e56 $56 movlw,
$5fd0: 6eec PREINC0 a, movwf,
$5fd2: 0e34 $34 movlw,
$5fd4: 6eec PREINC0 a, movwf,
$5fd6: 50ed POSTDEC0 w, a, movf,
$5fd8: 10ee POSTINC0 w, a, iorwf,
$5fda: e0fd $5fd6 bz,
$5fdc: 6eed POSTDEC0 a, movwf,
$5fde: 6eed POSTDEC0 a, movwf,
$5fe0: 0012 return,
ok<#,ram>**
To implement the debugger, the approach has been to start from the original FF, without modifying anything of the source, in such a way that compiling the forth code from forth it can be operative.
This does not take advantage of the debugging capabilities of the cpu.
In a later version it would be interesting to use the debugging capabilities, but this would imply including code for this purpose in the source file of the forth.
This implementation is made for 18FxxK22 and obviously has dependencies.
I have proposed a debug that executes forth words step by step and that also allows go to assembler, executing instruction to instruction.
The debugger is activated on a forth-word, like "debug -word-". Once in step-by-step execution, it supports instructions by means of a key, which are:
'a'sm 'b'ack 'c'ontinue 'd'ec 'f'orth 'n'est 'h'eaders 'q'uit he'x'
With 'a' it goes to assembler mode, following cpu instructions, and with 'f' it goes on forth words mode.
The forth mode presents the data-stack after executing the instruction.
The assembly mode presents after executing the instruction, the STATUS flags, the bank and the W register, and then the return-stack.
With 'x' and 'd' the presentation of the data-stack is changed to hexadecimal or decimal.
The step-by-step execution in forth is always inside the word that is being traced, to enter a level in the execution we can use the command 'n'est, and go back in the debug nesting using the 'b'ack command.
With the space the current instruction under debubbing is executed, and with 'c' the execution continues until a key is pressed.
In assembler, instruction by instruction is always executed, following the thread of execution.
The debug is based on the trigger of the Timer5 that interrupts the execution, and is installed through the method provided by "[i ... i] ;i" to start executing forth from the interrupt. The interrupt code 'dbgirq' changes the return address of the interrupt to the forth-word 'dbgstep' which processes the 'menu' and debug screen outputs, to finally push on the return-stack the original return address, and after resetting the timer emulate the return of the interrupt. For speed reasons, the word 'dbgirq' compares the breakpoints in use, or if we are debugging in assembler mode, and leaves it in a variable-flag, to avoid entering the debug forth menu again if it will be exited immediately.
The debug is executed on the forth itself, using the same data-stack as the forth that is being traced ('operator' task).
At first, it appears that the 'tick' timer could interact with the trace timer5 interrupt, so, pending analysis at another time, it is canceled during the debug.
There also appears to be a 'pause' related system corruption problem. Since 'pause' is called from rx1 ?, rx1, and tx1, and cannot be overridden, finally I choose to put some routines of 'rx1?', 'rx1.', and 'tx1.', which do not call pause, and point them in their corresponding key?, key, and emit. I have to study the implementation and operation of multi-tasking and 'pause'.
It is necessary to access the records saved in the interruption, to save and restore them before returning. Since the same data-stack is used, it is also necessary to save the byte above the pointer, since there are times when the forth primitives use the POSTDEC0-POSTINC0 instructions followed.
The words that process the interrupt and the entry in the debug process, seen from the disassembler itself, are as follows:
I repeat the second of the 'post', to give the text of the terminal a monospace format.
The 'see' of forth is complex of programing since this forth is direct-threading or rather subroutine-threaded code, with in-line expansion. In this way a call to a forth word can be compiled as a 'call', a 'goto', or correspond to a serie of inline cpu instructions.
As for the low-level disassembler, I found it important to give the option to interpret the ram bank in use, and present the symbolic name of the SFR, as well as the name of the routine (forth-word) called for each call or each goto.
The names of some SFRs are in a table of constants, to be used by the disassembler and also the assembler.
The names of the cpu instructions are in a table of the disassembler, which in the future could be grouped with the assembler, to take up less space on the flashrom.
Disassembly is done with forth words to be called for each instruction to see (which will use the debug) or by blocks of instrucctions to see from the 'forth' console.
see ( - | word ) see word code on a line
seel ( - | word ) see word code by lines
seea ( - | word ) see word on assembler
(.uasm) ( addr – addr' ) print instruction, returns address to next
disassembly variables are updated
(.fw) ( addr – addr' ) print a word, returns address to next word
disassembly variables are updated
As an example (copied from the window of a serial terminal ):
For a branched word: