PDA

View Full Version : Propeller Program loading trick



Beau Schwabe (Parallax)
03-26-2009, 03:00 PM
Ok, so a recent thread "What is save binary for? (http://forums.parallax.com/showthread.php?p=794563)" 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,$7 0,$00,$84,$00
byte $68,$00,$02,$00,$60,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00
byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$2C,$FC,$A0,$1 0,$2C,$FC,$2C
byte $16,$EC,$BF,$A0,$16,$E8,$BF,$A0,$15,$2E,$BC,$A0,$0 2,$2E,$FC,$28
byte $F1,$31,$BC,$A0,$17,$30,$BC,$80,$17,$30,$BC,$F8,$1 6,$E8,$BF,$6C
byte $12,$00,$7C,$5C,$00,$B4,$C4,$04,$34,$87,$08,$35,$2 C,$32,$00,$00


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

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

Sapieha
03-26-2009, 03:15 PM
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 Schwabe (Parallax)
03-26-2009, 03:19 PM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Sapieha
03-26-2009, 03:25 PM
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

jazzed
03-26-2009, 03:29 PM
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 :) No doubt, I do look forward to your contribution.

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


Propalyzer: Propeller PC Logic Analyzer (http://www.brouhaha.com/~sdenson/Propalyzer)
http://forums.parallax.com/showthread.php?p=788230 (http://forums.parallax.com/showthread.php?p=788230)

Carl Hayes
03-27-2009, 12:55 AM
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 (mailto:nn5i@arrl.net)

Beau Schwabe (Parallax)
03-27-2009, 02:24 AM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 5:14:04 AM GMT

MagIO2
03-27-2009, 04:44 AM
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[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[4]~
waitcnt( 30_000_000+cnt )
outa[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[2048]
long load_buffer[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 := @movable_end-@movable (mailto:movable_end-@movable)

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 Schwabe (Parallax)
03-27-2009, 05:22 AM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

MagIO2
03-27-2009, 05:46 AM
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

jazzed
03-27-2009, 07:38 AM
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://www.brouhaha.com/~sdenson/Propalyzer)
http://forums.parallax.com/showthread.php?p=788230 (http://forums.parallax.com/showthread.php?p=788230)

Sapieha
03-27-2009, 09:57 AM
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

Beau Schwabe (Parallax)
03-27-2009, 11:02 AM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 4:09:30 AM GMT

Beau Schwabe (Parallax)
03-27-2009, 11:29 AM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Beau Schwabe (Parallax)
03-27-2009, 12:19 PM
Updated version:
Sapieha (http://forums.parallax.com/member.php?u=50666)·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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Post Edited (Beau Schwabe (Parallax)) : 3/27/2009 5:29:26 AM GMT

MagIO2
03-27-2009, 02:54 PM
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[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 Schwabe (Parallax)
03-27-2009, 10:20 PM
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 (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

MagIO2
03-28-2009, 07:13 AM
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.