Shop Learn
TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++ - Page 51 — Parallax Forums

TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++

14849515354109

Comments

  • MJBMJB Posts: 1,200
    edited 2014-06-28 23:43
    artkennedy wrote: »
    I was so used to having only one or two characters to indicate comments that I hadn't noticed that ( would do it. I was using a \ before the ( . I can see now that seeing ( and not \ ( was confusing me. That's cleared up.

    Here's another.
    From the kernel:
    { quick test
    pub TC ( ch -- )
         CASE
        "4" =[ ." Knock on the door, it's a 4" ]=
        "5" =[ ." Let's jive, it's a 5" ]=
        "7" "9" ..[ ." Pick up sticks, it's more than six" ]=
    ;
    }
    
    Can't determine what =[ and ]= do. Also ..[
    I know the whole clip is a comment but I don't what's going on there. Help?


    looks like an old version of CASE now changed to more C-like
    SWITCH CASE -> see pub CASEDEMO

    I have the whole TACHYON files - Kernel + EXTEND + ... all extensions in NOTEPAD++ and then just do a search-all-files ...
    this reveals immediately what's going on ... and =[ are only in this single place
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-06-29 05:20
    artkennedy wrote: »
    I was so used to having only one or two characters to indicate comments that I hadn't noticed that ( would do it. I was using a \ before the ( . I can see now that seeing ( and not \ ( was confusing me. That's cleared up.

    Here's another.
    From the kernel:
    { quick test
    pub TC ( ch -- )
         CASE
        "4" =[ ." Knock on the door, it's a 4" ]=
        "5" =[ ." Let's jive, it's a 5" ]=
        "7" "9" ..[ ." Pick up sticks, it's more than six" ]=
    ;
    }
    
    Can't determine what =[ and ]= do. Also ..[
    I know the whole clip is a comment but I don't what's going on there. Help?

    I will have to track those outdated examples and bring them up-to-date. As MJB mentioned the newer method is more C like using SWITCH and CASE BREAK statements etc. I will look at updating that in the document but I'm also happy to provide examples of use as well, just let me know.
  • artkennedyartkennedy Posts: 168
    edited 2014-06-29 09:52
    I did not know about NOTEPAD++. I have just downloaded and will check it out. I have used The Semware Editor ( tsepro ) *forever* and love it. I have been keeping copies of the kernel and EXTEND loaded and switching to search. Sounds like combining for searching might be worth trying.

    I was trying to get a handle on the CASE structure and got flummoxed by the old example. Think I've got it now. Just had to realize that the structure does not need an explicit closing term.
    MJB wrote: »
    looks like an old version of CASE now changed to more C-like
    SWITCH CASE -> see pub CASEDEMO

    I have the whole TACHYON files - Kernel + EXTEND + ... all extensions in NOTEPAD++ and then just do a search-all-files ...
    this reveals immediately what's going on ... and =[ are only in this single place
  • artkennedyartkennedy Posts: 168
    edited 2014-06-29 11:04
    Oh! I just noticed in QWORDS. \\\ *** --- ... These are defined words. Duh,oh!
    But you missed some too :)
    I use the --- a lot since it allows me to space out a comment --- --- --- --- out to where I want it --- just so forum BB code doesn't gobble up whitespace plus --- does not clutter or confuse reading code like 1405 7 / \ is confusing
    There's also \\\ and *** but I use that mainly to disable lines of code and to distinguish this from a real comment although they work the same way.
  • artkennedyartkennedy Posts: 168
    edited 2014-06-29 12:03
    I was thinking I had the CASE structure whipped. Wrong!

    Why does this work:
    FORGET TEST
    : TEST     \ press keys 1-9 to trigger sensor n repeated reading.
                   \ when reading in progress press <esc> to return to sensor selection
                   \ when in selection press <esc> to quit
       SWITCH
       "1" "9" SWITCH>< IF SWITCH@ CR EMIT BREAK
       $1B CASE CR BREAK
    ;
    
    
    : DOTEST
       BEGIN
          KEY UPPER TEST
          SWITCH@ $1B =
       UNTIL
    ;
    SC DOTEST
    
    And this does not:
    FORGET TEST
    : TEST     \ press keys 1-9 to trigger sensor n repeated reading.
                   \ when reading in progress press <esc> to return to sensor selection
                   \ when in selection press <esc> to quit
       BEGIN
          KEY UPPER
          SWITCH
          "1" "9" SWITCH>< IF SWITCH@ CR EMIT BREAK
          $1B CASE CR BREAK
          SWITCH@ $1B =
       UNTIL
    ;
    SC TEST
    
    I think it has something to do with what BREAK does to the stack but I can't scope it.
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-06-29 17:54
    artkennedy wrote: »
    I was thinking I had the CASE structure whipped. Wrong!

    Why does this work:
    FORGET TEST
    : TEST     \ press keys 1-9 to trigger sensor n repeated reading.
                   \ when reading in progress press <esc> to return to sensor selection
                   \ when in selection press <esc> to quit
       SWITCH
       "1" "9" SWITCH>< IF SWITCH@ CR EMIT BREAK
       $1B CASE CR BREAK
    ;
    
    
    : DOTEST
       BEGIN
          KEY UPPER TEST
          SWITCH@ $1B =
       UNTIL
    ;
    SC DOTEST
    
    And this does not:
    FORGET TEST
    : TEST     \ press keys 1-9 to trigger sensor n repeated reading.
                   \ when reading in progress press <esc> to return to sensor selection
                   \ when in selection press <esc> to quit
       BEGIN
          KEY UPPER
          SWITCH
          "1" "9" SWITCH>< IF SWITCH@ CR EMIT BREAK
          $1B CASE CR BREAK
          SWITCH@ $1B =
       UNTIL
    ;
    SC TEST
    
    I think it has something to do with what BREAK does to the stack but I can't scope it.

    Good work, yYou are doing well in playing with it to see what it does and doesn't do. If you have a look at the source code you will find that BREAK compiles an EXIT THEN because CASE compiles an = IF so that makes sense. The limitation with this method is of course that when a CASE is taken is that it will EXIT the definition on BREAK so it won't execute any more code in the definition after that, your loop will be broken. This is not normally a problem but it pays to know the limitation.

    I suppose that I could define an OTHERWISE ..... ENDCASE where all the BREAKs could know where to jump to but that seems an unnecessary complication as I like to keep the structure open and flexible.
  • artkennedyartkennedy Posts: 168
    edited 2014-06-29 23:28
    Thanks. Okay, thought it was something like that. I was getting what I could from the source. Wasn't sure what an EXIT does. Yeah, I like to wring the juice out of things that are new to me so I know what to expect.
  • MJBMJB Posts: 1,200
    edited 2014-06-30 08:39
    artkennedy wrote: »
    Wasn't sure what an EXIT does.
    "search all files" will become your best friend ... ;-)
  • MJBMJB Posts: 1,200
    edited 2014-07-09 12:54
    Hi Peter,

    in working on the webserver -
    the lastest EASYNET is not working any more with the W5100 / Spinneret
    I spottet the new virtual memory functions as the problem and try to adapt
    the W5100.FTH - but I seem to miss s.th.
    the request comes in - but no result page back

    you surely see quickly, what's missing
    thanks,
    Markus
  • MJBMJB Posts: 1,200
    edited 2014-07-15 01:12
    Hi Peter,

    still struggling
    I traced the problem down to DIR works, but cat <filename> gives 'not found'

    with spinneret and latest google doc files up to EASYFILE

    I had this SD card working before but made changes to content, so decided to reformat to have clean unfragmented image.
    I did this with windows format ...
    D.P. reminded me of your post to use the SDFORMATTER tool.
    so I did this, copied the files back - looks ok from windows ...
    but on spinneret I get this very strange behavior

    this explains, why the webserver and FTP do not show the file contents ...

    what can I do?
    thanks, Markus

    here the output
    Media mounted as 5957.3321          NO NAME     FAT32    Cluster size = 2,768   Sectors = 3,600
     not found
      ok
    
    Cluster size and Sectors look very strange for a 4GB card
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-15 07:38
    MJB wrote: »
    Hi Peter,

    still struggling
    I traced the problem down to DIR works, but cat <filename> gives 'not found'

    with spinneret and latest google doc files up to EASYFILE

    I had this SD card working before but made changes to content, so decided to reformat to have clean unfragmented image.
    I did this with windows format ...
    D.P. reminded me of your post to use the SDFORMATTER tool.
    so I did this, copied the files back - looks ok from windows ...
    but on spinneret I get this very strange behavior

    this explains, why the webserver and FTP do not show the file contents ...

    what can I do?
    thanks, Markus

    here the output
    Media mounted as 5957.3321          NO NAME     FAT32    Cluster size = 2,768   Sectors = 3,600
     not found
      ok
    
    Cluster size and Sectors look very strange for a 4GB card

    I meant to have a look at it a while ago but just tried it now and it did the same thing. What I noticed was that it was remounting each time and basically wiping the request. Turned out to be a single line in MOUNT that have been \\\ commented out for some memory optimization but still had to set the mount flag. Fixed it up and it's fine now.

    BTW, if you load EPRINT.fth before SDCARD then it will save at least 2K of hub RAM by storing all the print strings in upper EEPROM.
  • MJBMJB Posts: 1,200
    edited 2014-07-15 11:10
    I meant to have a look at it a while ago but just tried it now and it did the same thing. What I noticed was that it was remounting each time and basically wiping the request. Turned out to be a single line in MOUNT that have been \\\ commented out for some memory optimization but still had to set the mount flag. Fixed it up and it's fine now.

    BTW, if you load EPRINT.fth before SDCARD then it will save at least 2K of hub RAM by storing all the print strings in upper EEPROM.

    how little optimizations can have strange side effects ;-)

    OK works again - back to webserver development

    I had a look to see if EPRINT could be loaded earlier in sequence to also save part of the strings in EXTEND.
    This will be possible with my proposed restructuring of EXTEND.

    Thanks Peter, Markus
  • max72max72 Posts: 1,152
    edited 2014-07-15 15:11
    Just a quick line to say thank you.
    I have a MMA845x accelerometer and I decided to test it with Tachyon.
    That was easy!!
    At the moment I'll revert to spin for trig calculations (I already have all the trig calculations in spin..), but the interactive mode is extremely easy.
    It takes a little bit to get acquainted to it, but the sheer power of Tachyon is terrific.
    Thanks again,
    Massimo
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-15 16:06
    max72 wrote: »
    Just a quick line to say thank you.
    I have a MMA845x accelerometer and I decided to test it with Tachyon.
    That was easy!!
    At the moment I'll revert to spin for trig calculations (I already have all the trig calculations in spin..), but the interactive mode is extremely easy.
    It takes a little bit to get acquainted to it, but the sheer power of Tachyon is terrific.
    Thanks again,
    Massimo

    Thanks, but is that a little hint to graft in the FPU package?

    BTW, do you have that section of Spin code I could look at to make sure it's covered? (when I do integrate it that is :)
  • D.PD.P Posts: 790
    edited 2014-07-15 16:23
    Thanks, but is that a little hint to graft in the FPU package?

    BTW, do you have that section of Spin code I could look at to make sure it's covered? (when I do integrate it that is :)

    Yes that is a hint, I swear I see a hint in there :)
  • max72max72 Posts: 1,152
    edited 2014-07-16 03:24
    D.P wrote: »
    Yes that is a hint, I swear I see a hint in there :)

    :-)
    Not really..
    I realised I can do with neithe FPU or trig/cordic.. :-)
    That was just a post to say unconditionally thank you.. with no extra requests ;-)

    I'm using also the nokia LCD, and the code available is a nice help.

    I would like to convert my current relevant spin code to Tachyon... the data come in 2's complement so that would offer me the possibility to learn more.. :-)
    I'm using the accelerometer to get the height of a tree. I "look" at it at known distance, and I get back an approximate height.

    The key code is the following:
      repeat
          i2c.i2cstart
          k:=i2c.i2cwrite(accel_w)
          k:=i2c.i2cwrite(1)  
          i2c.i2cstart
          k:=i2c.i2cwrite(accel_r)
          accel_x:=i2c.i2cread(0)
          accel_x:=accel_x<<8
          accel_x:=accel_x+i2c.i2cread(0)
          accel_x:=accel_x<<16
          accel_y:=i2c.i2cread(0)
          accel_y:=accel_y<<8
          accel_y:=accel_y+i2c.i2cread(0)
          accel_y:=accel_y<<16
          accel_z:=i2c.i2cread(0)
          accel_z:=accel_z<<8
          accel_z:=accel_z+i2c.i2cread(1)
          accel_z:=accel_z<<16
          i2c.i2cstop
          accel_x:=accel_x~>14
          accel_y:=accel_y~>14
          accel_z:=accel_z~>14
          ||accel_z
          ||accel_y
          ||accel_x
          pst.char(13)
          pst.dec(accel_x)
          pst.char(" ")
          pst.dec(accel_y)
          pst.char(" ")
          pst.dec(accel_z)
          pst.char(" ")
          pst.str(string(" -> "))
          var1:=dist*accel_y/accel_z
          pst.dec(var1)
    [
    
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-16 06:32
    max72 wrote: »
    :-)
    Not really..
    I realised I can do with neithe FPU or trig/cordic.. :-)
    That was just a post to say unconditionally thank you.. with no extra requests ;-)

    I'm using also the nokia LCD, and the code available is a nice help.

    I would like to convert my current relevant spin code to Tachyon... the data come in 2's complement so that would offer me the possibility to learn more.. :-)
    I'm using the accelerometer to get the height of a tree. I "look" at it at known distance, and I get back an approximate height.

    The key code is the following:
      repeat
          i2c.i2cstart
          k:=i2c.i2cwrite(accel_w)
          k:=i2c.i2cwrite(1)  
          i2c.i2cstart
          k:=i2c.i2cwrite(accel_r)
          accel_x:=i2c.i2cread(0)
          accel_x:=accel_x<<8
          accel_x:=accel_x+i2c.i2cread(0)
          accel_x:=accel_x<<16
          accel_y:=i2c.i2cread(0)
          accel_y:=accel_y<<8
          accel_y:=accel_y+i2c.i2cread(0)
          accel_y:=accel_y<<16
          accel_z:=i2c.i2cread(0)
          accel_z:=accel_z<<8
          accel_z:=accel_z+i2c.i2cread(1)
          accel_z:=accel_z<<16
          i2c.i2cstop
          accel_x:=accel_x~>14
          accel_y:=accel_y~>14
          accel_z:=accel_z~>14
          ||accel_z
          ||accel_y
          ||accel_x
          pst.char(13)
          pst.dec(accel_x)
          pst.char(" ")
          pst.dec(accel_y)
          pst.char(" ")
          pst.dec(accel_z)
          pst.char(" ")
          pst.str(string(" -> "))
          var1:=dist*accel_y/accel_z
          pst.dec(var1)
    [
    

    Okay, I won't take the hint then :)

    Here is your code transposed with Forth for a nice side by side comparison and then at the end how you can code it. I noticed that I did not have the equivalent of a arithmetic right shift ~> and so I combined all those shifts and absolute ops into one definition and here is how it looks:
    [FONT=courier new] repeat                                                BEGIN
          i2c.i2cstart                                        I2CSTART
          k:=i2c.i2cwrite(accel_w)                            @accel I2C!                @accel is the 8-bit i2c address
          k:=i2c.i2cwrite(1)                                  1 I2C!
          i2c.i2cstart                                        I2CSTART
          k:=i2c.i2cwrite(accel_r)                            @accel 1+ I2C!                read address is always write address+1
          accel_x:=i2c.i2cread(0)                             0 I2C@
          accel_x:=accel_x<<8                                 8 SHL
          accel_x:=accel_x+i2c.i2cread(0)                     0 I2C@ +
          accel_x:=accel_x<<16                                16 SHL #14 ~> ABS        x - justify and sign extend then convert to abs        
          accel_y:=i2c.i2cread(0)                             0 I2C@
          accel_y:=accel_y<<8                                 8 SHL
          accel_y:=accel_y+i2c.i2cread(0)                     0 I2C@ +
          accel_y:=accel_y<<16                                16 SHL #14 ~> ABS        y
          accel_z:=i2c.i2cread(0)                             0 I2C@
          accel_z:=accel_z<<8                                 8 SHL
          accel_z:=accel_z+i2c.i2cread(1)                     1 I2C@ +
          accel_z:=accel_z<<16                                16 SHL #14 ~> ABS        z
          i2c.i2cstop                                         I2CSTOP
          accel_x:=accel_x~>14                                                        combined in previous ops
          accel_y:=accel_y~>14                
          accel_z:=accel_z~>14
          ||accel_z
          ||accel_y
          ||accel_x
          pst.char(13)                                        CR
          pst.dec(accel_x)                                    ROT .DEC
          pst.char(" ")                                       SPACE
                                                              2DUP                    keep a copy of y and z
          pst.dec(accel_y)                                    SWAP .DEC
          pst.char(" ")                                       SPACE
          pst.dec(accel_z)                                    .DEC
          pst.char(" ")                                       SPACE
          pst.str(string(" -> "))                             PRINT"  -> "
          var1:=dist*accel_y/accel_z                          / dist @ *              divide x by y on stack then multiply by dist variable
          pst.dec(var1)                                       .DEC
                                                            AGAIN
     
     \ Need to define an arithmetic shift right and though I am loathe to use a hint of PASM it happens to be the most efficient way
     \ However in this case we combine all the shifting and ABS in one operation
     
     : AFIX ( hb lb -- result )              SWAP B>W 16 SHL $38FF680E PASM DROP ABS ;
     
     \ Now we define the loop anew
     : DOIT
            BEGIN
              I2CSTART @accel I2C! 1 I2C!
              I2CSTART @accel 1+ I2C!
              ackI2C@ ackI2C@ AFIX                \ x adjusted
              ackI2C@ ackI2C@ AFIX                \ y adjusted
              ackI2C@ 1 I2C@ AFIX                 \ z adjusted
              I2CSTOP
              
              <CR> ROT .DEC SPACE 2DUP SWAP .DEC SPACE .DEC SPACE 
              PRINT"  -> " / dist @ * .DEC
            AGAIN
            ;
     
     [/FONT]
    
  • max72max72 Posts: 1,152
    edited 2014-07-16 09:22
    Thanks Peter!
    I'll give it a run tonight, and I'll try to digest it all :-)

    Just a question:
    I was thinking about combining the two bytes and testing bit 16 for the sign. Would it works too?
    After all I need to combine the two bytes, get the sign, ABS it, and have it less than say 16-18 bits.
    Maybe it's the right occasion to do some experiments :-)

    Massimo
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-16 17:51
    max72 wrote: »
    Thanks Peter!
    I'll give it a run tonight, and I'll try to digest it all :-)

    Just a question:
    I was thinking about combining the two bytes and testing bit 16 for the sign. Would it works too?
    After all I need to combine the two bytes, get the sign, ABS it, and have it less than say 16-18 bits.
    Maybe it's the right occasion to do some experiments :-)

    Massimo

    I'm not quite sure what result you are looking for but I just had a look at the datasheet and the raw data is 14-bit signed left justified so that the 2 lsbs are zeros. Why are you converting these to an absolute value? Surely you would want it signed?

    If raw value = $7FFC then this is the maximum positive value of 8191
    $FFFC = -1

    So just get the raw 16-bit word and shift it right 2 bits then test bit 13 to see if it's set and if it is then just subtract $4000 from it like this (assuming signed result though):

    : AFIX ( hb lb -- result ) SWAP B>W 2 SHR DUP $2000 AND IF $4000 - THEN ;

    \ test data by supplying max+ -1 max-
    $7F $FC AFIX . 8191 ok
    $FF $FC AFIX . -1 ok
    $80 $00 AFIX . -8192 ok

    An alternative AFIX using the signed shift right operator (implemented as a PASM opcode)
    : AFIX ( hb lb -- result ) SWAP B>W 16 SHL $38FF6812 PASM DROP ;


  • D.PD.P Posts: 790
    edited 2014-07-16 21:08
    max72 wrote: »
    Thanks Peter!
    I'll give it a run tonight, and I'll try to digest it all :-)

    Just a question:
    I was thinking about combining the two bytes and testing bit 16 for the sign. Would it works too?
    After all I need to combine the two bytes, get the sign, ABS it, and have it less than say 16-18 bits.
    Maybe it's the right occasion to do some experiments :-)

    Massimo
    : AFIX ( hb lb -- result )              SWAP B>W 16 SHL $28FF680E PASM DROP ABS ;
    
    Here they be dragons!
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-16 21:35
    D.P wrote: »
    : AFIX ( hb lb -- result )              SWAP B>W 16 SHL $28FF680E PASM DROP ABS ;
    
    Here they be dragons!

    Actually that should have been a $38FF680E hex dragon in this example!

    I'm actually allocating a new opcode called MYOP which can be user set easily. By default I use it for fast cropping (<mask> AND) but in this example I would init MYOP with $38FF680E ' MYOP COG! after which I just run AFIX like this:
    : AFIX ( hb lb -- result ) --- SWAP B>W 16 SHL MYOP ABS ;

    Of course the final example used:
    : AFIX ( hb lb -- result ) SWAP B>W 16 SHL $38FF6812 PASM DROP ;
    So that would convert to:
    : AFIX ( hb lb -- result ) SWAP B>W 16 SHL MYOP ;
    In this case MYOP is preset to perform a ~>18 or SAR tos,#18
  • max72max72 Posts: 1,152
    edited 2014-07-16 23:02
    Thanks Peter.
    In fact my original code was a rather primitive test.
    I had the two bytes composing the acceleration, and the result from the datasheet is in 2's complement. So I simply shifted left until the acceleration sign bit reached the bit 32, and let spin handle the rest...

    Seeing how you code things is a great learning opportunity. The final result is so elegant and effective..
    Thanks again.
    Massimo
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-18 08:55
    I've been working on V2.4 of the kernel which removes the CMPSTR memory hog from the cog kernel to save memory for other things but it can still run as a RUNMOD during a block mode compiling. I've also added an OPCODE construct that works just like CONSTANT in that you can create an OPCODE word which when invoke is executed as that PASM operation.

    \ Example of creating an OPCODE that runs as a PASM instruction when invoked.
    $80FF6204 OPCODE ADD4 --- ADD tos,#4

    Testing this:
    1200 ADD4 . 1204 ok


    While playing with the OPCODE word I wondered how much trouble it would be to have a simple inline assembler so I wouldn't have to work out the machine code but could type it in as normal assembly code. Yes, normal assembly code, pretty much. Here's a quick little assembler I have just been playing with and the results of a few quick test codes reveals works quick well. This may be used for assembling OBEX code for my runtime OBEX in EEPROM or SD but rather than take up code memory for something that only gets used during devlelopment I may store the mnemonics and opcodes on an SD file or EEPROM instead.

    [FONT=courier new]( Demo assembler for Tachyon Forth )
    \ this assembler is being tested but generates code interactively from the console
    
    \ define some conditional execution words
    BYTE    ce
    : CE       ce C! ;
    : if_z     1010b CE ;
    : if_nz    0101b CE ;
    : if_c     1100b CE ;
    : if_nc    0011b CE ;
    
    \ define some PASM instructions 
    LONG op
    : OP    op ! ;
    : add        100000_0010b OP ;
    : and        011000_0010b OP ;
    : rdbyte     000000_0010b OP ;
    
    \ alias for top-of-stack
    STACKS    == tos
    
    \ define some results modifiers
    BYTE sr
    : SR+    sr C@ OR sr C! ;
    : SR-    NOT sr C@ AND sr C! ;
    ( with results - zcri )
    : wc    0100b SR+ ;
    : wz    1000b SR+ ;
    : nr    0010b SR- ;
    : #     0001b SR+ ;
    
    \ The assembler itself - console prompt is revectored to this so all final assembly is carried out on an end-of-line
    : ASSEMBLE    
        BEGIN HERE 3 AND WHILE 1 ALLOT REPEAT
        op @ IF 
          SWAP 9 SHL OR op @ #22 SHL OR sr C@ #22 SHL OR ce C@ #18 SHL OR 
          4 ALLOT ( just allot the memory for now, do not store )
          "A" 1 VC SPACE HERE .WORD ." : " .LONG CR
         THEN 
        $0F CE 0 OP 0 sr C!
        ; 
    
    : ASMCODE    ' ASSEMBLE prompt W! "," delim C! "`" NFA' # 1+ C! ' CR prompt 2+ W! ;
    
    
    \ Now let's try to assemble some code 
    
        ASMCODE
                    add    tos,#,1 
            if_z    add    tos,#,1 wc
                    and    tos,#,0111
            if_c    rdbyte tos,tos     
                    add    tos 1+,#,4
        
    [/FONT]
    

    The result when run and when compared against code generated by a Spin compiler
    [FONT=courier new][COLOR=#0000cd]{ Results from test code
             ASMCODE
     3758: 80FF.6201         add     tos,#,1 
     3768: 81EB.6201 if_z    add     tos,#,1 wc
     3775: 60FF.6227         and     tos,#,100111b
     3784: 00B3.63B1 if_c    rdbyte  tos,tos          
     3791: 80FF.6404         add     tos 1+,#,4
    }
    [/COLOR]
    { Results from Spin compiler
    7E4C(0051) 01 62 FF 80 |        ADD        tos,#1
    7E50(0052) 01 62 EB 81 |         if_z   ADD        tos,#1        wc
    7E54(0053) 27 62 FF 60 |                AND        tos,#100111b
    7E58(0054) B1 63 B3 00 |         if_c   RDBYTE     tos,tos                ' same thing as a C@
    }
    [/FONT]
    

  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-18 22:23
    I've had a little time to play a bit more and expand and optimize the resident assembler and considering it's only taking 290 code bytes of storage so far I think I'm doing well. Here's what a listing looks like at the moment and remember that this is interactive on the Prop through the serial terminal but what I want to do is add forward referencing and try to standardize the assembler format closer to how PASM is written in Spin.
    [FONT=courier new]DAT     
     0200:      
     0200:                          corg    $41C0    
     41C0:              :: outmask  res    1
     41C4:              :: modeMux  res    1
     41C8:              :: freq4    res    1
     41CC:              :: lcnt     res    2
     41D4:              
     41D4:                          corg    $4000    
     4000: 80FF.6201                add    tos,# 1
     4004: 81EB.6201          if_z  add    tos,# 1 wc
     4008: 60FF.6227                and    tos,# 100111b
     400C: 00B3.63B1          if_c  rdbyte tos,tos    
     4010: 80FF.6404                add    tos 1+,# 4
     4014:              :: loop
     4014: A0FF.9908                mov    lcnt,# 264
     4018:              :: leds
     4018: 2CFF.F801                shl    PHSA,# 1        
     401C: 2CFF.F801                shl    PHSA,# 1        
     4020:              :: fspi
     4020: A0BF.EDC0                mov    DIRA,outmask
     4024: A0FF.E800                mov    OUTA,# 0
     4028: A0BF.F1C4                mov    CTRA,modeMux
     402C: A0BF.F7C8                mov    FRQB,freq4
     4030: A0FF.F200                mov    CTRB,# 0
     4034: 047F.9818                djnz   lcnt,# leds 
     4038: 5C7C.0014                jmp    # loop
     403C:            
    [/FONT]
    


    EDIT: updated the listing again, I can see that I can remove the :: for labels if I allow the "not found" error handler to create a label, simple. Getting closer.

  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-20 02:46
    This inline assembler is just about complete although I still have to resolve how to handle CALL and possibly forward references (in one pass). With all PASM opcodes defined the assembler takes up around 1400 bytes including headers and code. The interesting thing with this assembler is that it just uses the normal Forth parsing technique but TF has a few flexible hooks whereby I can tell it what to do at the start and at the end of a line as well as what to do when it comes across a word that is not in the dictionary nor is it a number. So labels are unknown when Forth first parses them but the "unum" vector which optionally processes unresolvable words points to code that creates a constant using the current origin truncated to 9-bits.

    So far so good, I will soon embark on allowing PASM code to be loaded in the same way as source code but have the code saved in a EEPROM or SD file for the runtime OBEX. I've kept it simple with the "corg" directive so it assembles to the BUFFERS area for instance and the lower 9-bits of the address are the same as the assembled cogs address. The object code would then be saved in a file to free up the storage and remove the label constants.The code would include an OBEX name such as "UART4" and at runtime we could load a cog simply by saying " UART4" 2 LOADCOG or " FPU" 5 LOADCOG for instance. With any existing PASM code there is very little modification required to make this work, mostly I just include a space after an immediate # for instance. Normal Forth operations and calculations can be intermixed with PASM even on the same line, this is a macro-macro-assembler!

    The implications for P2 are somewhat obvious too, it also means the system can be standalone and even metacompile it's own kernel.

    [FONT=courier new]DAT 
     403C: 
     403C:                          corg    $41C0
     41C0:                  unext       res    1
     41C4:                  instr       res    1
     41C8:                  IP          res    1
     41CC:                  R0          res    1
     41D0:                  
     41D0:                          corg    $4000
     4000:                  doNEXT
     4000: 00BF.89C8                    rdbyte  instr,IP    
     4004: 81FF.9001                    add     IP,# 1 wc    
     4008: 5C3F.89C4                    jmp     instr        
     400C:                  
     400C:                  _STREND        
     400C: 00BF.99B1        fchlp       rdbyte  R0,tos    ( read a byte )
     4010: 84FF.9801                    sub     R0,# 1    ( end is either a null or anything >$7F )
     4014: 857F.987E                    cmp     R0,# $7E wc
     4018: 80F3.6201              if_c  add     tos,# 1
     401C: 5C70.180C              if_c  jmp     # fchlp
     4020: 5C3F.81C0                    jmp     unext
     4024:                  
     4024:                  
     4024:                  { 
     4024: 00BF.63B1        CFETCH      rdbyte  tos,tos
     4028: 5C3F.81C0                    jmp     unext
     402C:                  
     402C:                  { 
     402C: 04BF.63B1        WFETCH      rdword  tos,tos
     4030: 5C3F.81C0                    jmp     unext
     4034:                  
     4034:                  { 
     4034: 08BF.63B1        FETCH       rdlong  tos,tos
     4038: 5C3F.81C0                    jmp     unext
                            ENDDAT ok
    
    [/FONT]
    
  • D.PD.P Posts: 790
    edited 2014-07-20 10:26
    This inline assembler is just about complete although I still have to resolve how to handle CALL and possibly forward references (in one pass). With all PASM opcodes defined the assembler takes up around 1400 bytes including headers and code. The interesting thing with this assembler is that it just uses the normal Forth parsing technique but TF has a few flexible hooks whereby I can tell it what to do at the start and at the end of a line as well as what to do when it comes across a word that is not in the dictionary nor is it a number. So labels are unknown when Forth first parses them but the "unum" vector which optionally processes unresolvable words points to code that creates a constant using the current origin truncated to 9-bits.

    So far so good, I will soon embark on allowing PASM code to be loaded in the same way as source code but have the code saved in a EEPROM or SD file for the runtime OBEX. I've kept it simple with the "corg" directive so it assembles to the BUFFERS area for instance and the lower 9-bits of the address are the same as the assembled cogs address. The object code would then be saved in a file to free up the storage and remove the label constants.The code would include an OBEX name such as "UART4" and at runtime we could load a cog simply by saying " UART4" 2 LOADCOG or " FPU" 5 LOADCOG for instance. With any existing PASM code there is very little modification required to make this work, mostly I just include a space after an immediate # for instance. Normal Forth operations and calculations can be intermixed with PASM even on the same line, this is a macro-macro-assembler!

    The implications for P2 are somewhat obvious too, it also means the system can be standalone and even metacompile it's own kernel.

    [FONT=courier new]DAT 
     403C: 
     403C:                          corg    $41C0
     41C0:                  unext       res    1
     41C4:                  instr       res    1
     41C8:                  IP          res    1
     41CC:                  R0          res    1
     41D0:                  
     41D0:                          corg    $4000
     4000:                  doNEXT
     4000: 00BF.89C8                    rdbyte  instr,IP    
     4004: 81FF.9001                    add     IP,# 1 wc    
     4008: 5C3F.89C4                    jmp     instr        
     400C:                  
     400C:                  _STREND        
     400C: 00BF.99B1        fchlp       rdbyte  R0,tos    ( read a byte )
     4010: 84FF.9801                    sub     R0,# 1    ( end is either a null or anything >$7F )
     4014: 857F.987E                    cmp     R0,# $7E wc
     4018: 80F3.6201              if_c  add     tos,# 1
     401C: 5C70.180C              if_c  jmp     # fchlp
     4020: 5C3F.81C0                    jmp     unext
     4024:                  
     4024:                  
     4024:                  { 
     4024: 00BF.63B1        CFETCH      rdbyte  tos,tos
     4028: 5C3F.81C0                    jmp     unext
     402C:                  
     402C:                  { 
     402C: 04BF.63B1        WFETCH      rdword  tos,tos
     4030: 5C3F.81C0                    jmp     unext
     4034:                  
     4034:                  { 
     4034: 08BF.63B1        FETCH       rdlong  tos,tos
     4038: 5C3F.81C0                    jmp     unext
                            ENDDAT ok
    
    [/FONT]
    

    Wow, 1400 bytes, access to obex pasm objects, P2 Tachyon being able to "self host". And all "we" did was make a little nudge for FPU pasm access. Uh looks like you are having fun so I'll just shut up and keep studying the code. Thanks Peter
  • D.PD.P Posts: 790
    edited 2014-07-21 22:55
    I am missing something basic trying to use the I2C bus from another cog.

    I have my allocated space for stack and regs, I am using the standard I2C bus pins which are initialized in I2CSTART,
    the routine works as expected when not in a task, then in the task I get zero output as seen by my logic analyzer?
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-21 23:30
    D.P wrote: »
    I am missing something basic trying to use the I2C bus from another cog.

    I have my allocated space for stack and regs, I am using the standard I2C bus pins which are initialized in I2CSTART,
    the routine works as expected when not in a task, then in the task I get zero output as seen by my logic analyzer?

    Same ol, same ol, this is the OR'd port pin from the main cog still driven high so you need to release the I2C lines before passing control to another cog. Remember, any cog can set a pin high but another cog cannot pull it down. Either keep the output low in the unused cog or release the DIRA bits. Actually it probably wouldn't really hurt leaving these lines low after an I2CSTOP so I might look at doing that instead.
  • D.PD.P Posts: 790
    edited 2014-07-21 23:47
    Right again, but the code states:
    \ I2C STOP CONDITION also releases I2C lines
    pub I2CSTOP
        SDA OUTCLR SCL OUTSET 0 DROP SDA OUTSET        \ Patch 140319 - leave SDA as a high output (in case it's shared)
         0 DROP                        \ short delay
        ;
    

    So I'll add
    pub I2CCLR
       SDA OUTCLR SCL OUTCLR
       ;
    
  • Peter JakackiPeter Jakacki Posts: 10,043
    edited 2014-07-22 00:07
    D.P wrote: »
    Right again, but the code states:
    \ I2C STOP CONDITION also releases I2C lines
    pub I2CSTOP
        SDA OUTCLR SCL OUTSET 0 DROP SDA OUTSET        \ Patch 140319 - leave SDA as a high output (in case it's shared)
         0 DROP                        \ short delay
        ;
    

    So I'll add
    pub I2CCLR
       SDA OUTCLR SCL OUTCLR
       ;
    

    Yes, but perhaps this could just be added to I2CSTOP after a few microseconds, but what if we let it float, so:
    pub I2CSTOP
    SDA OUTCLR SCLR OUTSET 0 DROP SDA OUTSET 1 us SCL INPUTS SDA INPUTS
    ;
    Note: 1 us is actually around 10 us (overhead)
Sign In or Register to comment.