### Passing immediate ROM data to a subroutine

The first way to access ROM data from program is to embed that data in the code itself, exactly like the immediate operands are hard-coded in instructions. This goal can be achieved by locating the data at the return address of the subroutine.

Since the return address can be found in the `TOSL/TOSH/TOSU` registers, the subroutine is able to access the ROM data. Although it seems freestyle, this way is very handy from the end-user point of view. For example, the LCD library provides the `void lcd_RIprint_() ;` routine that uses this type of parameter passing. As a «first step» example, the following code sends a message to a LCD display:

    lcd_RIprint_();
    ROM_TXT("Hello !\0") ;

A better way to do that is to use a macro that hides the real nature of the message:

    #define lcd_RIprint(txt) { lcd_RIprint_() ; ROM_TXT(txt) ; }

Finally, the following code will send the message:

     lcd_RIprint("Hello !\0") ;

In this example, the `'R'` stands for ROM and the `'I'` stands for immediate.

Writing a function such as `lcd_RIprint_()` is not easy because it needs a clear understanding of the PIC-18 instruction set and how the program is compiled. People interested by this point can read the code in the file `lcd.slb`, that is written in assembly language. However, it is perfectly possible to write such a function in C. For this purpose, the `rom.h` header provides several very handy macros:

1. `PREPARE_ROM_ACCESS`

   This macro mainly copy the TOSx registers to the TBLPTRx registers, and set bits needed to access ROM.

2. `READ_ROMBYTE`

   Reads one byte of data from ROM. The fetched data is stored in the `prodl` C variable, that is just an alias for the `PRODL` register. Consecutive invocations of `READ_ROMBYTE` will read consecutive data from ROM.

3. `READ_ROMWORD`

   Reads one word of data from ROM. The fetched data is stored in the `prodhl` C variable, that is just an alias for the `PRODL/PRODH` pair of registers. Consecutive invocations of `READ_ROMWORD` will read consecutive data from ROM.

4. `FINISH_ROM_ACCESS`

   Ends the transaction with ROM. The TBLPTRx registers are copied back to `TOS`x registers. The macro takes care of alignment, so the address stored in `TOS`x, is always even. Obviously, the use of this macro is mandatory in this context.

Here is an example of how to uses the proposed macros. This example implements a ROM version of the following `puts()` routine.

    void puts(char *p)
    {
      for( ; *p ; ++p)
        putchar(*p) ;
    }

The first step is to define a macro for convenience.

    #define RIputs(str) { RIputs_() ; ROM_TXT(str) ;}

The second step is to write a function that read from ROM memory every char to be printed. The number of `char` can be odd or even because the `FINISH_ROM_ACCESS` macro restores a correct parity.

    void RIputs_()
    {
      PREPARE_ROM_ACCESS ;  READ_ROMBYTE ;
      while( prodl )
      {
        putchar( prodl ) ; READ_ROMBYTE ;
      }
      FINISH_ROM_ACCESS ;
    }

Please note an important point: all the data stored in ROM must be read. Violating this rule will lead to execute data instead of machine code and will crash the processor.

Here is another example: this routine fetches 16 bit data from a ROM table, and displays it. In this example, the data is preceded by a word indicating the size of the table.

    #define RIputwords(list) { RIputwords_() ; ROM_WORDS(list) ; }

    void RIputwords_()
    {
      int k ;
      PREPARE_ROM_ACCESS ; READ_ROMWORD ;
      for( k = prodl ; k ; --k)
      {
        READ_ROMWORD ;
        outdec(prodhl) ; putchar(' ' ) ;
      }
      FINISH_ROM_ACCESS ;
    }

This function is very simple to use:

    RIputwords("3, 1000, 2000, 3000") ;

Notice that despite the parameter of `RIputwords()` is a literal, the data really stored in ROM is a sequence of words (not a string of chars).