MBLe Manual
MBLe Manual
16 January 2016
Revision History
CONTENTS
1. MBLe IMPROVEMENTS ................................................. 3
2. INSTALLATION ...................................................... 4
3. SUPPORTED DEVICES AND PORT ADDRESSES .............................. 4
5. OPERATING PROCEDURES .............................................. 6
6. ERROR INDICATIONS ................................................. 8
7. 8800b TURNKEY MODULE COMPATIBILITY ................................ 8
APPENDIX A - SOURCE CODE LISTING ..................................... 9
16 January 2016
88 MBLe PROM vers. 3.00 1
1. MBLe IMPROVEMENTS
MBLe works exactly the same as the Altair MBL PROM, except for the
following changes:
1. Turnkey Module Compatibility
MITS’s MBL PROM will not work with any of their Turnkey Modules
except the oldest revision of these boards, without MITS’s 88-SYS-
CLG rework, because the Turnkey Module will disable the PROMs upon
the first IN instruction from the sense switch port. (Some versions
of the Turnkey Module will disable the PROMs upon any IN or OUT
instruction. See Section 7.)
To fix this, MBLe relocates itself to the same 256-byte page of RAM
where its stack is located, and runs from there - never executing
any IN or OUT instructions while running in PROM. SO, unlike MITS’s
MBL PROM, MBLe works correctly will all Turnkey Module versions.
2. Position Independence
MBLe 3.0 and later PROMs will run from any 256-byte page of memory,
except page 0.
3. High-Speed Serial Tape Reader Support
MBL’s 88-HSR load device has been replaced with support for loading
from the second port on the 88-2SIO. Thus, the front panel sense
switch setting that was originally assigned to the 88-HSR (see
below) now selects the 88-2SIO’s second serial port as the load
device. This makes it possible to load Altair BASIC and other files
using a high-speed RS-232 tape reader connected to the 88-2SIO’s
second port, and still use the 88-PIO’s first port for the Terminal.
4. OAE OP-80 Support
An initial read is performed from both the 88-PIO and the 88-4PIO
Port 0, to clear data handshake latches in external devices such as
the Oliver Audio Engineering OP-80 paper tape reader. This makes
loading files (e.g. Altair BASIC) with the OP-80 work correctly.
5. MAKEALT and UBMON Punched File Support
Both MBL and MBLe skip over the checksum loader that is normally
punched on an Altair BASIC tape between the tape leader and the
actual file to be loaded. (MBL contains its own checksum loader that
is independent of the particular file being loaded.) On a tape that
does contain a checksum loader, the binary value of the leader
character is also the length (in bytes) of the checksum loader. MBL
and MBLe both use this leader value to count bytes as it skips over
the checksum loader.
However, tapes that were punched using MAKEALT, or with older
versions of UBMON “D” command, may not contain a checksum loader.
Such tapes just has a long string of leader nulls before the file to
16 January 2016
88 MBLe PROM vers. 3.00 3
MBLE.PRN
;===============================================================
; MBLe - Enhanced Multi Boot Loader for the Altair 8800
;
; Loads and runs an Altair 'Absolute Binary File' from input
; transfer port specified by the Sense Switch settings.
; Normally run in PROM at address 0FE00h. However, since
; version 3.00 the PROM is position independent and can run
; at most any 256 byte boundary.
;
; Vers. Date Author Comments
; 1.00 01Sep2013 M. Eberhard
; Disassembled from MITS EPROMS
; 1.01 01Sep2013 M. Eberhard
; Modified to support e.g. a fast reader on the 2SIO's 2nd
; port, instead of a MITS HSR
; 1.02 03Sep2013 M. Eberhard
; initial read from parallel ports to clear latches
; (fixes the OP-80)
; 1.03 09Sep2013 M. Eberhard
; fix for no checksum loader (see 7 below.)
; 1.04 12Mar2014 M. Eberhard
; Search for end of RAM before initializing ports, so the
; UART has time to finish echoing, upon entry
; 1.05 05Jun2014 M. Eberhard
; Ignore sense switch A11 (see 9 below)
; 2.00 11Aug2014 M. Eberhard
; Major rewrite: copy to RAM and run from there, so it works
; with an 8800b Turnkey Module too
; 2.01 24Aug2014 M. Eberhard
; Also move I/O port setup to RAM code, so that MBLe will
; work with older Turnkey modules, with just the 88-SYS-CLG
; rework (Which may disable PROM on any IN or OUT
; instruction). Also tidy up comments.
; 3.00 16Jan2016 M. Douglas
; Make the PROM position independent by making the RAM
; sizing and relocation routines position independent.
; Change the address relocation technique to free up the
; space required for the position independent code.
; Eliminate the two second start-up delay by sizing RAM with
; a page-by-page search instead of a byte-by-byte search.
;
; Written to assemble with ASM by Digital Research.
;
; Thanks to Geoff Harrison for his MBL disassembly, which I
; plagerized freely.
;
;** Differences between MITS MBL and MBLe **
;
; 1) The code starts off by relocating itself to the highest
; page of RAM that is found, so that it will still work on
; a Turnkey Module that phantoms the PROMs upon a IN from
; port FFh (the Sense Switches), or any IN or OUT
; instruction (i.e. 88-SYS-CLG Turnkey Modules)
; 2) All HSR support is eliminated, including 88-4PIO Port 1
; initialization and code for starting the HSR transport.
; 3) The second 88-2SIO port (port 1) is initialized.
; 4) The 88-HSR entry in PTABLE is replaced with an entry for
; the 8-2SIO port 1. See sense switch table below.
; 5) PTABLE has an 8th entry, which is the same as the 7th
; (2SIO port 1). Testing for illegal sense switch setting
; is eliminated.
Page 1
MBLE.PRN
; 6) An initial read is performed for both the 88-PIO and the
; 88-4PIO Port 0, to clear data handshake latches in
; external devices such as the OP-80 paper tape reader
; 7) If the leader character is 0, then no checksum loader
; will be skipped.
; 8) The end-of-memory hunt to find the end of RAM occurs before
; the I/O ports get initialized, instead of afterwards. This
; gives time for the UART to finish transmitting the echo of
; e.g. the 'T' character, when entering MBLe from UBMON.
; 9) Sense switch A11 is ignored when getting the load device,
; rather than generating an I error. This allows A11 to be
; used for something else - e.g. selecting a boot disk.
;===============================================================
; Program Notes
; Since the 8800b Turnkey Module disables PROMS whenever an IN
; instruction accesses port FFh, this code cannot execute from
; PROM - at least not from the point where the Sense Switches
; are read onwards. Additionally, some versions of the Turnkey
; Module are broken, and will disable PROM when *any* IN
; instruction is executed. This means that MITS's MBL, as well
; as versions 1.xx of MBLe, will not work in a Turnkey Module.
;
; MBLe 3.00 Strategy:
; 1) Search the memory space for the highest actual RAM, as
; MITS's MBL did. This page of memory will be used not only
; for the stack, but also for the relocated MBLe code.
; 2) Copy code into the high RAM page that was found in step 1.
; (This is called the RAM Execution Page.) The high byte
; of addresses are relocated to the RAM execution address
; as the bytes are copied.
; 3) Jump to the RAM code, and run from there - never to
; return to PROM.
;
; The RAM page is laid out as follows:
; * The high portion (From RAMPAG up to FFh) contains the
; relocated MBLe code
; * Immediately below this is the stack, initialized to RAMPAG
; and growing downward. (Note that a PUSH decrements the
; stack pointer before writing to the stack.)
; The stack therefore has as much space as is occupied by the
; bit of code that executes from PROM: plenty of room.
;
; Although this uses more memory in the highest page of RAM,
; it will behave the same as MITS's MBL, because both programs
; still abort with an "M" error if a Load Record attempts to
; write anywhere into the page that contains the stack.
;
;===============================================================
; An Altair 'Absolute Binary File' has 4 sections, which may be
; separated by any number of nulls. These sections are:
;
; 1) The Leader, which comprises 2 or more identical bytes, the
; value of which is the length of the Checksum Loader.
;
; 2) The Checksum Loader, which is a program that is normally
; used to load the subsequent sections
;
; 3) Zero or more Load Records, each structured as follows:
; Byte 0: Sync Byte = 3Ch (identifies a Load Record)
; Byte 1: NN = number of data bytes in record
; Byte 2: LL = Load address low byte
; Byte 3: HH = Load address high byte
; Bytes 4-NN+3: NN data bytes to store at HHLL, NN>0
Page 2
MBLE.PRN
; Byte NN+4: CC = checksum of bytes 2 through NN+3
;
; 4) The Go Record, structured as follows
; Byte 0: Sync Byte = 78H (identifies the Go Record)
; Byte 1: LL = low byte of go address
; Byte 2: HH = high byte of go address
;
; Altair file Leaders and Checksum Loaders are specific to
; both the version of the particular software and the memory
; size. For example, the Checksum Loader for 4K Basic 3.2 is
; different than the Checksum Loader for 8K Basic 3.2. And
; both the Leader and Checksum Loader for 8K Basic 3.2 are
; different than those for 8K Basic 4.0.
;
; MBL and MBLe are able to read any such Altair file by simply
; skipping over the Leader and Checksum Loader, and loading
; the Load and Go Records directly.
;
; MBLe chooses its input port based on the front panel Sense
; Switches <2:0>, using the conventions set up in Basic 4.X,
; more or less.
;
; Device bits 2:0
; 88-2SIO Port A (2 stops) 000b
; 88-2SIO Port A (2 stops) 001b
; 88-SIO 010b
; 88-ACR 011b
; 88-4PIO 100b
; 88-PIO 101b
; 88-2SIO Port B (2 stops) 110b
; 88-2SIO Port B (2 stops) 111b
;
; Prior to Basic 4.0, MITS used different Sense Switch settings
; to specify the console device. You can load an older tape
; with MBLe by setting the switches according to the above
; table and starting the load. After MBL has skipped over the
; Checksum Loader on the tape and has begun to load the Load
; Records (but before the load completes) change the Sense
; Switch settings as required by the earlier version of Basic
; (or other program) that you are loading.
;--------------------------------------------------------------
; 8080 EQUATES
;--------------------------------------------------------------
00CA = JZOP EQU 0CAH ;JZ OPCODE
00C2 = JNZOP EQU 0C2H ;JNZ OPCODE
;--------------------------------------------------------------
; ALTAIR ABSOLUTE BINARY FILE EQUATES
;--------------------------------------------------------------
003C = ALTPLR EQU 3CH ;PROGRAM LOAD RECORD
0078 = ALTEOF EQU 78H ;EOF/GO ADDRESS RECORD
0055 = ALTBNR EQU 55H ;BEGIN/PROGRAM NAME (NOT SUPPORTED)
000D = ALTBND EQU 0DH ;END-OF-NAME MARK (NOT SUPPORTED)
;--------------------------------------------------------------
;SENSE SWITCH EQUATES
;--------------------------------------------------------------
00FF = SSWTCH EQU 0FFH ;FRONT PANEL SWITCH REGISTER
0007 = LDMASK EQU 007H ;LOAD DEVICE MASK <-ME (WAS 00FH)
;--------------------------------------------------------------
;88-2SIO EQUATES
;--------------------------------------------------------------
;88-2SIO REGISTERS
0010 = S2CTLA EQU 10H ;ACIA A CONTROL OUTPUT PORT
Page 3
MBLE.PRN
0010 = S2STAA EQU 10H ;ACIA A STATUS INPUT PORT
0011 = S2TXDA EQU 11H ;ACIA A TX DATA REGISTER
0011 = S2RXDA EQU 11H ;ACIA A RX DATA REGISTER
0012 = S2CTLB EQU 12H ;ACIA B CONTROL OUTPUT PORT
0012 = S2STAB EQU 12H ;ACIA B STATUS INPUT PORT
0013 = S2TXDB EQU 13H ;ACIA B TX DATA REGISTER
0013 = S2RXDB EQU 13H ;ACIA B RX DATA REGISTER
;ACIA CONTROL REGISTER BITS
0001 = SIOIDR EQU 00000001B ;INPUT DEV RDY (RX BUF FULL)
0004 = SIOPE EQU 00000100B ;PARITY ERROR
0008 = SIOFE EQU 00001000B ;FRAMING ERROR
0010 = SIODOV EQU 00010000B ;DATA OVERFLOW
0080 = SIOODR EQU 10000000B ;OUTPUT DEV RDY (TX BUF EMPTY)
;--------------------------------------------------------------
;88-ACR (AUDIO CASSETTE RECORDER) EQUATES
;NOTE: THE ALTAIR 88-ACR IS BUILT AROUND AN ALTAIR 88-SIO
;--------------------------------------------------------------
;88-ACR REGISTERS
0001 = ACRIDR EQU 00000001B ;INPUT DEV RDY (RX BUF FULL)
0004 = ACRPE EQU 00000100B ;PARITY ERROR
Page 4
MBLE.PRN
0008 = ACRFE EQU 00001000B ;FRAMING ERROR
0010 = ACRDOV EQU 00010000B ;DATA OVERFLOW
0080 = ACRODR EQU 10000000B ;OUTPUT DEV RDY (TX BUF EMPTY)
;--------------------------------------------------------------
;88-4PIO EQUATES
;NOTE: THE 88-HSR USES PORT 1 OF THE 88-4PIO
;--------------------------------------------------------------
;88-4PIO REGISTERS
0020 = P4CA0 EQU 20H ;PORT 0 SECTION A CTRL/STATUS
0021 = P4DA0 EQU 21H ;PORT 0 SECTION A DATA
0022 = P4CB0 EQU 22H ;PORT 0 SECTION B CTRL/STATUS
0023 = P4DB0 EQU 23H ;PORT 0 SECTION B DATA
0024 = P4CA1 EQU 24H ;PORT 1 SECTION A CTRL/STATUS
0025 = P4DA1 EQU 25H ;PORT 1 SECTION A DATA
0026 = P4CB1 EQU 26H ;PORT 1 SECTION B CTRL/STATUS
0027 = P4DB1 EQU 27H ;PORT 1 SECTION B DATA
;--------------------------------------------------------------
;RELOCATION EQUATES
;--------------------------------------------------------------
; ORG statement
; Run-time relocation of addresses is done by replacing any
; byte that matches the MSB of the ORG address with the MSB
; of the destination RAM address. This requires that the value
; of the ORG MSB never appears in the assembled code other
; than as the MSB of an address. FD00 works well for this.
Page 5
MBLE.PRN
FD00 org 0FD00h
00FD = ADRMARK equ ($ SHR 8) ;address mark value
0080 = STACK0 equ 80h ;page zero stack
;==============================================================
; Start of Code
;==============================================================
; Move code from PROM to RAM. If a byte matches the MSB of the
; assembled ORG address (i.e., it is an address MSB), then
; it is replaced with the destination RAM MSB.
;--------------------------------------------------------------
; Patch the GETBYT routine with the correct parameters for the
; load port that is specified by Sense Switches 2:0
; On Entry & Exit:
; h = d = RAM Execution Page
;--------------------------------------------------------------
FD59 DBFF in SSWTCH ;read sense switches
;This also disables PROMS...
FD5B E607 ani LDMASK ;bits specifies load device
FD5D 87 add a ;2 bytes/entry
FD5E C6ED adi PTABLE and 0FFh ;Look up in PTABLE
FD60 5F mov e,a ;de=PTABLE((SWITCHS) <2:0>)
FD61 1A ldax d
FD62 2EE6 mvi l,(GBDP+1) and 0FFH ;Data port addr place
FD64 1F rar ;move jnz flag int carry
FD65 77 mov m,a ;install data port addr
FD66 2EDF mvi l,(GBSP+1) and 0FFh ;Status port addr place
FD68 3D dcr a ;stat port = data port-1
FD69 77 mov m,a ;install stat port addr
FD6A 1C inr e ;next table entry is
FD6B 1A ldax d ;..the status port mask
FD6C 2EE1 mvi l,(GBMASK+1) and 0FFh ;status mask place
FD6E 77 mov m,a ;install stat port mask
FD6F D275FD jnc ITSJZ ;test jnz flag
FD72 2C inr l ;jnz right after mask
FD73 36C2 mvi m,JNZOP ;install jnz opcode
;------------------------------------------------
; Flush external data latches for e.g. the OP-80
; or flush garbage from UARTs
; On Entry & Exit:
; d = RAM Execution Page
;-------------------------------------------------
FD75 CDE5FD ITSJZ: call GETNOW
;--------------------------------------------------------------
; Skip over leader - a sequence of identical bytes, the value
Page 8
MBLE.PRN
; of which is the length of the checksum loader. If the value
; is 0, then there is no loader to skip, so go get records.
; On Entry:
; d = RAM Execution Page
; On exit:
; c = checksum loader length
; d = RAM Execution Page
; The 1st byte of the checksum loader has already been read
;--------------------------------------------------------------
FD78 CDDEFD call GETBYT ;get 1st byte
FD7B 4F mov c,a ;number of bytes in loader
FD7C B7 ora a ;Null leader?
FD7D CA8FFD jz RCHUNT ;y: skip leader
;---End-------------------------------------------------------
;Error handler:
; Save error code and address at beginning of memory
Page 10
MBLE.PRN
; Hang writing the error code forever, to all known consoles.
;-------------------------------------------------------------
FDC8 320000 ERDONE: sta 00000H
FDCB 220100 shld 00001H
FDCE FB ei
FDCF D301 ERHANG: out SIOTXD ;SIO
FDD1 D311 out S2TXDA ;2SIO
FDD3 D305 out PIOTXD ;PIO
FDD5 D323 out P4DB0 ;4PIO port 0
FDD7 C3CFFD jmp ERHANG
;---Subroutine-----------------------
; Get 2-byte word from transfer port
; On Entry:
; b=checksum so far
; On Exit:
; l = next byte
; a = subsequent byte
; b := b+a+l
;------------------------------------
FDDA CDDEFD GETWRD: call GETBYT
FDDD 6F mov l,a
; Fall into GETBYT
;---Subroutine-----------------------------------------
; Wait for and get a byte from the transfer port
; This code gets modified once the input port is known
; On Entry:
; b=checksum so far
; On Exit:
; a = input character
; Z set if received byte matched previous checksum
; b := b+a
;------------------------------------------------------
GETBYT:
FDDE DB00 GBSP: in 0 ;(Status Port Address)read status
FDE0 E600 GBMASK: ani 0 ;(Port Mask)
FDE2 CADEFD jz GETBYT ;(may become jnz) wait for data
; Fall into GETNOW
;---Subroutine-----------------------------------------
; Get a byte from the transfer port
; This code gets modified once the input port is known
; On Entry:
; b=checksum so far
; On Exit:
; a = input character
; Z set if received byte matched previous checksum
; b := b+a
;------------------------------------------------------
GETNOW: ;call to flush port
FDE5 DB00 GBDP: in 0 ;(Data Port place)get data byte
FDFD end
Page 12