For running compiled programs, the operating system must provide a mechanism called "loader" to transfer the exectutable code from a file into memory, perform some adjustments (e.g. relocating the jump and branch addresses and handling command line parameters), and pass CPU control over to the program in memory for execution. This kind of compiled programs also exists for the HP 9845 series and is called "Binary Programs".
Binary Programs are special programs consisting of pure object code. Binary programs are generally used as extensions to the BASIC interpreter, i.e. they implement one or more new BASIC statements. Actually, binary programs are simply machine language programs which were normally written in assembler and which can be used for any purpose, either as complete, self-contained program or as extension to the BASIC command set. The program decides on its own whether it just registers new keywords with proper routines, or executes object code after being loaded, or both. Once a Binary Program has been loaded, it stays resident inside a reserved memory area until there is a soft or hard reset.
The approach how binary programs are used with BASIC program was different to the standard way how it was normally done in other BASIC dialects. One of the differences was, that HP9845 BASIC was quite well protected against any kind of machine address reference, including direct jumps to arbitrary machine addresses. Instead, HP provided means to load object code modules into memory and to add those routines together with the associated keywords to the BASIC instructions set which was already provided by the 9845 LPU firmware.
For a calling BASIC program, there was no difference whether the routine belonging to a special keyword was implemented permanently in ROM or temporarily loaded into R/W memory. Probably, the HP way was a bit more sophisticated and secure than the standard approach with the SYS and USR statements, since the ROM BASIC could be extended with real new instructions and it was'nt too easy to freeze the system accidentally through a jump to the wrong address. On the other side, through the complete abandonment of standard BASIC direct access statements like PEEK, POKE, ADR, SYS and USR, any access from within BASIC to the system resources was completely blocked.
Binary programs can also be used to implement complete applications. The TBIN system test binary is such an example, it works just like any other program, with the difference that it is completely in machine code. The functions provided by this program are driven via menus and keyboard short-cuts.
Binary programs had to meet some rules. The first rule was that it was not possible to specify a certain memory location where the object code should be installed. As a consequence, the object code module had to be designed with fully relocatable code. Another speciality was that each binary module had to have a defined header which holds information about the keyword(s) with which each module routine was invoked, the version information of the module, and the way how the statements can be syntaxed, listed and executed inside a BASIC program.
Binary modules could be saved and loaded in different ways, either explicitely as standalone code (with the LOAD BIN or STORE BIN commands) or implicitely in combination with a BASIC program (see the Software Architecture section for more information about the the usage and structure of binary routines). All binary programs could include special routines which are automatically executed after loading.
Since binary programs could be used to extend the set of statements which was implemented in firmware, it was the ideal way to implement some special functionality which couldn't be performed in BASIC. This includes even low level functionality, which is intentionally not provided by the normal BASIC implementation. One of the most useful example is the PHYREC binary program, which added the PHYREAD and the PHYPRINT statements, through which a direct sector access for any mass storage device was available. Other binary programs provided means to read standard SIF tapes or to access, test and diagnose selected memory areas. Because they - for certain applications - added very useful functionality to the standard BASIC, they are generally still of high interest. The funny side is, that keyword usage in BASIC programs was intentionally protected by 'secured lines' in many cases, in order to hide both purpose and usage for the normal user.
Special importance is due to the TBIN test binary program. This program was generally used by the service personnel in combination with the 09845-65520 Test ROM cartridge. It provides a number of highly useful diagnostics for exercising the different functional areas of a 9845 system and for the identification and isolation of defects.
The overall concept was highly flexible. Binary Programs play a crucial role, because they can be used for
- high performance code (compiled to machine level, no run time interpreter required)
- self-contained code (no external firmware required once loaded, also no option ROMs needed)
- gaining full system level access on both LPU and PPU
- extending or replacing BASIC keywords
- adding new mass storage drivers
- creating hybrid programs containing both machine language and tokenized BASIC code in one single program file
Below are the binary programs in alphabetic order which are known to me. Most binary programs implement more than one keyword, and most keywords accept parameters.
Where to find: Utilities II
ID String: "PHYREC REV B"
Provides low level sector access for any mass storage device which is supported by the unified mass storage system of the HP 9845, including tape, floppy and hard disc drives. PHYREC does all of its operations on the current mass storage device selected by MASS STORAGE IS.
This binary program is one of the most useful binary programs and works on all known 9845B and 9845C systems. For the 9835A/B, a separate version is required. No working version for the 9845A is known. Program source for 9845B/C and 9835A/B is available.
|Description:||Get one record (256 bytes) from the position <record> on current mass storage|
|<record>||Record address on mass storage (starting at record 0)|
|<array>||INTEGER array with 128 entries|
|Description:||Write one record (256 bytes) to the position <record> on current mass storage|
|<record>||Record address on mass storage (starting at record 0)|
|<array>||INTEGER array with 128 entries|
|Binary Program||Package||ID String||Keywords||Short Description||D/L|
|PHYREC||Utilities II||PHYREC REV B||
|The PHYREC program is included in the Utilities II package and is used by programs for file copy or backup operations|
|ONKBD REV B 03-27-79||
ON KBD GOTO
|Allows the use of ON KBD statements in subprograms or functions|
|GPRINT|| Utility Library,
2D Graphics Utilities
|GPRINT REV. A 4/26/79||GPRINT
|Print alpha characters on the graphics display|
|DGRAPH||Utility Library||DUMP GRAPHICS # REV.A 4/9/79||DUMP GRAPHICS||Dump CRT display to a raster scan device (e.g. 2631G printer)|
|KGPRIN||Utility Library||KGPRINT REV. A 8/06/79||KGPRIN
|Print katakana alpha characters on the graphics display|
|LDK45A||Utility Library||LDK45A||LOAD KEY 9845A||9845A to 9845B key file conversion|
|SHOWBN||Utility Library||SHOWBIN REV. A||SHOWBIN||List all currently loaded binary modules which contain header identification|
HP 85 Data Utilities
|SIF REV. A 11/26/79||INTERCHANGE IS
|Provides full access to SIF tapes. See Utility Libraray Manual for usage.|
|AJECT||HPL to BASIC Translator||TREAD 781016||TREAD||?|
|MEMTST||9845B/C Exerciser Tape #1||EXERBIN45B/C REV. A 10/25/79||self starting/ menu driven||Memory exerciser|
|RCKSUM||9845B/C Exerciser Tape #2 (ROMREV)||RCKSUM_DIAG REV. A 6/30/80||RCKSUM||Checksum calculation for ROM diagnostics|
|CIARC||2D Graphics Utilities,
3D Graphics Utilities
|ARC-CIRCLE REV. B 5/15/79||CURVE||Fast circle and arc generator|
|DMPG||2D Graphics Utilities,
3D Graphics Utilities
|DUMP GRAPHICS||DUMP GRAPHICS||Dump CRT on a dot matrix printer|
|RUBBND||9845C Graphics Utilities||RUBBERBAND REV.A 04/21/80||RB ON
|Rubber band software emulation for 9845C|
|79XX||9845B/C Exerciser Tape #1 (7906A)||79xx_DIAG REV. C 10/23/79||SD, STS, POP, HCLR, SK, AR, RC, CL, VF, SM, RDA, WRTD, WFS, INITD, REDD, RFS, RWO, IDY, DSJ, FYSPD, WRTLP, REDLP, DWPL, DRPL, PWPL, PRPL||79xx disc drive diagnostics (provides AMIGO commands as keywords for program and command line use)|
|DEVSTA||9845B/C Exerciser Tape #1 (AUTOST, 9134A)||DEVICE_STATUS REV. A 9/26/79||DSTS <sc>, <ret_status>||Return device status for device <sc>|
|ODESSY||9845B/C Exerciser Tape #1 (CLRGR)||ODESSY_GRAPHICS REV. A 9/26/79||OTEST <ret_memoryplane>, <ret_resultpattern>, <ret_expectpattern>||98770A color graphics memory exerciser. Returns <ret_memoryplane> = 0 if no error, or faulty memory plane plus both expected and returned pattern.|
|WTMEMB||9845B/C Exerciser Tape #1 (ENHGR)||WTMEMB||
WRITE MEMORY <block>:<address>, <value>
|Memory read/write and base conversion utility. WRITE MEMORY and MEMORY can be used on any <block>:<address> combination, or, if 4 ≤ address ≤ 7, as <select_code>:<register> combination. DTO$, DTB$ and DTH$ return a number in octal, binary or hexadecimal notation. OCT converts an octal number into a decimal number.|
|FTBIN||9845B/C Exerciser Tape #1 (ENHGR)||FAST TRANSFER BINARY||TRANSFER [<from_block>:]<from_address> TO [<to_block>:]<to_address>, <size>
COMPARE <from> TO <to>, <size>, <ret_errorflag>
FAST SUM [<block>:]<address>, <size>, <checksum>
CHECK SUM [<block>:]<address>, <size>, <checksum>
|Memory block utility. TRANSFER moves between memory locations and/or arbitrary objects such as integer arrays. COMPARE returns -1 in case both blocks compare in ret_errorflag. FAST SUM does a simple sum on the selected memory area modulo 32768, and CHECK SUM calculates a validation sum like it is used to validate (not identify) 9845 ROMs.|
|TBIN||9845B/C Test Binary||n/a||self starting/ menu driven||Service test binary for in-depth 9845 diagnostics. Lock the AUTOST key to run the rack test automatically after loading.|
The above binary programs can be downloaded here as complete archive, including a disc image with all binaries: 9845-Binaries-081230.zip
All binary program files follow a certain structure with file header, file trailer, a linked list of keywords plus some extra code & data for tables and execution. Binary programs can be either stored in special files of type BPRG or packed together with BASIC program files of type PROG. So if a BASIC program requires certain binary programs to be present, it is good practice to pack these binary programs together with the BASIC code into one single file of type PROG. This is automatically done with each STORE command (i.e. the binaries which are currently loaded into RAM are automatically stored together the the current BASIC program into one single file). Note that storing binary programs together with BASIC code is possible with the STORE command only, not with the SAVE command.
The way back, i.e. separating binary programs from the BASIC code, requires three steps. First the PROG file containing both binary programs and BASIC code has to be loaded with LOAD. Then, the binary programs can be stored separately with the STORE BIN command, and the BASIC program can be stored without binaries using SAVE.
For handling programs of type PROG and BPRG on a PC I wrote a special utility named 'Progalyze'. It can be used to detect binary programs included in PROG files, to extract those binary modules, to get detailed internal information on the PROG files, and even to perform operations on the PROG file like removing line protection. See the 9845 Utilities Section for more information on how to use this utility.
Writing Binary Programs was not intended for the standard user, but rather performed by HP's own engineers. Whereas they can be loaded and stored by the user, writing Binary Programs was a well cept secret within HP. For a good reason, since with Binary Programs the user could gain full access the system. Now, actually, the secret was not cept in the way HP might have intended, or HP gave it intentionally to third party developers. We actually don't know. Fact is that third party companies like Infotech and Structured Software Systems (SSS) had that knowledge and were able to create Binary Programs on their own.
On the other side, there is not one single Binary Program known not developed by either HP itself, Infotech or SSS. As a consequence, there are not as many hown brewn machine language programs available for the HP 9845 compared to other popular platforms such as Commodore or Apple.
Anyway, with some knowledge it is also possible for you today to write a Binary Program. The basic trick is to write an assembler program with the Assembly Execution & Development ROM, use some symbol tables for cardinal numbers, important system parameters and routines, and some kind of BASIC stub program to write the Binary Program code into a file, including the header containing all necessary information for the program loader. But be warned, there is some system and firmware knowledge required to write proper Binary Programs. I am planning to set up a special tutorial for this in the future.
So, writing your own binary programs is a bit tricky, especially when passing parameters from and back to BASIC. Below is a basic understanding of the header structure. The object code part can be produced with the asm45 assembler program. Note that the object code has to be fully relocatable and that each BPRG file starts with an additional size word over all binary routines which are stored in the file. All pointers will be updated automatically when the binary program is installed (i.e. with the LOAD BIN command).
Here is the general structure of a single binary program (all offsets in words):
Start: Pointer to binary program name string at Binary_name (normally including revision ID)
Start+1: Binary program size in words (reserved memory space)
Start+2: Pointer to 1st primary keyword (or -1 if no primary keyword)
Start+3: Pointer to 1st secondary keyword (or -1 if no secondary keyword)
Start+4: On load LPU execution address (or RET 1 (=$F081) if no LPU execution routine)
Start+5: PPU stolen word routine (or RET 1 (=$F081) if no PPU stolen word routine)
Start+6: On load PPU execution address (or RET 1 (=$F081) if no PPU execution routine)
Start+7: Mass storage link to new drivers (or 0 if no link)
Start+8: Reference point, used to re-calculate all other pointers within the binary program
Start+9: Next group of pointers to relocate during load (or 0 for no pointers)
Start+10: Number of relocatable pointers
Start+11: Relocatable pointer #1
Start+12: Relocatable pointer #2
Binary_name: Binary program name string (max. 32 characters, terminated with $80, word align padding with $0)
Keyword: Pointer to next Keyword (or to -1 for last keyword)
Keyword+1: Keyword string (n*2 characters, word align padding with $20)
Keyword+n: Offset pointer to keyword execution code in upper memory block (with MSB set)
Keyword+n+1: JMP to keyword syntax scanner (syntax routine)
Keyword+n+2: JMP to keyword lister (list routine) or RET 1 for no parameters
Execution: Execution code starts here, terminates with RET 2 in case of success or with RET 1 for error
Syntax: Syntax scanner routine starts here
Lister: Lister routine starts here (or RET 1 for no parameters)
Binary program files are terminated by a trailing word holding the size of the whole binary, plus some record boundary fillers. Since binary programs can only be installed via the LOAD BIN command, first the object code is to be produced (e.g. with the asm45 utility), then the header/trailer structure and all pointers have to be added. Finally the module can be saved to disc as a file of type BPRG.
STORE BIN saves all binary programs which are currently resident (i.e. the full memory area currently in use for Binary Programs) into a single file, preceeded by a single word containing the total size of all modules in words.
For parameter syntax checking, parameter listing and parameter data reference the OS provides a couple of utility routines, however I've not yet figured out how it works in detail. Of course, all utility routines used by the BASIC interpreter (e.g. for CRT output or keyboard input) can be used from within a binary program, too.
When writing Binary Program code, it should be taken into account, which target machine (9845A, 9835A/B, 9845B or 9845C) it should be running on. In general, 9845B and 9845C code just differ when doing direct I/O with the CRT (text and graphics), but the 9845A and the 9835A/B use a completely different firmware with different code entry addresses. Also, it must be decided which part of the code should run on the PPU, and which on the LPU.