How are propeller objects loaded into hub RAM?
borisg
Posts: 39
I hope this isn't a real newbie question, but I haven't been able to find out anything about how code is loaded into hub RAM. So far I've just been playing around with assembly language programs and today, with some trepidation, tried to do some programming in Spin. It didn't take long to realize that a "Global" variable in my 1 msec timer object was anything but global. What I had hoped to do was to put a longword in low RAM where it would accumulate counts from my 1 msec timer which runs in a cog and have that variable available to other cogs by just doing a RDLONG. As it was, I had to add a spin function which returns the value of my "global" SysTimer which doesn't help me at all when it comes to performing inter-cog communication without Spin. When I look at the object info display in Propeller tool, every object has it's code start at location $10. Presumably at some point there's an object load map created of how all of the objects are loaded into RAM but I haven't been able to find it anywhere. With the amount of assembly code I'm going to potentially have, I'll also need a way of reclaiming the hub RAM that is just used to hold DAT structures with the cog code.
Is there any way to reserve the first 2 Kb of hub RAM for my exclusive use? Right now the only dedicated locations are 0 and 5 dealing with clock speed. What I had planned on doing for my project was to use direct addressing of global locations in low hub RAM with a literal addresses which would give me a maximum of 2048 bytes when accessing hub RAM as longs as well as not requiring a longword in the cog to store the address. I was planning on having a Propeller "page0" in a similar fashion to how the 6502 chip had shorter instructions to access commonly used variables in the first page of RAM. Given the complexity of my application which will do ambulatory physiologic monitoring from multiple sensors, I need every cog location and it would be more satisfying to use only a single propeller chip rather than go to a 2 chip solution.
I've found very little on the details of the Spin interpreter and, given the efficiencies which one can attain with addressing "Page 0" locations, it wouldn't surprise me if some of these locations were used by the spin interpreter as it would facilitate cramming the whole interpreter into a single cog.
While I'm not very impressed with Spin, I'm very impressed with the efficiency with which one can code routines in propeller assembly language. I do have to admit that I prefer programming in assembler and in my days as a programmer my PDP-11 programs were written almost exclusively in assembly with a bit of FORTRAN glue code to tie the routines together. Right now I'm trying to decide if my time would be better spent writing my own supervisor code in assembler rather than trying to learn Spin.
Is there any way to reserve the first 2 Kb of hub RAM for my exclusive use? Right now the only dedicated locations are 0 and 5 dealing with clock speed. What I had planned on doing for my project was to use direct addressing of global locations in low hub RAM with a literal addresses which would give me a maximum of 2048 bytes when accessing hub RAM as longs as well as not requiring a longword in the cog to store the address. I was planning on having a Propeller "page0" in a similar fashion to how the 6502 chip had shorter instructions to access commonly used variables in the first page of RAM. Given the complexity of my application which will do ambulatory physiologic monitoring from multiple sensors, I need every cog location and it would be more satisfying to use only a single propeller chip rather than go to a 2 chip solution.
I've found very little on the details of the Spin interpreter and, given the efficiencies which one can attain with addressing "Page 0" locations, it wouldn't surprise me if some of these locations were used by the spin interpreter as it would facilitate cramming the whole interpreter into a single cog.
While I'm not very impressed with Spin, I'm very impressed with the efficiency with which one can code routines in propeller assembly language. I do have to admit that I prefer programming in assembler and in my days as a programmer my PDP-11 programs were written almost exclusively in assembly with a bit of FORTRAN glue code to tie the routines together. Right now I'm trying to decide if my time would be better spent writing my own supervisor code in assembler rather than trying to learn Spin.
Comments
to be real honest I did'nt want to read all the text you have written.
What I have understand so far is
global variables are not really global.
variables within a *.SPIN-file (most of the time an object are accessible within this file)
If you wanthave access from everywhere you can write "set_variable" and "get_variable" methods inside your object
and to acess them from outside this *.-spin-file call these method like any other method
as you come from assembler the other method is to pass the pointer to this variable
to the other code
As you are asking how are spin-files loaded into HUB-RAM
why would you like to fiddle around with absolute adressing where the variable is stored and this place changes with every little change of the SPIN-code?
just use the @-operator to get the valid HUB-RAM-adress
best regards
Stefan
As you see at the begin of hub memory 16 bytes are reserved for clock and Spin pointers, then comes a jump table for the Spin methodes of the top-object and then follow the DAT section of the top-object. So you can reserve 2kByte at the begin of the DAT section of the top object to reserve that space at begin of the hub ram (just don't use the first 32 bytes or so). But you can access only 512 bytes with the immediate form of WRBYTE and RDBYTE/-WORD/-LONG, not 2kB (hub ram is byte addressed, not long addressed like cog ram).
Spin may not be so impressive for an Assembly programmer when it comes to speed,. Where Spin shines is compactness of code, easy to programm (objects) and very simple integration of PASM code for the fast parts of the project.
Andy
WRLONG msecCount, #F0
instead of using:
WRLONG msecCount, SysClock
which requires me to have a cog variable SysClock holding the address of the 1 msec clock variable in hub RAM.
Similarly, in any other cog that needs to know the value of the 1 msec clock to timestamp an event, all it would have to do is:
RDLONG, msecCount, #F0
This saves a whole long in the cog, but not knowing the location that my msec clock "global" is loaded, I can't directly access hub RAM to get at the value.
Use of literal addressing allows one to access the first 512 bytes, words and longs in hub RAM using the RDBYTE, RDWORD and RDLONG instructions. What I was planning on doing in this low memory area was to hold commonly used variables and utilize the approach you outlined for less commonly used variables.
My method does have the disadvantage that one needs to refer to memory locations by address rather than mnemonics but I'm already executing the Propeller assembly code in my head to check on timing and the longest routine I've written thus far has been some 30 instructions long.
I can pass a single address to other cogs in the cognew call but I was hoping to be able to use most of the first 2048 bytes of hub RAM to create an inter-cog communication area with minimal Spin coding required. I'm probably dating myself when I bring up the Commodore 64 which used the first 256 bytes of RAM for storage of key system variables - the Propeller allows the same approach except one has fast cog access to 2048 bytes of low hub RAM.
After perusing your document as well as the Propeller tool memory maps, discovered that main object DAT section comes first in physical memory. Can grab this RAM by creating array:
PP0 Long $0[128]
as the first statement in the main object's DAT section. Verified it by using
WRLONG MsecTimer, #$20
to write out a shared copy of my msec timer which will be used to timestamp all events in other cogs.
Have been getting more proficient in Spin over the last couple of hours but still huge numbers of errors in comparison to the nice clean assembler instruction format. From my perspective, when one has such a powerful 32 bit instruction set as each cog has, why bother with a HLL? Again, I probably date myself as I can't see any use for OOP.
Just looking at the timer values returned by my spin code (using Parallax serial terminal) and the values which are stored in RAM in my Spin test program shows that the serial terminal spin calls take from 1-3 msec which is fine in a user interface application but I've become used to the 20 MIPS/cog one can get programming in assembler. The Propeller is fast enough that one can create virtual peripherals with a small amount of assembler and get away with writing the main code in Spin. Curious that no-one has written a pure assembler system that takes full advantage of the Propeller's speed.
It is One that program.
Look for Linus demo program -- it is written entirely in PASM.
Spin implements only a very simple form of OOP, the objects are more like modules or library files. The advantage is that you can mix them together without knowing how they work internally and you never will have nameing conflicts.
I think there are alternative Assemblers (command line tools) but they are mostly used only by the creator. BST and Homespun are two alternative Spin compilers that also have improved Assemblers included. And they can generate a Listing with hub- and cog memory addresses.
Programming a big project full in Assembly will be a pain, also if PASM is nice and clean. You have only a very limted memory inside the cogs, if you need longer code you can use the LMM technic (Large Memory Modell) which loads the instruction longs from hub and executes it. But then you soon wish you had a HLL that generates this LMM code ;-) . When you are at that point it's time to look at PropGCC. This C compiler generates can generate LMM and fast PASM code from a HLL.
Andy
I would advise, just don't do it. Don't even think about reserveing any such "page 0" memory on the Prop.
There have been hundreds of PASM codes written for the Prop that don't need to do that and I would imagin it's only an extreme circumstance that would absolutely require it.
1) It's messy, you have to arrange for the data to be in that "page0" some how. Can be done but it's not nice.
2) As you say you end up having to refer to those "page0" variable by number rather than symbol.
2) It does not gain you any speed.
3) Yes, you need a long in COG to hold the HUB address of your HUB variable. That has not cause problems for most people most of the time.
So just use @ to get the address of you HUB variables and pass them into COGs via PAR as is normal practice.
If you ever get to a situation where that thwarts your progress then come back here and shout and seare at me:)
If you really don't want to work in Spin, a quite resonable approach there are some options:
1) propasm will assemble pure PASM programs, no Spin required. It's a bit historic now I think as Cliff is not advancing it.
2) Use propogcc. Even if you don't use C it can start up into your PASM that you write in GAS syntax. Then of course you can use your "page0" with ease.
Thanks a lot for that link.
if you start a PASM-cog you can handover a long in the second parameter of the cognew.
This can be any HUB-RAM-adress so then you have your memory location(s) for anything
you want to exchange between any cogs
best regards
Stefan
globalStore.spin
And use it like that:
globalMain.spin
You can "Import" the globalStore.spin in any other SPIN-file and the variables would not be duplicated. The PASM-code can access the variables as shown in the code. Some other SPIN-code can Access the variables with the long[]-Array:
long[ gs.getAddress + gs#SPECIAL_REG1 ] := 0
The idea behind the HLL in general is to have code which is much easier to understand. In Propeller world there is a much more important benefit: The bytecode is much more compact!
So, with the 32k limit you can put more functionality in the code than in a PASM-only program.
Have also discovered that loading of additional Spin objects seems to take up $10 bytes of low hub RAM for each object loaded. My 1msec timer test program worked well writing data to a long at $20 but when modified Greg Denson's MMA7455 interfacing program found out that the first free byte of Propeller "Page 0" was now at $30. Experimentally tried clobbering byte at $20 with my 1 msec timer and got a reboot from EEPROM. Have my EEPROM loaded with Turbulence so getting the audio from my Propeller Demo Board is a good indication that the system has rebooted itself and it's a reminder of how much one can do with PASM.
While I agree with those who point out that byte code tokens are more efficient use of RAM than PASM longword instructions, I find it hard to go from an environment where I'm dealing with fractions of microseconds to one where single statement executions are measured in msec or tens of msec. Thus my desire to write as compact PASM code as possible to take advantage of the raw speed of the Propeller.
A little faster than that, try 50ns for each 'regular' pasm instruction.
I takes a little time to get used to the PAR.
but if you create a set of VARibles in SPIN, they all will be in right order after each other in hub ram.
So if you pass the address of the first variable to pasm though PAR, you will know the hub address and you offset from there.
PAR is read only and you can not overwrite it by mistake, and you can not add to it so copy it to t1 etc and then add.
Hub ram address is in bytes, so after writing a long you would need to add 4.
A cog rams "byte" is always 32bit, so there you would add 1 after a long write to move to next location.
@borisg,
If you feel the need for speed perhaps you should look at using C instead of Spin. Both propgcc and Catalina compilers will compile down to so called LMM mode. That is where PASM code is generated but kept in HUB memory, a simple loop in COG fetches those instructions into COG one at a time and executes them. Basically it compiles to PASM that is run at one quarter speed of COG code.
However don't forget that often a lot of your code does not actually need to be optimized for Speed. Once you have the serious work going in PASM in Cogs, those parts can be hooked together in Spin without much loss in performance.
A simple made up example: Read from a serial line and log the incoming data to SD card. Here the stuff that needs to be fast is the serial driver and the SD block writer. Cranking up the speed of the "glue" code that connects them together may not be your bottleneck and may be easier to leave it as Spin.