To access tables on SX, two methods can be used:
First method should be used with special care; the table cannot cross a page boundry because the PC may overflow and jump will take you anywhere but the table. It is a good idea to include a couple directives to check for 256 word block crossing in the table. For example, a table to convert a bit number in W to its mask:
bitnum2mask and W, #%00000111 ;limit offset in 0-7 range add PC, W ;add offset to PC ;also can be coded as ; jmp PC+W table_start retw 1 retw 2 retw 4 retw 8 retw 16 retw 32 retw 64 retw 128 IF ((($ - 1) ^ table_start) >> 8) != 0 error: 256 word block crossed in bitnum2mask ;it won't compile if error condition exists ENDIF
Another disadvantage of jump-tables is that the maximum range is 0-255, i.e. 256 table entries. That's because only bits 0:7 of program counter are accessible.
Finally, despite this not really being documented anywhere (as of 2000/11/06), adding, or-ing, and-ing, moving, etc... an 8 bit value to the PC (bits 0..7) also results in CLEARING the 9th bit (bit 8) of the PC. So you can only do relative or computed jumps into the first half page of each page. Just like calls.
These are all limitations of the PIC 16C5x architecture that the SX chips cop.. err... emul.. err... work kinda the same as.
Also: My macros (a work in progress for the SXKey) has an GotoW macro that automatically generates the most compact lookup code possible depending on a jump tables length and position in program memory. It depends on part of the first half page of program memory being reserved for the jump table and generates the actuall jmp PC+W call and jmps there with a long jump to that location from the main code. Due to a limitation of the macro engine in the SXKey compiler, it does not support forward references. For SASM (in the new SXKey 2.0 beta or above) see sasmcond.src
The SX specific IREAD instruction is specifically designed for easy table access. It returns the whole 12 bit word from program memory - lower byte is returned in W and higher byte in M. The range of table entries restricted only by program memory. Same example can be rewritten using IREAD:
bitnum2mask ;load lower byte of address plus index mov temp, W ;store index mov W, #table_start && $FF ;w = lower byte of table start address add W, temp ;add index to w mov M, #table_start >> 8 ;load higher address of table snb C mov M, #table_start >> 8 + 1 ;correct if carry IREAD ;read table to M:W mov M, #$0F ;restore MODE to default table_start dw 1, 2, 4, 8, 16, 32, 64, 128
Of course, another advantage of the IREAD instruction is that the table values are 12 bit rather than 8. This fact can be used to store more data in the same program space or to implement desination page independant "jump" tables. The bit 8 = 0 problem remains, however.
Also:
See Also:
Questions:
Hello, I'm just beginning to play with SX devices and have a question about Table Lookups code sample: In IREAD example why do we need following adjustment?
snb C mov M, #table_start >> 8 + 1 ;correct if carry
According to description of IREAD command 12-bit address is obtained by CONCATENATION, not by ADDING conents of M and W. I think there should be no adjustment in this case. May be documentation is incorrect?
The adjustment is needed if the IREAD table data (the DW's following the table_start label) pass over a half page address boundry... in other words, what if the addition of W and temp causes an overflow? The macro in My Macros and sasmmem.src checks for this possibility and does not compile the skip and second move if there is no need for them.