How to address main memory in PASM?

Hi,
I'm trying for hours to access main memory and become more and more confused.
I try to access the main memory like shown in the following code:
This kind of code sometimes works, sometimes not. It depends on the position of the instructions. So I think I'm accessing memory, but not the one I want. I guess I overwrite some instructions.
Now I figured out that the addresses of #mainmem does not make much sense.
I declared the #mainmem as follows:
Looking at the addresses now tells me, that #mainmem is 0x00000000 and #other is 0x00000001.
Why is the distance between the two longs only 1?
And why starts the address as 0?
Is this the right way to declare "global" variables? In spin I've to use VAR, but then the symbols are not available to the assembler.
ps.: I use OpenSpin as assembler
I'm trying for hours to access main memory and become more and more confused.
I try to access the main memory like shown in the following code:
DAT
org 0
test mov :addr, #mainmem
movd :addr, #mainmem >> 9
rdlong :data, :addr
jmp #test
:addr res 1
:data res 1
fit
This kind of code sometimes works, sometimes not. It depends on the position of the instructions. So I think I'm accessing memory, but not the one I want. I guess I overwrite some instructions.
Now I figured out that the addresses of #mainmem does not make much sense.
I declared the #mainmem as follows:
PUB main
cognew(@blink, 0)
' … more cogs started …
cognew(@test, 0)
cogstop(cogid)
DAT mainmem long 0 ' For testing
DAT other long 0 ' For testing
Looking at the addresses now tells me, that #mainmem is 0x00000000 and #other is 0x00000001.
Why is the distance between the two longs only 1?
And why starts the address as 0?
Is this the right way to declare "global" variables? In spin I've to use VAR, but then the symbols are not available to the assembler.
ps.: I use OpenSpin as assembler
Comments
PUB main cognew(@test, @mainmem) DAT mainmem long 0 org 0 test mov addr, par ' address is passed as parameter rdlong data, addr data res 1 addr res 1
This is because there's no way in "standard" PASM to get the HUB address of a symbol; all label references are translated to their COG (32 bit) addresses. That's why there is only "1" between the two longs in your earlier sample, and why they start at the wrong address.In some non-standard assemblers (bstc, fastspin, I think homespun) there is a triple @ operator that does give the absolute HUB address of a symbol. The forum messes up the at sign, so I'm going to insert spaces between them, but in the real program the 3 at signs should come immediately together:
org 0 test mov addr, mainmem_ptr rdlong data, addr mainmem_ptr long @ @ @ mainmem ' contains HUB address of mainmem addr res 1 data res 1
There are multiple correct ways of doing it, here are some of them:
1. Pass a pointer to one variable in through the PAR register (= the second parameter to cognew)
PUB main cognew(@test, @mainmem) cogstop(cogid) VAR long mainmem ' For testing DAT org 0 test rdlong data, par jmp #test data res 1 fit
Advantages:- No code patching => no issues when multiple cogs are being started
Disadvantages:
- Only one pointer - If you need more you need to either use multiple "adjacent" memory locations (= an array or multiple variables defined in a particular order) or add an additional layer of indirection
2. Patch in the pointers before starting the cog
PUB main mainmem_ptr := @mainmem cognew(@test, 0) cogstop(cogid) DAT mainmem long 0 ' For testing DAT org 0 test rdlong data, mainmem_ptr jmp #test mainmem_ptr long 0 data res 1 fit
Advantages:
- Multiple pointers without any mess
Disadvantages:
- Can cause issues when starting multiple cogs in quick succession (IIRC a cog needs roughly 8192 cycles to start up and fill its memory). When in doubt, add a waitcnt after the cognew
3. Use manually allocated memory at the end of RAM (here: last LONG at $7FFC)
CON _FREE = 1 ' 1 LONG reserved at end of RAM. I think this must be in the top level object. You can do without it, but the compiler won't warn you _STACK = 128 ' Also reserve some stack (otherwise _FREE isn't very useful) PUB main cognew(@test, 0) cogstop(cogid) DAT org 0 test rdlong data, mainmem_ptr jmp #test mainmem_ptr long $7FFC data res 1 fit
Advantages:- Smaller code
- Nicer in an application that consists of mostly/only custom PASM
Disadvantages:
- Is a huge mess to keep track of
- Not suited for "plug-and-play" reusable Spin objects
This is very helpful information.
I'm writing an XMM application in C using the Catalina compiler. This is due to a bunch of menus and stuff that I can't fit into CMM mode.
But I also need to run another cog to handle traffic management to a GPS receiver and some motors.
Unfortunately due to the caching issue within XMM, Catalina is unable to start another cog containing C code. But it can start another cog to run Spin or Assembly code.
So I'm thinking about writing the traffic manager code in Assembly.
I'm using the SMALL XMM memory model, meaning that all of the variables I'm using are contained within HubRam.
I'm now wondering if I create a structure in C that contains all of the variables the traffic manager needs, and then pass a pointer to that structure to the cog running the Assembly code, if it will work. At first glance it seems that it should.
Thanks for giving me some ideas on how to do this...
Method 2 works perfectly for my purpose.
I know exactly how many memory I need for each buffer and I only start one instance/cog for each code "segment".
So I can simply assign all memory addresses first and then start the cogs.