Instructions for MS-DOS program "MAKEROM" ***************************************************************** NOTICE Hewlett-Packard is making MAKEROM.EXE available to customers free of charge to help them in HP 48SX application development, under the following conditions: * The program MAKEROM.EXE and the documentation file MAKEROM.DOC are provided "as is," and are subject to change without notice. Hewlett-Packard Company make no warranty of any kind with regard to the software or documentation, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. Hewlett-Packard Company shall not be liable for any error or for incidental or consequential damages in connection with the furnishing, performance, or use of this software and documentation. * The program and documentation are copyrighted by Hewlett- Packard. Sale of this material is prohibited without prior written permission of Hewlett-Packard Company. * The HP Customer Support department does not support MAKEROM. Questions, comments, defect reports, etc. should be directed to the Library Development conference on the HP Calculator Bulletin Board System. All responses from Hewlett-Packard will normally be provided through that conference. * Software generated by MAKEROM.EXE should be tested and qualified in its final form. Revised versions of the software and documentation will be posted on the Bulletin Board as they become available. -1- 1. MAKEROM - Library Generator The RPL development tools RPLCOMP, SASM, and SLOAD may be used to create individual code objects, but they do not easily support the creation of a library object. MAKEROM is a preprocessor that reads a control file and external files (with the .ext extension) generated by the RPL compiler, then generates the appropriate header, hash, and end files for library generation with the Saturn assembler and loader. Libraries are a collection of objects in a precompiled form that allows fast access. The precompiled form of a library includes a library name, a hash table containing all the names of user words, a link table in routine number order with execution addresses of all routines, an optional message table containing all the messages for use by the error handler, and a configuration routine which lets the library do something at configuration time (whenever a System Halt occurs). It also contains a checksum that the HP 48 uses to verify if the library is valid or not (Warning: Invalid Card Data). The tool MAKEROM is used to build the various tables. A SLOAD command creates the checksum. Libraries must be address-independent, because they can reside anywhere in ports 0, 1, or 2. To be address-independent, all references to library routines is done through a rom pointer. A rom pointer is an RPL object with a 5-nibble prologue (DOROMP) and a 6-nibble body containing the rom id (called Library ID to users) and the routine number within the library. When a library routine is called, the mainframe determines if the rom is present in the system, and if so, determines the address of that routine and transfers control to it, thereby recognizing the fact that the routine's actual address is unknown until the moment the routine is called. Three things tell the RPL compiler to turn references to library routines into rom pointers. First, the compiler directive xROMID says to compile certain routines for external ROMs (libraries) rather than for a HP 48 built-in ROM. Second, all library routines must be declared with xNAME (or sNAME) for named user words or NULLNAME for unnamed words -- NAMELESS is not allowed. Third, the compiler directive EXTERNAL identifies which of the NULLNAMEd routines are to be subject to compilation as romptrs. Routines that are not declared EXTERNAL will be compiled as object pointers. -2- Assembly language must be bounded by the CODE...ENDCODE directives in order to be address-independent. No statements like CON(5) (*)+5 are allowed, because they are loaded at a specific address. Moving that code to a different address will then fail. CON statements can only be used for values, not for addresses. Addresses can be referenced by REL statements. The process of generating a library object with MAKEROM is not a trivial one, so the file structure and procedures that have been used by HP and other developers for such projects as the HP 82211A Equation Library Card or the HP 48 Programmer's ToolKit will be illustrated here. The order of events is: + Compile and assemble the source + Use MAKEROM to create the head, hash, end, and loader control files + Use the loader to build the library from the output files generated by MAKEROM in combination with your code + Use the loader to add a binary download header to the front of the library and fill in the system references. A naming convention is used to lend some organization to all the files that comprise a completed library. A unique two-letter prefix is used to separate one library from others, and the file extension is used to indicate the type of a file. For instance, in the Equation Library card project, the prefix PT was used for the Periodic Table library, CO was used for the Constants library, BR was used for the browser, etc. The two-letter prefix is also used to name internal routines within the library. This is done to help separate one library's routines from another. -3- The file extensions are defined as follows: EXTENSION MEANING --------- -------------------------------------------- .A Saturn assembler source file .EXT External list generated by RPLCOMP .H Include file, used by RPLCOMP or SASM .L Saturn assembler list file .LR SLOAD output list file .M SLOAD control file .MN MAKEROM control file .O Saturn object code file (with Saturn header) .OL Loader output file .S RPL source file A series of internal RPL source files are used to create a complete library object. Since a large number of files will eventually be involved, an example will be used to walk through the process. The example library object will contain two user words, which will be kept to an absurd simplicity so that attention may be kept on the file structures. The file structure in this example is more complex than is needed, however the intent is to illustrate a structure suitable for more involved applications. The prefix letters GE will be used in this example to keep the "geometry library" distinct from other projects and to prefix the names of the internal routines in the library. This is the batch file that builds the example library: RPLCOMP GEUSER.S GEUSER.A GEUSER.EXT SASM GEUSER RPLCOMP GEMAIN.S GEMAIN.A GEMAIN.EXT SASM GEMAIN RPLCOMP GESUBS.S GESUBS.A GESUBS.EXT SASM GESUBS RPLCOMP GECFG.S GECFG.A GECFG.EXT SASM GECFG MAKEROM GE.MN GE.M SASM GEHEAD SASM GEHASH SASM GEEND SLOAD GE.M SLOAD -H G.M -4- The example contains two words, ACONE and VCONE. The files that are used to build the library object are: Group 1 ---------- GEROMID.H ROM ID include file GEEXTDEC.H External declaration include file Group 2 ---------- GECFG.S Library configuration code GEUSER.S User words GEMAIN.S Dispatchees of user words GESUBS.S Subroutines Group 3 ---------- GE.MN MAKEROM input file G.M Loader control file MAKEGEO.BAT Batch file to do it all The files in group 1 are very important. The first file, GEROMID.H, contains an xROMID instruction that tells the RPL compiler what library number is being used, and an assembler ROM ID equate that's used in the configuration source code: * Geometry Library ROM ID include file. This file should * be included in all source modules. Library ID numbers * in this file are expressed in hex. *** NOTE THAT THERE ARE TWO ENTRIES TO CHANGE IF THE *** LIBRARY ID CHANGES xROMID 2FC ASSEMBLE GEROMID EQU #2FC This file is included in every RPL source file - those files ending with the ".S" extension. If the romid is to be changed, only this file will need to be edited to affect a complete change of the romid (after re-compiling and assembling everything, of course). A "make" utility would be useful here. -5- The second file in group 1, GEEXTDEC.H, contains the external declarations. TITLE Geometry External Declarations ***************************************************************** * Geometry Library external declarations file. This file should * be included in all source modules. These external declarations * are listed in alphabetical order, but there is no requirement * about ordering. ***************************************************************** EXTERNAL GEDoACone EXTERNAL GEDoVCone EXTERNAL GEtimesPI Each routine in the RPL source files must be declared with NULLNAME, so that the compiler will generate a ROM pointer call (XLIB call) for that routine instead of a call-by-address (system call). Names may contain up to 11 characters. This file is included in every RPL source file. By centralizing the external declarations in one file, between-file calls are not at risk from a missing external declaration. -6- The source files in group 2 above contain the configuration code, the user words, and the remaining code for the application. Note that each file in group 2 "INCLUDEs" both files in group 1. The configuration code contains one label that is not NULLNAMEed, because it is referenced by a relative address in the header file GEHEAD.S, to be discussed below. The configuration code is executed as part of a series of events that happen when a System Halt is performed: TITLE Geometry Library Configuration INCLUDE GEROMID.H INCLUDE GEEXTDEC.H ***************************************************************** * Add the Geometry Library ROMPART to the SYSRAMROMPAIR. * The following construction of a binary integer is used * to enable use of the GEROMID equate defined in GEROMID.H. * * NOTE: The label GEcfg is only referenced via a relative address * in the header file GEHEAD so it is being made a "NAMELESS". * If it was going to be referenced from a secondary then it would * need to changed to a "NULLNAME" so that the reference would be * made via a romptr. ***************************************************************** ASSEMBLE =GEcfg RPL :: DOBINT GEROMID XEQSETLIB ( autoattach ) ; -7- The user words are consolidated into one file, in this case GEUSER.S: TITLE Geometry Library User Words INCLUDE GEROMID.H INCLUDE GEEXTDEC.H ***************************************************************** * The user module contains the "xNames" - the user words. These * will be visible to the user. The nibble that precedes each * xName tells the parser that this is a non-algebraic. Note that * the user words are specified with the compiler directive * "xNAME". ***************************************************************** ASSEMBLE CON(1) 8 RPL xNAME ACONE :: CK2&Dispatch REALREAL ( real real ) GEDoACone ; ***************************************************************** ASSEMBLE CON(1) 8 RPL xNAME VCONE :: CK2&Dispatch REALREAL ( real real ) GEDoVCone ; ***************************************************************** There is no requirement that all the user words reside in one file, but there is an advantage. First, the user words (denoted by an xNAME instead of a NULLNAME declaration) will appear in the library menu in the order that the MAKEROM tool encounters them. Secondly placing all the user words in one file you control their order and avoid re-compiling the "check and dispatch" code if only other parts of the code are being changed. -8- The dispatchees of the user words may be in one or more files, to the taste of the developer. In this example, the file GEMAIN.S contains the dispatchees of the user words: TITLE Geometry Library Main Module INCLUDE GEROMID.H INCLUDE GEEXTDEC.H ***************************************************************** * The main module contains the dispatchees of the user words. * Each routine is named with a NULLNAME compiler directive, and * has a corresponding entry in the external declarations file. ***************************************************************** NULLNAME GEDoACone ( %radius %height --> %area ) * Calculates the area of a cone given its radius and height :: DUP %* OVER DUP %* ( r h^2 r^2 --> ) DUPROT %+ %SQRT ( r r^2 SQRT[r^2+h^2] --> ) ROT GEtimesPI %* ( r^2 PI*r*SQRT[r^2+h^2] --> ) SWAP GEtimesPI %+ ( %area ) ; ***************************************************************** NULLNAME GEDoVCone ( %radius %height --> %volume ) * Calculates the volume of a cone given its radius and height :: OVER %* %* GEtimesPI %3 %/ ; ***************************************************************** The file GESUBS.S contains a routine common to both user word dispatchees: TITLE Geometry Library Subroutine Module INCLUDE GEROMID.H INCLUDE GEEXTDEC.H ***************************************************************** * The main module contains the subroutines for the user words. * Each routine is named with a NULLNAME compiler directive, and * has a corresponding entry in the external declarations file. ***************************************************************** NULLNAME GEtimesPI ( % --> %*PI ) * Multiplies real number by PI :: %PI %* ; ***************************************************************** -9- The experienced programmer will note that this use of a subroutine in the file GESUBS.S creates more overhead than is needed - the example is here to emphasize file structures. When the source files are compiled with RPLCOMP, it is important to make sure that the external declarations are generated. For instance, compile the source files as follows: RPLCOMP GEUSER.S GEUSER.A GEUSER.EXT The files in Group 3 are control files for the tools MAKEROM and SLOAD. The MAKEROM tool reads the file GE.MN, and generates a new loader control file, GE.M. MAKEROM is invoked as follows: MAKEROM In this example, the invocation would be: MAKEROM GE.MN GE.M Let's take a careful look at the MAKEROM input file GE.MN: TITLE Geometry Library OUTPUT GE.O LLIST GE.LR CONFIGURE GEcfg NAME GELIB :Geometry Libr ROMPHEAD GEHEAD.A REL GEUSER.O REL GEMAIN.O REL GESUBS.O REL GECFG.O TABLE GEHASH.A FINISH GEEND.A END The first line contains a title command for the list files. The OUTPUT command directs the Saturn output code to the file GE.O. The LLIST command directs the corresponding list report generated by the loader to the file GE.LR. The CONFIGURE command references the label in the configuration code (file GECFG.S). The NAME command is followed by the label text for the library. This text appears in two places: + A menu label in the library menu. To correspond with other library names, the name should be short enough to fit in a menu label, followed by a space and whatever text you like. + In the HP 48 display when the you press [left][LIBRARY], then [left][REVIEW]. -10- The Equation Library Card libraries use five letters, followed by a space, colon, and text, and this example follows that pattern: EQLIB :Equation Libr PRTBL :Periodic Table COLIB :Constants Libr FIN :Finance MES :Mult Eqn Solver UTILS :Utilities GELIB :Geometry Libr It is important to preserve the order of the commands, particularly the relative positions of the ROMPHEAD, REL, TABLE, and FINISH commands. The ROMPHEAD command specifies the name of the header file to be generated by MAKEROM. The REL commands list all the output modules you have created by compiling and assembling the RPL source files. The TABLE and FINISH commands specify the hash table file and rompart-end files that will be created by MAKEROM. The three files generated by MAKEROM must be assembled before the next step. The files generated in this example are GEHEAD.A, GEHASH.A, and GEEND.A. This is the loader control file GE.M generated by MAKEROM: TITLE Geometry Library OUTPUT GE.O LLIST GE.LR **CONFIGURE GEcfg **NAME GELIB :Geometry **ROMPHEAD GEHEAD.A REL GEHEAD.o REL GEUSER.O REL GEMAIN.O REL GESUBS.O REL GECFG.O ** Could not open GECFG.ext **TABLE GEHASH.A REL GEHASH.o **FINISH GEEND.A REL GEEND.o END There are no external routines in GECFG.S, so an external file was not created. The messsage "Could not open GECFG.ext" is therefore harmless. -11- Running SLOAD with the new loader control file GE.M produces a rompart which is ready to link to the HP 48 internal routines. This last step is accomplished with another loader control file, G.M: TITLE Geometry Library OUTPUT GEOLIB OPTION CODE LLIST GEOLIB.LR SUPPRESS XR SEARCH \INCLUDE\ENTRIES.O REL \INCLUDE\BINHD.O REL GE.O CK LIB2FC SYSEND2FC When SLOAD is invoked for this control file, it is important to use the -H option in the command line. This ensures that a code file will be generated, and not a Saturn object file (which includes a header and symbol table). The SEARCH command instructs the loader to read the HP 48 system entries so that the references to internal routines may be filled in. The REL command for the file BINHD.O is the command to include the binary download header. The rompart is filled in next, and the last command fills in the library checksum. The source for the binary download header is not too complex: NIBASC /HPHP48-A/ Just assemble the file and place the resulting BINHD.O file in a convenient place to include it in your projects. The output of the final load, in this case the file GEOLIB, is now ready to download to the HP 48. Guaranteeing proper behavior of a library in all ports can be troublesome. When a "make" tool is used to manage recompilations, the dependencies in the makefile are such that any change to either the library ID or the external declarartions forces a recompile of all source files in the library, ensuring that all references are compiled as rom pointers with the proper library ID. Every time a new routine is added, add the corresponding external declaration to the externals file. The quickest way to verify address-independence is to look in the .lr file (in this case, GE.lr). A reference to a library routine that is address- independent will have two addresses after its name in the cross reference: one for the routine's definition (where the NULLNAME is) and one for its entry in the link table. -12-