@ or \ addressing - which to use?

I have been led to believe that the @ forces absolute addressing but in modifying code that used @ in the jmp adressing in hub rom it didn't affect anything but when I modified it in my copy in first 64k it responded. Investigating further at the actual machine code generated by PNut I found that the jump was relative $FD9x_xxxx where the lsb of 9 is the Relative addressing mode. However if I use the \ then it becomes $FD8x_xxxx plus also I can see the destination address is absolute. So what is going on? Is it supposed to be @ for relative and \ for absolute?

I have done other tests with and without etc but this is the main point in question. This is hubexec code btw.

Hubexec calling hubexec code where I have now changed it to \ to call Cluso's monitor from TAQOZ.

My understanding is that @ does *not* mean anything special in jumps; what it means (in all instructions other than "rep") is to use the hub address of a label rather than the cog address. For labels that are "obviously" in hub memory (following an orgh) "@label" and "label" will mean the same thing.

To force an absolute jump use "\" (always). Otherwise whether the jump is absolute or relative depends on whether it crosses between COG and HUB. If there's no crossing and no "\" then the jump will be relative, otherwise absolute.

If you really want to force an absolute jump to the hub address of an instruction (even for things that will be loaded into COG memory) use "jmp #\@label".

I think this is consistent with what Cluso saw. In the first example we're jumping from COG to HUB memory, so all the variants had to use an absolute address. In the second "jmp #_cog" is a COG to COG, so relative, but "jmp #@_cog" specifically asks for a HUB address, so it's treated as a COG/HUB crossing and comes out absolute (it'll switch to hubexec mode). In the third example "_hub" is in hub memory, so "jmp #_hub" and "jmp #@_hub" are treated the same; it's a HUB to HUB transfer so relative. Finally the label "_cog" is in COG memory so the jumps to it from HUB are absolute. However, "jmp #@_cog" comes out relative because, again, we're asking for the HUB address and so forcing it to be a HUB to HUB transfer.

We have a linear address space for instructions. Why isn't the same linear address space used for data? Or is it? I thought COG addresses were 0x0 to 0x1ff, LUT addresses were 0x200-0x3ff, and hub addresses were 0x400 and up. Then why do we need something to indicate whether an address is in COG, LUT, or hub space?

No, I think it should be a relative branch, because "@_cog" is a hub address, and we're starting in hub memory. " @ " on its own doesn't mean "use absolute hub address", it just means "use hub address". If you want "use absolute hub address" you need both "\" (absolute) and " @ " (hub address). At least, that's the way I understand it and implemented it in fastspin, and it seems to match PNut. But perhaps Chip can chime in and clarify things for us.

We have a linear address space for instructions. Why isn't the same linear address space used for data? Or is it? I thought COG addresses were 0x0 to 0x1ff, LUT addresses were 0x200-0x3ff, and hub addresses were 0x400 and up. Then why do we need something to indicate whether an address is in COG, LUT, or hub space?

I think it's complicated for a number of reasons:

(1) there is HUB memory from 0x0 to 0x3ff, and so there needs to be a way to access that 1K of RAM
(2) data access has to use different instructions depending on which memory is accessed: rdlong/wrlong for hub, rdlut/wrlut for LUT, and mov for COG

(2) is a particular pain for compilers and interpreters, because it means we can't have generic pointers that point anywhere If we were starting from scratch I'd recommend changing this, but it's *way* too late for that I think Besides, even for instructions things get pretty complicated, as we've seen from the discussions above.

We are having problem with jumps and calls going to the wrong place. We need to be able to tell the compiler jump/call this routine in cog, lut or hub. Currently we cannot reliably force the jump/call
The _cog and _hub labels are not really data, they are instructions located in cog and hub respectively.
And the results are opposite depending upon whether the jump/call is currently in cog or Hub.

IMHO this is plainly wrong and may result in our ROM containing incorrect jump/call addresses. We just don't know for sure although it's likely ok.

We have a linear address space for instructions. Why isn't the same linear address space used for data? Or is it? I thought COG addresses were 0x0 to 0x1ff, LUT addresses were 0x200-0x3ff, and hub addresses were 0x400 and up. Then why do we need something to indicate whether an address is in COG, LUT, or hub space?

Instructuctions can only (normally) reference cog registers because we are limited to 9 bits for both S and D operands.
But we cannot always use absolute addresses for a few reasons.
Not all jump/call instructions have enough bits to fully address the entire memory map.
Hub data addresses between $00000-$00400 do exist and overlap cog and LUT space.
We may want the code to be relocatable.
We may want to call a routine that may reside in cog as well as Hub. Yes, I do that now with Chip's booter - I call his routines as hubexec even though he loads them into cog and LUT and runs them from there. His method is faster, but when I call them they may not exist in cog or LUT. My SD and Monitor code runs totally in hubexec mode.
TAQOZ runs in lower Hub and cog. It is compiled for ROM but is copied down to lower Hub.

Currently Chip, Peter and I are using JMP/CALL #@hub to mean an address in HUB ROM. This is compiling correctly (thankfully) for the case where the jump/call is executing from cog. This is how Chip passes control to SD, TAQOZ and the Monitor.

When this was sorted around a week ago, I converted one of my code blocks (IIRC it was SD) from # to #@. It's probably not going to matter either way, but it's not the right way.

We have a linear address space for instructions. Why isn't the same linear address space used for data? Or is it? I thought COG addresses were 0x0 to 0x1ff, LUT addresses were 0x200-0x3ff, and hub addresses were 0x400 and up. Then why do we need something to indicate whether an address is in COG, LUT, or hub space?

I think it's complicated for a number of reasons:

(1) there is HUB memory from 0x0 to 0x3ff, and so there needs to be a way to access that 1K of RAM
(2) data access has to use different instructions depending on which memory is accessed: rdlong/wrlong for hub, rdlut/wrlut for LUT, and mov for COG

(2) is a particular pain for compilers and interpreters, because it means we can't have generic pointers that point anywhere If we were starting from scratch I'd recommend changing this, but it's *way* too late for that I think Besides, even for instructions things get pretty complicated, as we've seen from the discussions above.

Ugh. Do you mean that the first location in hub memory is 0x400 if we're executing code from it and 0x0 if we're accessing it as data. That seems like a big mistake.

Edit: I guess that isn't true. Phew! We just can't execute code from the first 0x400 bytes of hub memory. That seems fine.

We are having problem with jumps and calls going to the wrong place. We need to be able to tell the compiler jump/call this routine in cog, lut or hub. Currently we cannot reliably force the jump/call

I believe you can reliably force an absolute jump/call as follows:

jmp #\@_cog ' jump to the hub address of _cog
jmp #\_cog ' jump to the cog/lut address of _cog (if it is in cog/lut memory)
jmp #\_hub ' jump to the hub address of _hub (if it is in hub memory; in that case same as jmp #\@_hub)

What seems to be missing is a way to force a relative jump and to give an error if it cannot be relative.

The _cog and _hub labels are not really data, they are instructions located in cog and hub respectively.

For the assembler there's no difference between data labels and instruction labels -- they're just labels. My understanding (based on the docs and on reverse engineering PNut) is that labels have two values: their "default value" (if no " @ " is used in front of them) and their "hub value" (if " @ " is used in front of them). After .orgh these two values are the same. After .org they are different, and the "default value" becomes the COG/LUT address based on the .org. " @ " applies to the label, not the instruction, and forces the hub value to be used. That is, "jmp #@_cog" just means "jmp to the hub address of the label _cog", and whether that jump is relative or absolute is determined by the crossing rules. Similarly, "mov x, ##@_cog" will place the hub address of _cog into x.

An example would be:

DAT
orgh $400
org $80
x
jmp #x ' same as jmp #$80: relative
jmp #\x ' same as jmp #\$80: forced absolute
jmp #\@x ' same as jmp #\$400: forced absolute
jmp #@x ' same as jmp #$400: absolute due to crossing
long x ' same as long $80
long @x ' same as long $400

PNut and p2asm both handle this the same. fastspin chokes on the #\@, I need to fix that (using #\(@x) does work).

I'm afraid I still don't understand the difference between a hub and a COG address. I understand that COG/LUT overlap the first 0x400 bytes of hub memory. Is that the only issue? Otherwise, the value of the address determines where it is in the memory map I think. Or are you distinguishing between the address in hub memory where a COG image resides before COGINIT vs. where it is in the COG?

What seems to be missing is a way to force a relative jump and to give an error if it cannot be relative.

I'm having trouble locating the discussion, but I believe this is correct. Chip said something along the lines of, "Relative jumps COG to HUB, HUB to COG are a bad idea" and discouraged them. Nobody talked about relocatable code that does this back then. Here we are with the ROM, and it's a valid case.

What was discussed was the fact that the instructions permit it, but as a general programming practice, the assembler wouldn't actually do that. Not making a statement on that, just recalling the relevant discussion we had at the time.

Questions:

Is that a general case we need to fix in Pnut? I'm asking, because Chip's reason was the high difficulty and potential for error present when doing this kind of thing.

(Since we are likely to publish this ROM code as part of the chip docs, we should fix this, or at least document how to make it explicit.)

At the time we had the discussion, we did not have the robust debug capability we do now. Does that debug cover doing this well enough?

I'm afraid I still don't understand the difference between a hub and a COG address. I understand that COG/LUT overlap the first 0x400 bytes of hub memory. Is that the only issue? Otherwise, the value of the address determines where it is in the memory map I think. Or are you distinguishing between the address in hub memory where a COG image resides before COGINIT vs. where it is in the COG?

I guess it depends on what you're talking about, but I think for jump purposes addresses $0-$3ff are treated as cog/lut memory and $400 up are treated as hub memory. That means you cannot do an absolute jump to a hub address below $400. It is (theoretically) possible to do relative jumps to such addresses, but in practice the assembler may give errors because it thinks you'll be crossing between the hub and cog domains, and relative branches are not supposed to do that.

I'm afraid I still don't understand the difference between a hub and a COG address. I understand that COG/LUT overlap the first 0x400 bytes of hub memory. Is that the only issue? Otherwise, the value of the address determines where it is in the memory map I think. Or are you distinguishing between the address in hub memory where a COG image resides before COGINIT vs. where it is in the COG?

I guess it depends on what you're talking about, but I think for jump purposes addresses $0-$3ff are treated as cog/lut memory and $400 up are treated as hub memory. That means you cannot do an absolute jump to a hub address below $400. It is (theoretically) possible to do relative jumps to such addresses, but in practice the assembler may give errors because it thinks you'll be crossing between the hub and cog domains, and relative branches are not supposed to do that.

So this issue of absolute COG/LUT vs. hub addressing really just amounts to how to handle the first 0x400 bytes? Or do we also have to deal with the two low-order bits being missing from COG/LUT addresses?

So this issue of absolute COG/LUT vs. hub addressing really just amounts to how to handle the first 0x400 bytes? Or do we also have to deal with the two low-order bits being missing from COG/LUT addresses?

There's also the complication that every label has two values, its "default" value (which may be in COG memory) and its hub value (which definitely is in hub memory). The hub value is accessed via " @ ". The documentation is a little unclear on this whole concept, I'm afraid, and it's easy to think that " @ " signals an absolute jump (it doesn't, only "\" signals an absolute jump.

So this issue of absolute COG/LUT vs. hub addressing really just amounts to how to handle the first 0x400 bytes? Or do we also have to deal with the two low-order bits being missing from COG/LUT addresses?

There's also the complication that every label has two values, its "default" value (which may be in COG memory) and its hub value (which definitely is in hub memory). The hub value is accessed via " @ ". The documentation is a little unclear on this whole concept, I'm afraid, and it's easy to think that " @ " signals an absolute jump (it doesn't, only "\" signals an absolute jump.

When would the COG and hub address of a variable be different? Are we talking about the two low-order bits?

It's to do with how to force the compiler to do what the programmer wants, and for this method to be consistent.

We have code in the Hub ROM area commencing at $FC000. This is the code executed when the final silicon P2 boots. It's in hubexec mode. It copies code from, for ease let's say from $FC000 into cog and from FC800 into lut, and then jumps to let's say cog $000. So the same code can be present in both cog and Hub. Similarly LUT and Hub but let's forget that.
So that code has a cog address and a hub address.
If I want my program to jump to that code, I need to tell the compiler which address to use, cog or Hub. Currently I have to know if my code (the code doing the jumping) is currently running in cog or hub, because the method of forcing the compiler to do the jump to cog or hub is reversed depending on whether my jumping code is running from cog or hub. That's a bug because the instruction format should be the same!! See my code results posted above. They are taken from the real pnut output!!
Now, the code that Chip executes in cog also resides in Hub. And when I need to call it, it's no longer available in cog. But it is still in Hub, and it is compatible with hubexec operation (not all code can run in hubexec because some instructions don't work in Hub). So I have to force the compiler to jump/call a routine using its hub address.
The alternative is for each of us to have identical routines in hub which is a waste (and we no longer have the space either).

Eric, sorry you are incorrect. See my top post where I show what pnut produces.
Again, it's not the compiler that has issues with Hub execution addresses below $400 (which I think is actually $400 << 2 = Hub $1000), but rather the P2 silicon PC (program counter) is 20 bits and addresses in the bottom 2KB are interpreted as cog and the next 2KB as lut. When in cog/lut I believe its the bottom 2bits that get discarded as cog and lut are only addressed as longs. Hub is addressed in bytes, and I believe can. execute from odd addresses. Certainly rdlong can fetch from a non-long aligned address.

Potatohead, the ROM of a few versions back has already been published for testing purposes. It may be included with the latest FPGA code - I got mine directly from Chip and it's in the zip file.

Eric, sorry you are incorrect. See my top post where I show what pnut produces.

I'm sorry, I think we're talking past each other somehow. Your top post seems consistent with what I would expect, namely " @label " is always treated as a hub address, and whether or not a jump is absolute is an orthogonal question. The jump is absolute either if (a) an explicit "\" is given before it, or (b) the code has to jump from cog to hub or vice-versa.

If code in hub jumps to a label with " @ " in front of it (and no "\") it will always use a relative jump, since it's hub to hub. If code in cog jumps to a label with " @ " in front of it (and no "\") then it will always use an absolute jump, since it's cog to hub.

So if you really want an absolute jump to a hub address use both "\" and " @ ", namely:

Eric,
Sorry I wasn't aware until you said today that the #\@label was legitimate. It never crossed my mind.
So what I am saying is pnut is not consistent within the rules that we thought we were using.
With that further explanation, I will need to look again. That's not going to happen for another 18 hrs at least.
Perhaps in the meantime you might test these out with pnut for us?

When would the COG and hub address of a variable be different? Are we talking about the two low-order bits?

I posted an example earlier in the thread, but another simple one:

orgh $400
org 0
entry
jmp #entry
long entry ' will be 0
long @entry ' will be $400

Here the default (cog) address of entry is 0 (set by org) and the hub address is $400. "@entry" gives the hub address. "entry" gives just the default address, which in this case is a cog address.

If you take away the "org 0" then both addresses will be the same, that is " @entry " and "entry" will both have the value $400.

So the difference between COG and hub address is due to the code being assembled to reside in hub memory (it's hub address) but it is then copied to COG memory for execution and hence also has a COG address?

All code resides in hub RAM, so everything has a hub address. If an ORG directive is used the code will also have a cog address starting with the address specified by the ORG directive. Symbols that have a cog attribute will result in the cog address if it is not preceded by an @. If an @ is used, then the result is the hub address.

For symbols that do not have a cog attribute it doesn't matter if the @ symbol is used or not. The result is always a hub address.

Here's the listing output from p2asm when assembling a short snippet of code. The first column shows the hub address, and the second column shows the cog address. Note that the code after the ORGH does not have a cog address. Jumps from cog to cog and hub to hub use relative addresses unless the \ character is present, which forces an absolute jump. Jumps between cog and hub always use an absolute address.

All code resides in hub RAM, so everything has a hub address. If an ORG directive is used the code will also have a cog address starting with the address specified by the ORG directive. Symbols that have a cog attribute will result in the cog address if it is not preceded by an @. If an @ is used, then the result is the hub address.

For symbols that do not have a cog attribute it doesn't matter if the @ symbol is used or not. The result is always a hub address.

Here's the listing output from p2asm when assembling a short snippet of code. The first column shows the hub address, and the second column shows the cog address. Note that the code after the ORGH does not have a cog address. Jumps from cog to cog and hub to hub use relative addresses unless the \ character is present, which forces an absolute jump. Jumps between cog and hub always use an absolute address.

I'm sure there will be uses for creating code that can be executed in either cog or hub, but I think most of the time we will want to dedicate the code to either cog or hub execution exclusively. Also, instructions that use the data streamer cannot be executed from the hub since hubexec requires the data streamer as well.

A nice feature of relative addressing is that it allows for position independent code. A snippet of hub code could execute equally starting at location $400 or $FFF0. For a while I supported a position independent code (PIC) mode in p2gcc. The jumps could be done from anywhere in memory. However, I did have to adjust the data addresses to match where the data is located in memory.

Sorry I wasn't aware until you said today that the #\@label was legitimate. It never crossed my mind.
So what I am saying is pnut is not consistent within the rules that we thought we were using.
With that further explanation, I will need to look again. That's not going to happen for another 18 hrs at least.
Perhaps in the meantime you might test these out with pnut for us?

I must agree that the documentation is confusing. I was lucky that I already had " @ " in my mind as an operator that acts on labels (like "-") rather than an instruction modifier (like "#" or "\"). So my mental picture agreed with Chip's.

Below is a slightly modified version of your original post. As you can see the " #\@ " form always gives a jump to abs hub. I've checked and p2asm and PNut both produce the same result. fastspin kind of does as well, if you give it the -c option to just extract the DAT. Otherwise fastspin wants to compile a Spin method and optimizes everything away when it doesn't find one . Again, something I will need to fix. This has been very enlightening...

Keep in mind that "@address" always returns the hub address of the label, even if the label also represents a cog address. The implication of using "@address" in branches is that the assembler sees you branching to a hub address.

I might be missing something, but it seems that the assembler is working correctly. This needs more documentation, though.

I am happy that what I am using in my code is working as desired, but it is more by luck than good management.

Now I can clean it up to ensure I use what I want the compiler to do. I will use the #\@label or #@label when I want to jump/call hubexec code. Currently I have no need to jump/call cog or lut code, but that will come later for sure.