Hello Tristan,
thanks for your message.
My below answers/comments only regard AVR8. I have currently no
idea, how this is similar or different in the other 3 targets.
> I revisited "Redirecting emit from within a task in AmForth",
> as I still like the idea of having a self contained task that can
> perform its own io, but without having to write my own version of
> pictured numeric output.
It sure would be nice, if this worked without a hitch. Agreed!
> It turned out that redirecting emit was not the problem. The xt for
> the new emit was correctly being stored in the task's user area
> (user+14) and was being called correctly by emit within the task. What
> I had not appreciated at the time was that (user+12) which holds the
> task's base value is zero by default.
A base of value '0' is not good. However, it seems a little more
convoluted:
The USER area is filled from a snippet stored in EEPROM. The
EEPROM values are defined in "avr8/amforth-eeprom.inc". In trunk
the relevant snippet looks like this:
> | ; default user area
> | EE_INITUSER:
> | .dw 0 ; USER_STATE
> | .dw 0 ; USER_FOLLOWER
> | .dw rstackstart ; USER_RP
> | .dw stackstart ; USER_SP0
> | .dw stackstart ; USER_SP
> |
> | .dw 0 ; USER_HANDLER
> | .dw 10 ; USER_BASE
> |
> | .dw XT_TX ; USER_EMIT
> | .dw XT_TXQ ; USER_EMITQ
> | .dw XT_RX ; USER_KEY
> | .dw XT_RXQ ; USER_KEYQ
> | .dw XT_SOURCETIB ; USER_SOURCE
> | .dw 0; USER_G_IN
> | .dw XT_REFILLTIB ; USER_REFILL
> | .dw XT_DEFAULT_PROMPTOK
> | .dw XT_DEFAULT_PROMPTERROR
> | .dw XT_DEFAULT_PROMPTREADY
> | .dw XT_DEFAULT_PROMPTINPUT
So base is set to #10. When setting up a user area, these values
are copied over. If you end up with the value zero in USER_BASE,
it either was overwritten afterwards, or it wasn't copied
correctly to begin with. For that I need to investigate, how
exactly a task area is setup. And propably read a lot of
documentation along the way :-)
> This meant that after . or u. ,
> emit was never called as the mcu had crashed in the pictured numeric
> output routines (in #s I think, though it is # that fetches base) which
> use base.
>
> Ironically, to establish this I did end up re-writing versions of the
> pictured numeric output routines in Forth so that they wrote to part
> of an extended task user area - so providing task specific pad and
> numeric picture buffers that I could be (more) sure were not being
> modified elsewhere. When this still crashed the mcu, I re-read
>
> http://amforth.sourceforge.net/TG/Architecture.html?highlight=user
> http://amforth.sourceforge.net/TG/recipes/Multitasking.html
>
> and I realised that I was responsible for providing a newly created
> task with more than just an xt for emit. task-init only does so much.
> Once 10 was written to the task's base location (user+12), my versions
> of . u. wrote correctly to the task's local buffers and the redirected
> emit was called by type (from my numeric picture routines). AmForth's
> . and u. also wrote correctly to the (shared) numeric picture buffer below
> the (shared) pad.
>
> http://amforth.sourceforge.net/TG/recipes/Multitasking.html
This piece of documentation was written by me a long time ago.
It does need some brush up.
Now back to your original problem. I rephrase: "Wouldn't it be
nice if I have one or more background tasks running along and
printing their output as they go --- independantly of each
other"?
I think, it would. Now, what can we do about it? What is /the/
problem? One problem I mentioned is that the HOLD area (the
place where pictured output is stored before emitting it) is
shared between all tasks, as of this time[1]. A similar problem
occurs, if more than one task print to the same output,
character by character: we probably end up with a little mess.
Sometimes this is not a problem, other times it is.
Option 1: create a semaphore to ensure, that only one task is
accessing HOLD, until it's finished. I was convinced there is an
example in the cookbook. But there isn't. What I found is this:
> | common/lib/multitask-semaphore.frt
> | common/lib/multitask-messages.frt
That can serve as inspiration.
Option 2: create a separate hold area for each task.
Well. It surely can be done, and others have surely done so. I
need to spend some time on the exact layout of the RAM space.
Having said that I feel inclined to add another: "Wouldn't it be
nice, if I could run a second commandline task (quit) on an
existing second serial connection (thing atmega644pa or
similar)"? Thus effectively creating a *Two User AmForth on one
AtMega644pa*? Actually I do have a use case for this. And I have
started to implement something in small steps[2]:
- add a second interrupt service routine on incoming data on
that second serial interface.
solved.
- add a second input ring buffer (below rx/key/key?)
solved.
- add a second set of rx/key/key? tx/emit/emit?