Persistent Jump Table¶
Date: | 2018-11-11 |
---|
Intro¶
The cookbook section holds an explanation, how persistent Jump tables can be constructed.
The table used in the inner workings of the DCF clock has the following features:
- there are #60 entries, some unused
- the functions called will consume one item from the stack
- the default action should then be
drop
rather thannoop
- the stored functions are accessed exclusively through the table, their name is not needed. So the will be defined using
noname:
Creating the RAM table¶
First we create the temporary RAM table by simply alloting 60 cells:
\ create temporary RAM table
variable dcf.tmp.table #60 cells allot
Then we add the XT of drop
as default:
' drop dcf.tmp.table #60 ramtable.init
At this point we have a valid RAM table, allthough it will not lead to much useful action as is.
To simplify the code generating the table, we add a short hand to
store a given XT
at position idx
in the RAM table just defined.
: >rt ( xt idx -- ) dcf.tmp.table >ramtable ;
Creating noname: functions, storing their XTs in the RAM table¶
Just for the sake of the argument we define a word, which is lighting up an LED, if the value on the stack is non-zero.
:noname ( x -- )
if ( not zero ) led.0 on
else ( zero ) led.0 off
then
; #31 >rt
This function is then added at index #31
into the RAM table.
Whatever the behaviour of the newly defined function, all we know is
that :noname
will leave the XT on the stack, and >rt
will pick
that (and the index) up and place the XT in the RAM table at index
#31
.
Please Note: There should be no allocation of RAM space during this stage. All needed variables must be defined before alloting the temporary table. Beware of defining words! If we can stick to this rule, we can sort of release the RAM afterwards.
In the code this section is much longer of course. We will see more details in section Reading a dcf77 receiver.
Preserve the precious new content¶
After defining all the needed words and filling the RAM table, we want to preserve the precious new content.
dcf.tmp.table #60 >flashtable cmd_map
This will define a new word cmd_map
, which will leave the address
of its parameter section on the stack, just like an ordinary variable.
The parameter section will hold the saved content.
Release the space of the temporary RAM table¶
If we got this far, and if we did not allocate any RAM space after
the temporary RAM table, the we can release it by boldly resetting the
here
pointer
dcf.tmp.table to here
If funny, bad, or inexplicable things happen while running your code, disable this step and see, if it changes the behaviour. Just in bloody case.
Using the preserved table at last¶
The particular jump table in this case is used to call the correct function after a second has passed. It will get the value of the received DCF Bit and deal with it according to its position in the telegram.
Using the above table is a matter of fetch and execute:
: pos.cmd ( index -- )
dup 0 #60 within if
( position ) cmd_map + @i execute
else
drop
then
;
Somewhere in your code you will add the value to be consumed onto the
stack, add the index into the jump table on top and call pos.cmd
.
Putting it all together¶
The code lines give above are bracketing the lengthy section of code, which defines all the functions needed to handle a DCF77 telegram.
\ create temporary RAM table
variable dcf.tmp.table #60 cells allot \ only temporary really!
\ fill RAM table with ' drop \ noop -> drop: remove argument!
' drop dcf.tmp.table #60 ramtable.init
\ dcf.tmp.table #60 ramtable.dump \ DEBUG
: >rt ( xt idx -- ) dcf.tmp.table >ramtable ;
\ code snippet XTs to ram table
\ structure of functions
\ :noname ( 0|1 -- )
\ if ( bit:1 ) ...
\ else ( bit:0 ) ...
\ then ( always ) ...
\ ; #idx >rt
\ :noname
\ drop ( always ) ...
\ ; #idx >rt
\ #0 always 0
:noname
\ ...
; #0 >rt
\ ... more definitions here ...
:noname
\ ...
; #58 >rt
\ dcf.tmp.table #60 ramtable.dump \ DEBUG
\ copy RAM table to FLASH
dcf.tmp.table #60 >flashtable pos_cmd_map
\ release RAM
\ WARNING: there might be dragons around!
\ Iff so, disable the next line
Dcf.tmp.table to here
: pos.cmd ( index -- )
dup 0 #60 within if
( position ) pos_cmd_map + @i execute
else
drop
then
;