@ 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.
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.
DEBUGGER setint1 #0
jmp #\_Start_Monitor ' \ forces absolute address '
Comments
DAT orgh $1000 org 0 cog long $3d3d3d3d jmp #_hub ' 00 20 80 FD abs hub jmp #@_hub ' 00 20 80 FD abs hub <--- jmp #\_hub ' 00 20 80 FD abs hub <--- _cog long $3d3d3d3d jmp #_cog ' F8 FF 9F FD rel cog jmp #@_cog ' 10 10 80 FD abs hub <--- jmp #\_cog ' 04 00 80 FD abs cog <--- orgh $2000 hub _hub long $3d3d3d3d jmp #_hub ' F8 FF 9F FD rel hub jmp #@_hub ' F4 FF 9F FD rel hub \ ??? jmp #\_hub ' 00 20 80 FD abs hub / ??? long $3d3d3d3d jmp #_cog ' 04 00 80 FD abs cog jmp #@_cog ' F4 EF 9F FD rel cog \ ??? jmp #\_cog ' 04 00 80 FD abs cog / ???
NOTE: The #@ and #\ are reversed depending on whether the code is executing from hub or cog!!!
pnut has a bug
I hope this does not cause a ROM compile problem.
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.
So in that case the only error seems to be the second last example instruction.
jmp #@_cog ' F4 EF 9F FD rel cog 'should be jmp #@_cog ' 04 00 80 FD abs cog
Eric
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
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.
jmp #\@_cog 'from hub
Got it!
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.
So you see, these are real instances, not contrived examples.
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 will need a proper resolution and a pnut fix.
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.
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. 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 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 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.
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.
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.
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.
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:
jmp #\@_cog
If I'm mistaken, could you explain what I have wrong? I do want to get this right for fastspin.
Whether this is the way the assembler should work is another question, of course. I'm just describing how (I think) it actually does work.
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?
What was interesting while Peter and I were discussing this problem, we both used our own tools (TAQOZ and the Monitor) to "patch" the ROM.
Not bad eh!!
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.
00400 orgh $400 00400 000 org 0 00400 000 entry 00400 000 fd9ffffc jmp #entry 00404 001 fd800000 jmp #\entry 00408 002 fd800400 jmp #@entry 0040c 003 fd800400 jmp #\@entry 00410 004 fd800428 jmp #entry1 00414 005 fd800428 jmp #\entry1 00418 006 fd800428 jmp #@entry1 0041c 007 fd800428 jmp #\@entry1 00420 008 00000000 long entry 00424 009 00000400 long @entry 00428 orgh 00428 entry1 00428 fd800000 jmp #entry 0042c fd800000 jmp #\entry 00430 fd9fffcc jmp #@entry 00434 fd800400 jmp #\@entry 00438 fd9fffec jmp #entry1 0043c fd800428 jmp #\entry1 00440 fd9fffe4 jmp #@entry1 00444 fd800428 jmp #\@entry1 00448 00000428 long entry1 0044c 00000428 long @entry1
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.
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
DAT orgh $1000 org 0 long $3d3d3d3d jmp #_hub ' 00 20 80 FD abs hub jmp #@_hub ' 00 20 80 FD abs hub jmp #\_hub ' 00 20 80 FD abs hub jmp #\@_hub ' 00 20 80 FD abs hub _cog long $3d3d3d3d jmp #_cog ' F8 FF 9F FD rel cog jmp #@_cog ' 14 10 80 FD abs hub jmp #\_cog ' 05 00 80 FD abs cog jmp #\@_cog ' 14 10 80 FD abs hub orgh $2000 _hub long $3d3d3d3d jmp #_hub ' F8 FF 9F FD rel hub jmp #@_hub ' F4 FF 9F FD rel hub jmp #\_hub ' 00 20 80 FD abs hub jmp #\@_hub ' 00 20 80 FD abs hub long $3d3d3d3d jmp #_cog ' 05 00 80 FD abs cog jmp #@_cog ' F4 EF 9F FD rel cog jmp #\_cog ' 05 00 80 FD abs cog jmp #\@_cog ' 14 10 80 FD abs hub
Thanks,
Eric
DAT orgh $01000 org 0 'cog code cog jmp #cog '$FD9FFFFC cog to cog, relative jmp #\cog '$FD800000 cog to cog, force absolute jmp #@cog '$FD801000 cog to hub, always absolute jmp #\@cog '$FD801000 cog to hub, always absolute jmp #hub '$FD802000 cog to hub, always absolute jmp #\hub '$FD802000 cog to hub, always absolute jmp #@hub '$FD802000 cog to hub, always absolute jmp #\@hub '$FD802000 cog to hub, always absolute orgh $02000 'hub code hub jmp #cog '$FD800000 hub to cog, always absolute jmp #\cog '$FD800000 hub to cog, always absolute jmp #@cog '$FD9FEFF4 hub to hub, relative jmp #\@cog '$FD801000 hub to hub, force absolute jmp #hub '$FD9FFFEC hub to hub, relative jmp #\hub '$FD802000 hub to hub, force absolute jmp #@hub '$FD9FFFE4 hub to hub, relative jmp #\@hub '$FD802000 hub to hub, force absolute
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.
It has taken a while to get to the bottom of this.
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.