Re: [Amforth] Multitasking/emit/hold (was: Redirect EMIT from within a task)

2020-04-28 Thread Erich Wälde
Hello Tristan,


Tristan Williams writes:

> Hello Erich,
>
> Within task-init from multitask.frt I think a task's entire tcb/user
> area is filled with zeros and then only the values from the task's
> (flash) tib are copied across to the task's tcb/user area. A value for
> BASE is not stored within the tib. Only sp0, sp0-- and rp0 are stored
> in the task's tib.   
>
> : tib>tcb  ( tib -- tcb )  @i ;
> : tib>rp0  ( tib -- rp0 )  i-cell+ @i ;
> : tib>sp0  ( tib -- sp0 )  i-cell+ i-cell+ @i ;
> : tib>size ( tib -- size )
>   dup tib>tcb swap tib>sp0 1+ swap -
> ;
>
> : task-init ( tib -- )
>   dup tib>tcb over tib>size  0 fill \ clear RAM for tcb and stacks
>   dup tib>sp0 over tib>tcb #6 + !   \ store sp0in tcb[6]
>   dup tib>sp0 cell- over tib>tcb #8 + ! \ store sp0--  in tcb[8], tos
>   dup tib>rp0 over tib>tcb #4 + !   \ store rp0in tcb[4]
>   tib>tcb task-sleep\ store 'pass' in tcb[0]
> ;

You have clearly spend more time on this, I see! Populating base
won't be difficult, but I wonder what other candidates are
there.

>
> I believe the interpreter user area is fully populated from eeprom
> at boot time, but all other tasks rely on the programmer to fill in
> what is relevant to their tasks. I did not appreciate that included a
> value for BASE, but I do now.

That's what I had in mind.
COLD avr8/words/cold.asm does jump to PFA_WARM.
WARM common/words/warm.asm does call XT_INIT_RAM
init-ram avr8/words/init-ram.asm does the copy loop
> | XT_INIT_RAM:
> |   .dw DO_COLON
> | PFA_INI_RAM:  ; ( -- )
> | .dw XT_DOLITERAL
> | .dw EE_INITUSER
> | .dw XT_UP_FETCH
> | .dw XT_DOLITERAL
> | .dw SYSUSERSIZE
> | .dw XT_2SLASH
> | .dw XT_EE2RAM
> | .dw XT_EXIT
something like "  eeinituser up@ sysusersize 2/ ee>ram "
where " : ee>ram   0 do over @e over ! cell+ swap loop 2drop ; "
no garantees. But there is ee>ram, which could be called in
task-init, too, before storing sp0 rp0 ...


>
>> 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]:
>
> Would the two users have separate dictionaries?
Good question! I haven't really thought about that.
But I had in mind to prepend a new (limited) dictionary for that
second serial connection, in order to make it deal correctly
with the incoming data (well data wrapped in forth syntax).


Thank you for your input.
Cheers,
Erich


-- 
May the Forth be with you ...


___
Amforth-devel mailing list for http://amforth.sf.net/
Amforth-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/amforth-devel


Re: [Amforth] Multitasking/emit/hold (was: Redirect EMIT from within a task)

2020-04-28 Thread Tristan Williams
Hello Erich,

Within task-init from multitask.frt I think a task's entire tcb/user
area is filled with zeros and then only the values from the task's
(flash) tib are copied across to the task's tcb/user area. A value for
BASE is not stored within the tib. Only sp0, sp0-- and rp0 are stored
in the task's tib.   

: tib>tcb  ( tib -- tcb )  @i ;
: tib>rp0  ( tib -- rp0 )  i-cell+ @i ;
: tib>sp0  ( tib -- sp0 )  i-cell+ i-cell+ @i ;
: tib>size ( tib -- size )
  dup tib>tcb swap tib>sp0 1+ swap -
;

: task-init ( tib -- )
  dup tib>tcb over tib>size  0 fill \ clear RAM for tcb and stacks
  dup tib>sp0 over tib>tcb #6 + !   \ store sp0in tcb[6]
  dup tib>sp0 cell- over tib>tcb #8 + ! \ store sp0--  in tcb[8], tos
  dup tib>rp0 over tib>tcb #4 + !   \ store rp0in tcb[4]
  tib>tcb task-sleep\ store 'pass' in tcb[0]
;

I believe the interpreter user area is fully populated from eeprom
at boot time, but all other tasks rely on the programmer to fill in
what is relevant to their tasks. I did not appreciate that included a
value for BASE, but I do now. 

> 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]:

Would the two users have separate dictionaries? 

kind regards,
Tristan




___
Amforth-devel mailing list for http://amforth.sf.net/
Amforth-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/amforth-devel


[Amforth] Multitasking/emit/hold (was: Redirect EMIT from within a task)

2020-04-28 Thread Erich Wälde


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?