Data output using TBLRD (PIC 18Fx) The 18Fx series support the reading of byte data from instruction space (i.e. byte packed LUT's rather than the 'Return with Acc' word based tables). A Read operation copies one byte from program memory into the TABLAT table latch (a normal SFR register, address 0x). Read is one instruction, but consumes 2 CPU CLK's. When a read is performed, the address used is that in the Table Pointer latches (a set of 3 normal SFR registers, Upper, High, Low). The pointer register 'set (i.e. the 22bit value) can be incremented or decremented as part of the read instruction. Register addressing is 8bits, which are combined with the current value of the 4bit BSR (Bank Select Register) to choose one of the GP Registers - these instructions can all 'bypass' the BSR to access the SFR registers (in 'bank 0'). Bank 0 (0x0), address 0x00-0x5F (96 bytes) are normal GP registers called 'Access RAM' because they can always be accessed :-) ), whilst 0x60 and up are the Special Function Registers. On the 18F14K50, Bank 2 (0x2) is the 256 bytes that 'double up' as the USB FIFO (when USB is enabled). Bank 15 (0xF) maps direct to the SFR's (at 0x60 and up) = for example, 0xFFF points at the upper 4 bits of the Top of Stack. NB. There is a single 'Move Reg to Reg' (a 2 word instruction) that uses full 12 bit addressing (and ignores the BSR), however thus has no effect on the status bits. So, how fast can we transfer from Table to PORT ? First, any jump or loop 'costs' CPU cycles, so the fastest code will be always be 'in-line' which also means registers can be explicitly addressed (i.e. indirect source Reg addressing is not 'imposed'). so here's a chunk of code to output from a table look-up 'as fast as possible' (the Table 'high' bits (RBLPTRU and TBLPTRH) must be set (as must the BSR, if relevant) before calling the code). LineNout: COPY RegN,Acc ; get the ascii code (1) COPY Acc,TBLPTRL ; use as lo byte of table address (byte) pointer (1) TBLRD ;read shape byte to TBLAT (2 CLKs) COPY TBLAT,Acc ;byte to Acc (1) COPY Acc,PORTx ;and thus to PORT (1) ; and repeat for each Register regN we want to output 5 instructions, 6 CLK's per output Whilst this is an 'in-line' code 'stack', it's not restricted to a single instruction page (unlike anything that relies on using PCL), however, unless an indirect Register addressing pointer is used the instruction stack has to reference each Register 'explicitly'. Further, there is no EOL 'stop' control. The BSR (Bank Select) bits do mean we only have to 'set up' the stack for 256 registers (rather than however many kb's of Registers might exist), however that is still 256*5 = 1280 instructions (using explicit addressing means a scan line can't cross a BSR boundary i.e. we have to reach EOL before overflowing the current BSR). The main-line code can (has to) 'jump into' the 1280 instruction 'stack' at the right Register address to strat output from a specific RegN. Since the 'stack' ahs no ' end check', the main-line caode also has to set up the Timer/Counter to 'interrupt the stack when EOL CLK's have elapsed' (80chars at 6 CLK's each means count 480 (or 240 with div/2 prescaler)) Using indirect register addressing The 'size' of the stack can be reduced by using the FSR pointer / INDF register access - in whihc case an 80 character scan line only needs 80 code blocks Stackable code block to output 1 byte from the Table COPY INDF,Acc ;get first ascii code (1) INC FSR ; inc the indirect pointer (1) COPY Acc,TBLPTRL ;ascii to lo byte of table address (1) TBLRD ;read byte to TBLAT (2 CLKs) COPY TBLAT,Acc ;byte to Acc (1) COPY Acc,PORTx ;and thus to PORT (1) 7 CLK's per output, however this 'costs' 6 instructions for each (possible) byte. To output up to (say) 640/8= 80 characters, this is 480 instructions. The Timer Counter still has to be preset to Interrupt when the EOL is reached in order to terminate the stack ... Looped indirect register addressing There is no difference between an BRA Loop and a BRA nZ Loop in terms of CLK counts, so Looping means we can also make provision for variable length output (i.e. we can stop looping when EOL is found). All we have to do is make sure Z flag is set when ascii 0x00 (EOL) is seen Full loop with EOL checking ... LineNout: COPY INDF,Acc ;get first ascii code Loop: INC FSR ; inc the indirect pointer (1) COPY Acc,TBLPTRL ;ascii to lo byte of table address (1) TBLRD ;read byte to TBLAT (2 CLKs) COPY TBLAT,Acc ;byte to Acc (1) COPY Acc,PORTx ;and thus to PORT (1) note, sets Z bit COPY INDF,Acc ;get the ascii code now, so EOL sets the Z flag (1) BRA nZ,Loop: ; loop non-Z, drop through if EOL 0 (2) ; RETurn ; main-line code has to CLR PORT after appropriate delay ... Note that INDF is left pointing at the '0' byte ... 9 CLK's per output - and no need for any clever Interrupt tricks ..