Code Page Gotcha
Bean
Posts: 8,129
Just a little gotcha I discovered.
In the SX manual is says "To jump across a page boundary, the page select bits must first be set..."
Well I assumed that as long as the jump location was in the same code page as the jump instruction, I was ok (that I didn't have to set the page), well I was wrong.
If you have a routine that starts at the end of one code page then continues to the next (fine so far), then from the 2nd code page makes a jump to the 1st code page IT WORKS. But if the code in the 2nd code page tries to jump to a location IN the 2nd code page IT DOESN'T WORK, it jumps to the 1st code page.
I found that the page bits are not assumed to be the page the instruction is on (only you change them), they are NEVER changed unless you issue a PAGE instruction.
;
MyRoutine: ; this is at the end of code page 1
Loop1: ; this label is still in code page 1
; we have crossed to code page 2
JMP Loop1 ; THIS WORKS WITHOUT A PAGE INSTRUCTION
Loop2: ; this label is in code page 2
JMP Loop2 ; THIS FAILS BECAUSE IT JUMPS TO CODE PAGE 1 UNLESS YOU USE PAGE
;
I hope this makes sense. Please ask it if doesn't. I spent about 3 hours finding this and hope to save you from the same.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"SX-Video Display Module" Available Now.
www.sxvm.com
"A problem well defined, is a problem·half solved."
Post Edited (Bean) : 4/13/2005 12:54:44 PM GMT
In the SX manual is says "To jump across a page boundary, the page select bits must first be set..."
Well I assumed that as long as the jump location was in the same code page as the jump instruction, I was ok (that I didn't have to set the page), well I was wrong.
If you have a routine that starts at the end of one code page then continues to the next (fine so far), then from the 2nd code page makes a jump to the 1st code page IT WORKS. But if the code in the 2nd code page tries to jump to a location IN the 2nd code page IT DOESN'T WORK, it jumps to the 1st code page.
I found that the page bits are not assumed to be the page the instruction is on (only you change them), they are NEVER changed unless you issue a PAGE instruction.
;
MyRoutine: ; this is at the end of code page 1
Loop1: ; this label is still in code page 1
; we have crossed to code page 2
JMP Loop1 ; THIS WORKS WITHOUT A PAGE INSTRUCTION
Loop2: ; this label is in code page 2
JMP Loop2 ; THIS FAILS BECAUSE IT JUMPS TO CODE PAGE 1 UNLESS YOU USE PAGE
;
I hope this makes sense. Please ask it if doesn't. I spent about 3 hours finding this and hope to save you from the same.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"SX-Video Display Module" Available Now.
www.sxvm.com
"A problem well defined, is a problem·half solved."
Post Edited (Bean) : 4/13/2005 12:54:44 PM GMT
Comments
in Ubicom's SX 28 specs it reads: "The program memory is organized as 2K, 12-bit wide words. The program memory words are addressed sequentially by a binary program counter. The program counter starts at zero. If there is no branch operation, it will increment to the maximum value possible for the device and roll over and begin again." So from this point of view, the program memory looks like one contiguous block with no pages at all.
It is important to note that this "program counter" is not identical to the PC register at address 02 in RAM.
As long as you execute "linear" code, the program counter is incremented after each instruction in order to address the next instruction word. This works fine even when the code crosses page boundaries.
Trouble can occur when there is a JMP or CALL instruction. The 12 instruction bits of a JMP or CALL are not enough to hold the instruction code for the JMP together with the full jump address. Therefore, the JMP instruction can only contain the lower eight bits of the address to jump to (CALLs only hold the lower 7 bits - therefore, CALLs can only adress the lower halfs of the pages), where the upper three bits (in SX 28 and lower devices) are taken from the three page bits in the STATUS register to build the full 11 bit jump address which is then copied into the program counter.
It is important to notice that when page boundaries are crossed by the program counter, this does not automatically adjust the page bits in STATUS.
This explains the behavior that you have found.
Executing code from one page into the next one, and then doing a jump back into the first page will work fine as the page bits in STATUS still address this page. Executing a JMP into the second page without correcting the page bits before, will again cause a jump into the first page as the page bits still point to it.
Although it is possible to cross pages while executing "linear" code, it can be dangerous, as you have experienced. Therefore, I try to avoid such situations by using a code template that contains NOPs at the beginning of each page. When you then "fill" the pages with code, the assembler will report an error in case code crosses a page boundary as the first address in the next page is already "occupied" by the NOP instruction.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G
Bean - Good heads up.· Another case of the computer doing exactly what we ask it to do, but we humans (well, myself at least)·are too dim-witted to know that.· [noparse]:)[/noparse]
Nate
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Thanks Guenther, this is exactly what I THOUGHT happened.
Oh, well I just hope others can learn from my misfortune.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
"SX-Video Display Module" Available Now.
www.sxvm.com
"A problem well defined, is a problem·half solved."
·
Welcome to the club.
And Guenther;
I believe calls in fact use 8 bits (not 7) for the lower part of their address, allowing them to access 256 locations, albeit in the bottom half of a 512 byte page. Including the 3 status page bits and the ninth forced-zero bit this makes for a 12 bit address. In the SX48/52 all 12 are used, and in the smaller SX28 family only the lower 11 bits are used.
Peter
yes, you are right - 8 bits in the CALL instruction code are used to address 256 locations in the lower halfs of the pages, i.e. the 9th bit is forced to zero, and the JMP instruction uses 9 bits to allow for addressing all 512 locations in a page. As far as I know, the program counter is 12 bits wide in all SX types but the highest bit is only used in the SX48/52 devices.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G
But it is still really-really fast, so putting up with these limitations is something we just do.
Totally agreed.
However, once you are fully aware of the SX nuances and their implications, they don't pose too much of a problem.
This tiny chip really puts-out, and it's well worth the small issues.
Peter (pjv)
here is another Gottcha:
When you single-step this with the debugger, everything works as expected, especially the "jmp pc+w" causes a branch to "One" because w contains 1.
Now un-comment the "org $100" directive, and try again. The "jmp pc+w" now ends up at address $002, and not at $106, i.e. the address of "One".
Again, this is because the PC register is only 8 bits wide. The "jmp pc+w" adds w to the PC register, and then PC is copied into the lower eight bits of the program counter, and bits 8 to 10 of the program counter are set to the page bits in STATUS. As these are all 0, the program counter is set to $002 as you could see.
This means that you always must place jump tables like in this example into the first half of a page.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G
after posting my previous message, I thought it would be an idea to see how SXSim handles my code example, and I found another Gotcha:
SXSim actually did a branch to "One" even when the jump table was located in the second half of the page. I have fixed this in the meantime, and it will be available in the nect version to be posted soon.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G