Shop OBEX P1 Docs P2 Docs Learn Events
Propeller Program loading trick — Parallax Forums

Propeller Program loading trick

Beau SchwabeBeau Schwabe Posts: 6,568
edited 2009-03-28 00:13 in Propeller 1
Ok, so a recent thread "What is save binary for?" and something Jeff Martin·re-iterated in a webinar that I already knew got me thinking.
·
I'll post details on this later, because·I think this might open some doors for many of you running·large Propeller applications.· Here is how I would use something like this.· Suppose I have MANY assembly "snippets" that I want to use that I have functionally compiled over a period of time.· Each snippet is capable of standalone operation and is useful in it's own way.· Suppose I have a large project that would benefit from several of these code snippets working together, but·the problem is that I don't have enough memory left to contain all of the functions that I want to use. What do I do?·· The technique I have discovered would allow you to dynamically load a dedicated cog from any external EEPROM capable of holding all of·the code snippets, and run them as if it were an original part of the Propeller’s·boot memory without having to re-boot.· The same dedicated cog could be re-programmed on the fly from the main cog by fetching the data from the external memory and self-modifying the data·within·the dedicated cog.
·
Instead of saving the Original program as binary, I have saved the Original program as EEPROM.· From there I have written a small external program to parse the EEPROM file and create the "byte section" you see in the Tokenized Program below.· This eliminates the·need to transcribe the data.· But if you will notice doing an F8 on both programs below will yield slightly different tokenized code.· There is a reason for this and I will elaborate on this later.
·

Original Program:
CON
  _CLKMODE = XTAL1 + PLL16X
  _XINFREQ = 5_000_000
  
PUB start
    cognew(@Assembly_DEMOBoard_BlinkTest, 0)
DAT
Assembly_DEMOBoard_BlinkTest
        mov   t1,       #1
        shl   t1,       #16
        mov   dira,     t1
        mov   outa,     t1
        mov   t2,       clkf
        shr   t2,       #2
        
        mov   t3,       cnt
        add   t3,       t2
Loop    waitcnt t3,     t2  
        xor   outa,     t1
        jmp   #Loop

clkf    long  80_000_000
t1      res   1
t2      res   1
t3      res   1


Tokenized Program:
CON
  _CLKMODE = XTAL1 + PLL16X
  _XINFREQ = 5_000_000
  
PUB start
    cognew(@Assembly_DEMOBoard_BlinkTest, 0)
    
DAT
Assembly_DEMOBoard_BlinkTest
byte $00,$B4,$C4,$04,$6F,$A4,$10,$00,$78,$00,$80,$00,$70,$00,$84,$00
byte $68,$00,$02,$00,$60,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$2C,$FC,$A0,$10,$2C,$FC,$2C
byte $16,$EC,$BF,$A0,$16,$E8,$BF,$A0,$15,$2E,$BC,$A0,$02,$2E,$FC,$28
byte $F1,$31,$BC,$A0,$17,$30,$BC,$80,$17,$30,$BC,$F8,$16,$E8,$BF,$6C
byte $12,$00,$7C,$5C,$00,$B4,$C4,$04,$34,$87,$08,$35,$2C,$32,$00,$00


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 5:10:51 AM GMT

Comments

  • SapiehaSapieha Posts: 2,964
    edited 2009-03-26 08:15
    Hi Beau Schwabe (Parallax)

    Is it not posible edit EEPROM file that skip spin code section and only save in "MyCOG-Pasm.Cog" file DAT section.
    Then in MySpin program.

    CON
    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000

    PUB start
    cognew(@CogProg, 0)


    DAT
    CogProg 'The Transient Program Area
    .............. file "MyCOG-Pasm.Cog" ' assembly "snippet"

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-26 08:19
    Sapieha,

    Essentially that's what I'm doing, but there are some pointer offset considerations that you must take into account in your original program. I too originally thought it would be a straight copy, but it's not.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • SapiehaSapieha Posts: 2,964
    edited 2009-03-26 08:25
    Hi Beau Schwabe (Parallax)


    I wil compile only PASM with BSTC with first 8 Longs that have vectors to Places in HUB of my VARIABLES with COG comunikation.
    Then LOAD that snipet.
    And in my spin section only use them 8 Longs to point to HUB variables and discard rest of "Snipet"

    Ps Maybe 16 Longs

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
  • jazzedjazzed Posts: 11,803
    edited 2009-03-26 08:29
    If you need other ideas on this approach have a look at http://forums.parallax.com/showthread.php?p=776824
    Maybe since you are thinking about it people will be more warm to the idea [noparse]:)[/noparse] No doubt, I do look forward to your contribution.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-03-26 17:55
    Hmmm -- it would be worthwhile to develop an assembler/linker that would produce relocatable load modules that could be loaded dynamically·by name into a cog and executed.· Something running in a master cog could then decide it needed to execute one of these, and would load it into a cog (from, say, a large eeprom) and get it running.

    The eeprom would contain multiple relocatables and a directory for finding them by name.· The program in the master cog would include a simple loader/linker/relocater subroutine·to load'em up and get'em going.

    Relocatable modules could include encoded references (by name) to other relocatable code.· The loader/linker would·notice these references·as it was loading the code, and in the same operation also load any required subs, replacing the encoded references with actual as-loaded addresses.

    Nothing of this is a new idea, of course -- mainframes did it as early as the 1950s -- but no one has done it on a Prop, I think.· It'd be a fun project, not terribly tough, and it'd be a start on a real operating system, too.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-26 19:24
    Here is a little more·information with some test code examples...

    Assembly_DEMOBoard_TokenTest.ZIP - contains everything (attached)
    ·
    ···· Assembly_DEMOBoard_TokenTest.spin - Main DEMO program
    ···· Assembly_DEMOBoard_BlinkTest.zip- BlinkTest Assembly source code and EEPROM dump
    ···· Assembly_Pin_HIGH_Test.zip - PinHIGH Assembly source code and EEPROM dump·
    ···· Assembly_Pin_Pan_Test.zip - PinPan Assembly source code and EEPROM dump


    Demonstrates "safe" COG entry and exit after Assembly code completion
    Demonstrates COG entry and continued execution
    Demonstrates that Spin in original COG has not been compromised and continues to work properly
    Demonstrates that you can affectively move data around·from one location to another.
    ·Note : - This can be an external memory source
    ·········· - And you don't need to move the entire 32K block, just the portion that pertains
    ············ to the Assembly code.
    An example of copying/moving a tokenized routine from one location to the next and then executing the routine

    Updated version below - files removed

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 5:14:04 AM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-26 21:44
    I don't understand why you need to store the original PASM as EEPROM-file, use an external tool to extract something ... and put it back in code as byte array.

    You talk about large programs to run on the Prop. So the goal is to save tons of PASM-programs on a SD-card and load them when needed. You can easyly use the target propeller to store the stuff on the card. Just a little host program which utilizes the SD driver and contains the or some PASM code that has to be stored.

    With the @ spin and pasm know where to find the compiled PASM code. So, instead of running it with cognew let the SD driver store the code on SD. Later on it in the real program it can be loaded into a buffer and run from there.

    con
      _clkmode = xtal1 + pll8x
      _xinfreq = 10_000_000
    

    var
            long          led_pin, dt
            
    pub main
      dira[noparse][[/noparse]0..7]:=$ff
       
      ' this one starts the original version of the code
      led_pin:=1
      dt:=80_000_000
      cognew(@movable, @led_pin)
      repeat until led_pin==0
       
      ' now we copy the movable to another HUB RAM section and start it from there
      led_pin:=
      longmove( @load_buffer, @movable, 512 )
      led_pin:=2
      dt:=40_000_000
      cognew( @movable, @led_pin )
      repeat until led_pin==0
       
      repeat
        outa[noparse][[/noparse]4]~
        waitcnt( 30_000_000+cnt )
        outa[noparse][[/noparse]4]~~
        waitcnt( 30_000_000+cnt )
              
    dat
                  org 0
    movable                                         ' this points to the start of PASM-code
                  mov       hub_pin, par            ' get adresses of the HUB parameter buffer
                  add       hub_wait, par
    pin           rdlong    pin, hub_pin            ' read the pin reusing this RAM
    waittime      rdlong    waittime, hub_wait      ' read the wait time reusing this RAM            
                  wrlong    inb, hub_pin
                                
    time          mov       dira, pin               ' set the given pin to output
                  mov       time, cnt               ' calculate the first waitcnt-value
                  add       time, waittime
                  
    toggle        xor       outa, pin               ' toggle the pin
                  waitcnt   time, waittime          ' wait for the given time
                  jmp       #toggle                 ' and repeat endless
    

    hub_pin       long      0
    hub_wait      long      4
    movable_end   res       1                       ' this will point to the end of the PASM-code
    

    var
            long something[noparse][[/noparse]2048]
            long load_buffer[noparse][[/noparse]512]
    

    This is just a proof of concept. Instead of the longmove the 'storer' would write the PASM to SD and the big program would use the SD driver to load it into a buffer and run it from there.

    The only problem I currently have is the adress operator. I'd like to do something like

    length := @[url=mailto:movable_end-@movable]movable_end-@movable[/url]

    to calculate the size of the PASM code. But it does not work. Is it my mistake? How can you store a adress in a variable?
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-26 22:22
    MagIO2,

    I come from the idea that the main program is in Spin and calls the Assembly subroutines to aid in the overall program functionality. This may be my own fault, but it stems from years of writing code in QuickBasic4.5 and running "In-Line Assembly" from within Quickbasic4.5. Your method is not entirely different from mine in the sense of determining where the PASM is, but yours seems to live completely in PASM. Another thing I'm not clear on, is that it seems that your code must load the entire 512 longs into the buffer which is not the case with the code I have posted.

    As far as your questions...
    "The only problem I currently have is the address operator. I'd like to do something like ... length := @movable_end-@movable"

    This would work if you changed ... "movable_end res 1" ... so that it reads ..."movable_end long 0"

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-26 22:46
    Thanks for the tip. Now I can make the code not save/load 512 longs.

    length:=@movable_end-@movable
    longmove( @load_buffer, @movable, length )

    I have not been aware that the label of a RES is treated differently from a label of a LONG ... but sure ... the REServed long is only available for PASM.

    Of course you are right. My code was written having in mind to move store/load PASM code and no Spin code. But if Spin code is relocateable that's a nice to have as well. But shouldn't that work with the longmove & labels as well? I'll try that.

    My main point is: I don't know why you use an external program and use some tricks to mark the start and the end of code, if you can let a propeller do the job?

    Post Edited (MagIO2) : 3/26/2009 11:02:47 PM GMT
  • jazzedjazzed Posts: 11,803
    edited 2009-03-27 00:38
    One can use a spin binary loader to specify and load all the PASM "drivers" and not worry external files, but at some point the loader would have to load and start the application that uses the drivers. This of course requires a 64KB+ EEPROM or an SDCARD. As Mike Green points out, this is how his Prop-O/S and the follow-ons work ... not everyone wants an O/S though.

    For external PASM drivers that would be loadable on demand, tokenizing or some organizational form is necessary to extract the different DAT sections ... often people use tables that are not part of the PASM.

    It is an interesting idea to load and run certain PASM snippets on demand ... too bad you couldn't just point a custom spin interpreter to the newly loaded code and say go. While slower and obviously limited, you could pack more instruction features·in the cog memory.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • SapiehaSapieha Posts: 2,964
    edited 2009-03-27 02:57
    Hi Beau Schwabe (Parallax)

    Sorry if I not understand it.
    But You start COGNEW with HEADER position and NOT with real PASM code position.

    My Question is WHY?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nothing is impossible, there are only different degrees of difficulty.
    For every stupid question there is at least one intelligent answer.
    Don't guess - ask instead.
    If you don't ask you won't know.
    If your gonna construct something, make it·as simple as·possible yet as versatile as posible.


    Sapieha
    867 x 548 - 130K
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-27 04:02
    Sapieha,

    When I point directly to the PASM code, the pointers within the PASM code are not correct. I've noticed that if the PASM code does not have any jumps or calls it works, but that's not a realistic code approach. I'd like to get rid of the Header myself, but I don't think it's a possibility, since it contains information as far as how big the PASM code is (i.e. bytes 10 and 11 indicate the PSAM code size) and other information that is normally setup during compile time that you normally don't see. Perhaps I'm missing something, I am always open for suggestions.

    Scratch that... I just figured something else out ... update to follow

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 4:09:30 AM GMT
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-27 04:29
    Sapieha,

    Your absolutely right... for some reason I was not getting my head around how the assembly program is entered... I essentially replaced the Header with all Zero's and it still compiled just fine. This makes things much easier, even in the Assembly code. No header required at all. I will update the post and clean things up with the revision.

    Thank you

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-27 05:19
    Updated version:
    Sapieha·had pointed something out that I had overlooked.· In the previous version there was a Header requirement.· In this version the·Header has been removed.· What remains is the Footer, but this is mainly just a cue to a parsing program I use to generate the stand-alone EEROM dumps that I can later use in Spin in sort of an in-line assembly coding approach.



    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 5:29:26 AM GMT
    1280 x 1024 - 418K
    1280 x 1024 - 274K
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-27 07:54
    Ok .. I guess this will be the last post from me until I have a better example for my approach or I got enlightenment on the reason of having an external tool.

    But could you please confirm or unconfirm my understanding:
    In this thread we talk about a way to have at least PASM code snippets·(Spin snippets would be nice as well)·which get loaded during runtime as needed. For example we have devices A, B and C attached to the Propeller. All 3 are never used together and are only needed from time to time. Then there is no need to waste 3 COGs for the drivers AND no need to have the driver code in the HUB RAM for all the time.
    Or we have a menu based system and depending on the selected menu entry code is loaded to do the job.
    Or we want to implement a YALMM (Yet another LMM ;o) which runs a subsequence of the code with size of COG RAM at full speed and then reloads the next 512 LONGs and so on.

    What I still don't understand is the advantage of having a external tool which needs header and footer to find the PASM code in the EEPROM-file.

    My suggestion is to have a minimal storing system around the PASM code snippets. So, in PropTool you open at least 2 tabs for writing an extended program. One which is used to edit the main program and one which includes the storing system that can have (32k - size of storing system itself)Bytes of different PASM-code-snippets. The main function of the storing system of course would change a lot as it can be used to test the PASM modules. If tests have been passed successfully, you'd replace the test code with a call of the SD driver, which stores the PASM-code on the SD-card.
    In the main program you now can load this module in a buffer, start it in the COG and use the buffer for loading the next module or use it otherwise.

    This is not working code, but an outline of the idea:
    SnippetStoringSystem
    OBJ
      sd: "SomeKindOfSDdriver" ' or EEPROM or whatever storing system you like to use
    
    PUB mainStoringSystem
      ' test code for PASM module 1
      ' here comes the code for testing the PASM code (Spin or PASM ... whatever needed)
      ' when test was successfull this code is uncommented but kept for the case that further improvements of the module is needed
    
      ' in case of success you uncomment the line which stores the PASM snippet to SD
      ' sd.store( "module1", @module1, @module1_end - @module1 )
    
      ' test code for PASM module 2
      ' .......
    
    DAT
      ORG 0
    module1      mov x,par
                 ..... do something ....
    module1_end  long 0
    
    ORG 0
    module2      mov dira, #1
                 ... do something else ...
    module2_end  long 0
    
    .....
    
    

    Program which uses the snippets:
    OBJ
      sd: "SomeKindOfSDdriver"
    
    VAR
      long sync
    
    PUB mainProgram
      ' this code is for initial load of drivers for example. This way the driver does not waste HUB RAM
      ' (depending on the drivers it might be done in a loop as well)
      sd.load( @load_buffer, "module1" )
      cognew( @load_buffer, @sync )
      repeat while sync ' alternatively you can do waitcnt which waits long enough to let the HUB load the buffer into COG RAM
    
      sd.load( @load_buffer, "module2" )
      cognew( @load_buffer, whatsoever )
      waitcnt( loading_time )
    
      .... some code ....
    
      ' on demand load somewhere in the code
      sd.load( @load_buffer, "modulex" )
      cognew( @load_buffer, whatsoever )
      waitcnt( loading_time )
    
    var
      long load_buffer[noparse][[/noparse]512]
    
    
    

    As you see there is no external program needed to find the PASM snippets and store it on a SD card. A testing environment is needed anyway. No need to deal with EEPROM-files. The Propeller can handle that allone. (Beau, you should have more confidence in your controller ;o)
    Having a byte array which represents the PASM is not needed for (what I think is) our goal and I guess it's been used as a proof of concept, isn't it?

    Post Edited (MagIO2) : 3/27/2009 8:00:44 AM GMT
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-03-27 15:20
    MagIO2,

    You are correct, you don't need to deal with an EEPROM file if you have an SD card or other memory form attached, just have the Propeller write data to the SD card and be done with it.· In light of that, because of my minimalist hardware approach, I don't have an SD card attached and my way of extraction during this preliminary proof of concept debugging stage is to use an EEPROM dump ... I suppose I could send the data serially to the PC, that would be a real BIG storage reservoir, and that would more closely resemble an SD card or other external memory, but I'm an old DOS guy at heart and like to visually DEBUG·HEX code.· - smirk

    "But could you please confirm or unconfirm my understanding:
    In this thread we talk about a way to have at least PASM code snippets (Spin snippets would be nice as well) which get loaded during runtime as needed. For example we have devices A, B and C attached to the Propeller. All 3 are never used together and are only needed from time to time. Then there is no need to waste 3 COGs for the drivers AND no need to have the driver code in the HUB RAM for all the time.
    Or we have a menu based system and depending on the selected menu entry code is loaded to do the job.
    Or we want to implement a YALMM (Yet another LMM ;o) which runs a subsequence of the code with size of COG RAM at full speed and then reloads the next 512 LONGs and so on.
    "

    Yes, I agree with all of this and to add, an effective O/S could easily be achieved using a method like this.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-28 00:13
    So ... just finished the first demo of the PASMstore (after some soldering ... had to·prepare a SD card slot of an old multi card reader for my breadboard-propeller-setup;o), which shows how I will do the dynamic COG load in future.
Sign In or Register to comment.