Does SF ever set TBLPTRU?

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Does SF ever set TBLPTRU?

Post by Jerry Messina » Fri Apr 22, 2011 11:41 am

Is the TBLPTRU register ever set or initialized?

I realize that SF doesn't have support for a 24-bit data type (which is really what the TBLPTRU/TBLPTRH/TBLPTRL register set is), and does table accesses using a 16-bit address.

There's the following alias in the device .bas files...

Code: Select all

public dim
    TABLEPTR as TBLPTRL.AsWord
Which creates a 16-bit pointer. This allows access to the first 64K of flash memory space (assuming that TBLPTRU is $00).

I've seen code posted that allows access to the full 24-bit program memory space...

Code: Select all

function ReadByte(pAddress as TABLEPTR) as byte
   asm-
      TBLRD *+
      movff TABLAT, result
   end asm
end function

function ReadByte(pAddress as longword) as byte
   TBLPTRU = pAddress.Byte2
   TBLPTRH = pAddress.Byte1
   TBLPTRL = pAddress.Byte0
   asm-
      TBLRD *+
      movff TABLAT, result
   end asm
end function
This creates two functions... the first uses a 16-bit address and the second the full 24-bit address.

The issue is, once the TBLPTRU register is set like this, it's never set back to $00, so any future table reads (or accesses to const data) fail since the TBLPTRU may be pointing to a different page of 64K space.

For example, if you have

Code: Select all

dim b as byte

b = ReadByte($1000)         // accesses $001000 (assuming TBLPTRU=0)
b = ReadByte($200000)       // accesses $200000
b = ReadByte($1000)         // accesses $201000 **INCORRECT**
Likewise, accessing const data has the same issue

Code: Select all

const data_table() = (1,2,3,4,5,6,7,8)
dim b as byte

b = ReadByte($200000)       // accesses $200000, sets TBLPTRU = $20
b = data_table(b)           // doesn't work, as TBLPTRU isn't 0
since SF assumes that all 'const' data is located in the first 64K page and that TBLPTRU is 0.
SF uses the 16-bit TBLPTRH/TBLPTRL pair to access the 'const' data, and ignores the setting of TBLPTRU.

So it would seem that any functions that modify TBLPTRU must set it back to 0 when done

Code: Select all

function ReadByte(pAddress as longword) as byte
   TBLPTRU = pAddress.Byte2
   TBLPTRH = pAddress.Byte1
   TBLPTRL = pAddress.Byte0
   asm-
      TBLRD *+
      movff TABLAT, result
   end asm

   TBLPTRU = 0      // set upper TBLPTR back to 0 for normal SF access
end function
But, thats not the end of it. Since TBLPTRU is never set, if you have an interrupt routine that accesses const data, then 'ReadByte' can cause problems. To see that, add in something like this to the above

Code: Select all

interrupt intr()
    dim b as byte

    b = 1
    b = data_table(b)   // won't work if happens to interrupt ReadByte()!!!!
end interrupt
So, in addition to setting TBLPTRU back to 0, you must also disable interrupts in ReadByte(), and re-enable them when done

Code: Select all

function ReadByte(pAddress as longword) as byte
   INTCON.7 = 0      // disable interrupts while using TBLPTRH

   TBLPTRU = pAddress.Byte2
   TBLPTRH = pAddress.Byte1
   TBLPTRL = pAddress.Byte0
   asm-
      TBLRD *+
      movff TABLAT, result
   end asm

   TBLPTRU = 0      // set upper TBLPTR to 0 for normal SF access

   // reenable interrupts
   // this is an issue, since maybe they weren't enabled to start with.
   // really, we should have read the state of INTCON.7 before we cleared it,
   // and only enable them here if they were enabled to start with
   INTCON.7 = 1
end function
Another way would be to change the isr to save/restore the TBLPTRU...

Code: Select all

interrupt intr()
    dim b as byte

    save(TBLPTRU)
    TBLPTRU = $00       // needed for SF to access const data

    b = 1
    b = data_table(b)

    restore

end interrupt
And there's another issue (sorry for being long-winded)

Since TBLPTRU is never initialized, SF relies on it being set to 0 by a RESET event, such as a power-on reset, MCLR, WDT timeout, etc. Usually not a problem, unless you try to restart your code using a 'goto 0' or you're using a bootloader which might have changed TBLPTRU...

Code: Select all

b = data_table(b)           // this will fail the second time through
b = ReadByte($200000)       // accesses $200000, sets TBLPTRU = $20

// restart
asm
    goto 0
end asm
Adding a 'TBLPTRU = $00' statement to the beginning of your program will help, but you'd have to add it as initialization code in an included module to get it to execute before any other include files.

Post Reply