Shop OBEX P1 Docs P2 Docs Learn Events
TAQOZ Reloaded - SWITCH statement cannot be run by more than one cog — Parallax Forums

TAQOZ Reloaded - SWITCH statement cannot be run by more than one cog

bob_g4bbybob_g4bby Posts: 401
edited 2022-05-12 09:47 in Forth

In the Taqoz source code, I've been trying to fix a problem caused by long 'uswitch' being located in Hub memory, rather than where it should be in COG memory. If two or more COGS attempt to use a SWITCH statement simultaneously, then a race condition exists on the value stored at 'uswitch' and one or other SWITCH constructs will misbehave.

I'm looking for help to fix this as my knowledge of Taqoz source code and assembly language is limited. Here's what I've tried - assembling using flexprop 5.9.9 using this source code.

I add a new long 'cswitch' to COG memory:-

txpin       long    tx_pin

pinreg      long    0       ' PIN  - access via PIN operation'
cswitch     long    0       ' storage for the SWITCH selection

ACC     long    0       ' accumulator register cleared to zero before instruction'
x       long    0

I substitute for words _SWITCH and SWFETCH:-

' ************** CASE STATEMENTS *********************8
' SWITCH ( val -- )
_SWITCH word    rg+uswitch,STOREX+ex

' SWITCH@ ( -- val )
SWFETCH word    rg+uswitch,FETCHX+ex      ' Peter's original words

_SWITCH word cswitch,STOREX+ex

SWFETCH word cswitch,FETCHX+ex               ' New words cause Taqoz boot to fail or other hiccups

I've tried a number of different phrases but haven't hit on the right one over several days. the problem could do with a fresh pair of eyes!


  • Christof Eb.Christof Eb. Posts: 1,100
    edited 2022-05-13 08:01

    Hi Bob,
    I had a look into this now.

    Are you really sure, that switch does not work properly????

    As far as I understand this, uswitch resides at offset $01c+regptr of a "register area" in hub ram, at $200....$3ff.
    regptr is a cog resident pointer, which points to the register area of this cog. So it is intended and possible to let each cog have it's own "private register area".
    What I did not find, is the startup code of each cog, which would set regptr to different hub locations for each cog. There is some code that seems to reset the contents of the first 8? register variables depending on the cogid.
    Line 5140:
    word ATID,_8,ERASE ' clear this cog's task registers

    Line 5170:
    ' initialize task registers
    ' free memory backup
    word rg+0,w+$100,ERASE ' init task registers'

    Peter has used the wording "tasks" sometimes instead of cog. (?)
    Perhaps Peter wanted to be open to introduce several tasks per cog.

    I don't think, that it is a good idea to introduce new cog register variables in cog memory, because this will shift everything in the precious coq memory space!!! It will change codes of cog code and so on. Some things are hardcoded in this source code like erasing exactly 8 memory locations in the code above.

    Instead you already have introduced LUT variables, so if the original idea of Peter to separate the registers via regptr really does not work, I would strongly recommend to use a position in LUT for this!!!!
    I would also recommend to just define new versions of switch and case and not alter the original source code, because it seems to be rather hard to understand everything of it, at least for me.

    To your original question how to access cog memory directly:
    Have you tried something like:

    SWFETCH word w+cswitch,COGFETCH+ex

    But as said, do only alter cog ram, if you really know what you are doing.....

  • OK, I verified, different cogs do really use the same hub location for uswitch, so regptr is not initalised properly. I don't know what other effects will this have, because it means that all of these "user variables" are shared too. At least all printing will be affected, because BASE is global then too.

  • Hi @"Christof Eb." , thanks for looking into this. I had a skype call with Peter Jakacki this morning and he confirms that uswitch should be a cog ram variable, not hub ram. He is going to change it in a future release.

    As it stands, the details of running TAQOZ on more than one cog at the same time is not well documented - today I'm adding what I've learned in the glossary., which I'll reissue soon at v61.

    Cheers Bob

  • bob_g4bbybob_g4bby Posts: 401
    edited 2022-05-13 19:47

    Peter Jakacki could tell me in the source code:-

    'regptr' (located in COG ram) contains the start address of a block of Hub Variables. These are the variables headed 'variables.p2a'. On switch on, COG 0 sets 'regptr' = $200. So 'temp' is at $200+0, 'uemit' at $200+32 and so on. Let's dump it:-

    TAQOZ# $200 100 DUMP ---
    00200: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
    00210: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
    00220: 00 00 00 00  00 00 0A 0A  00 00 00 00  23 00 00 00     '............#...'
    00230: 00 00 00 04  44 55 4D 50  00 00 00 00  00 00 00 00     '....DUMP........'
    00240: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
    00250: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
    00260: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................' ok

    So at $200+38 is stored 0A 0A, the current number base, stored in variable 'base'.

    The preferred way of reading the Hub Variables is by using REG. e.g. the current number base is 38 REG C@ .B

    If we start another cog running Taqoz by using RUN, RUN: etc. we may need it to set up a new Hub Variable block for itself to avoid race conditions like we currently have with uswitch.

    We can do that by getting the new COG to:-
    1. Copy the COG 0 Hub Variables to a new hub location
    2. Setting regptr to point to the new hub location

    The new cog would have to execute something like:-

    177     :=  HVBsize                     --- Hub Variable Block size to store variable 'temp' up to variable 'ufind'
    pub regptr! 1 COG! ;    ( adr -- )      --- store adr at this cog's regptr
    pub !HVB    ( adr -- )                   --- set up this COGs Hub Variable Block at adr
        0 REG OVER HVBsize CMOVE            --- copy the values of the current block to the new one
        regptr!                             --- regptr now points to the new block
    HVBsize bytes MYHUBVARS                  --- create a space for the new Hub Variable Block  
    MYHUBVARS !HVB                           --- initialise the variables from the old block and set regptr to the start of the new block

    On the other hand, if all you want the new COG to do is read smartpins and read/write from hub ram, then a new Hub Variable Block may not be needed.
    Sadly all a bit messy - e.g. it's not easy for the programmer to determine when a new block is needed.

  • Christof Eb.Christof Eb. Posts: 1,100
    edited 2023-11-18 09:06

    Hi, I have now found, that there is a rather simple way to patch the words SWITCH and CASE@ so that they now use a variable in LUT. Taqoz will then use the new words. And as LUT is private to each cog, SWITCH can then be used in parallel.

    lutOrg @ := switchVar lutOrg -- \ reserve space in LUT
    : switchNew ( value -- )
       switchVar lut!
    ' switchNew 1+ ' SWITCH W! \ patch into SWITCH
    : case@New ( -- value )
       switchVar lut@
    ' case@New 1+ ' CASE@ W! \ patch into CASE@
    pub CASETEST ( val -- )
          1 CASE ." one" BREAK
          2 CASE ." two" BREAK
          3 CASE ." three" BREAK
          4 10 <CASE> ." between four and ten" BREAK
          ." default"
  • @"Christof Eb."
    That works well, good solution! May I put your patch in the glossary in the BRANCHING section?
    Cheers, Bob

  • @bob_g4bby said:
    @"Christof Eb."
    That works well, good solution! May I put your patch in the glossary in the BRANCHING section?
    Cheers, Bob

    Yes, Your glossary is the the best place to find such things.
    Cheers, Christof

Sign In or Register to comment.