Producing a machine-language program for the 9830 is covered here in two parts:

Resources


Program Creation & Assembly

The 9830 firmware provides for dynamically extending the user environment with features in the form of additional commands, functions and statements. In writing a machine-language program for the 9830, one writes assembly source to formulate the program as such a feature. The source must include linking tables to form the whole into a binary-block. There may be multiple features in one binary-block. The linking tables include the keywords for the new features, and allow the firmware to find the new machine code.

The assembly source can be assembled using the asm9830 assembler to produce 9830 machine code.

For an example of machine language routines and binary-block formatting at the assembly level, see the Machine Binary-Block source or listing.

IMPLEMENTING COMMANDS

One-word commands are easy to implement. See the SPUTNIK command in the MBB for a trivial example. Commands with additional syntax/arguments will require more examination of the firmware, we haven't needed the ability as yet.

IMPLEMENTING FUNCTIONS

Single-argument functions can be implemented easily as the firmware provides default parsing for such. See the MPEEK(a) function in the MBB for an example of how to get the argument and return a value.

Two-argument functions add some complexity, the function code must be forced to an offset beyond ~ 30 to inhibit the default single-arg parsing, and one must do the parsing in your own code. See the MPOKE(a,n) function in the MBB as an example. The MBB includes a routine for two-arg parsing.

Note that functions can be used directly at the user command level, not just within BASIC equations.

IMPLEMENTING STATEMENTS

We have not tried implementing statements as yet. A single-word statement is probably much like a command, additional statement syntax would require specific parsing.

BINARY BLOCKS

A binary-block is a dynamically-linked machine-language extension to the firmware. The block is seen as the addition of commands, functions and statements at the user level.

A binary-block can be implemented as a binary tape file loaded into RAM via the LOAD BIN command, as a ROM card, or as a ROM cartridge.

Binary-blocks can vary in length but in memory the end of the block is always aligned to the end of certain pages. The end-of-page alignment is the key to the dynamic linking. The block pages are the memory pages corresponding to the 4 ROM card slots, the 5 ROM cartridge slots, the last page of RAM, and two pages fixed in the firmware ROM.

The diagram to the right presents the linking organisation, using file 0 of the System Test tape loaded into the RAM block-page as an example. As a binary tape file, file 0 has been loaded at the very top of RAM, the end-of-file aligned to the end-of-page at MAW. The octal addresses are values for a machine with 8K of RAM, the decimal addresses are the address within the page. File 0 is 511 words long and pages are 1024 words, so the file was loaded starting at the 513'th word in the page.

MAW is the maximum RAM word, and is determined by a scan of RAM pages at reset / system initialisation.

LWAM is the last available RAM word for BASIC programs and data, and is set in accordance with the file size when the binary file is loaded.

While there is only one RAM block-page, I have not seen a limitation on the size of that block, so it may be larger than one page.

For ROM block-pages the same organisation applies, with the addresses changed to reflect the page corresponding to the slot the ROM is plugged into, and the size of the block limited to one page.

The two firmware block pages contain the built-in commands, statements and functions of BASIC and the cassette tape operations.

The last word of the block is a Block ID, and is used (in part) to detect the presence of a block in a block page. A Block ID of zero indicates an empty block.

The 3 words preceding the block ID are offsets to symbol tables for the extensions provided by the block. The symbol table offset is relative to the location of the offset itself. When looking for a command, statement or arithmetic function symbol, the system scans the last word of block pages looking for present blocks, and then searches the appropriate symbol table in the block for the symbol. The byte following a symbol contains a symbol-code, the symbol-code value is used as a negative offset from the beginning of the symbol table to obtain an offset to the executable machine code (entry point) for the symbol. The entry point offset is relative to the location of the offset itself. The symbol code byte includes two flag bits for End-Of-String and End-Of-Table.

Known Block IDs
Use Block ID Source
empty block 000000 PM
- 002000
String 004000 PM
Matrix 006000 PM
Plotter 010000 PM
BASIC Predefs 012000 PM
Tape Predefs 014000 PM
Terminal 016000 P
Mass Memory 020000 M
Advanced Prog. I 022000 M
- 024000
Extended I/O 026000 PM
- 030000
- 032000
- 034000
Advanced Prog. II 036000 M
- 040000
- 042000
- 044000
- 046000
(MBB) 050000 S
- 052000
- 054000
- 056000
- 060000
- 062000
- 064000
- 066000
- 070000
System Test Tape 072000 T
- 074000
- 076000
P = Patent
M = Memory dump
T = Tape dump
S = Selection
The Block ID value is of consequence, an initial chosen value of 0x5AA5 worked for commands but resulted in Error 1 (memory configuration error) when a function was incorporated in the block. The value seemed to be accepted for parsing but the error results when reverse-parsing and execution. Changing the ID to 026000 allows the function to execute. The Block ID is probably combined with the symbol-code to produce a unique function ID when BASIC statements are tokenised.

The BlockScan program provided with the MBB scans and lists the blocks in a system.


Loading the Program into the 9830

There are two ways of getting a binary-block into the 9830:

Here is an example of an interaction to assemble and load a program into the 9830 via the MPSI Server.
On the host:

       host$ asm9830 -a pgm.lst -o pgm.f98 pgm.s
       host$ tp9830
       TP9830> load pgm.f98
       TP9830> save pgm.t98
       TP9830> quit
       host$ mpsiServer -t pgm.t98
         -- MPSI Server: start, ^C to terminate.
         -- MPSI Tape: image file loaded, 1234 bytes.
On the 9830:
       LOADBIN #9,0
       NEWCMD

In the above:


The Sputnik Test Program

The binary-block linking details were derived from reading the patent firmware listing. To test it an absolutely minimal test program - something just enough to give an indication it was running - was written, hand-assembled, written to a cassette via the 9865 drive with I/O adapter, and loaded into the 9830. Sputnik was a 3 instruction program that beeps intermittently.

Sputnik is now included in the MBB.