Home   • Persönlich •

< Persönlich

< Persönlich: Projects

> Intro

> Hardware

• Manual

> Interfacing

> Terminal


— Projects: UZE, Manual —

UZE Version 1.02 of 30.December 1995

With Version 1.00 to 1.01, two additional public suboutines were added and the source code rearranged. Version 1.02 has a full handshake built in, a feature that was missed in the previous versions. The scheme empoyed is described below.

The UZE bare bones basic input output system version 1.02 has a size of 1984 bytes, 261 bytes more than the last released version 1.00. The EPROM-checksum is 0000-7FFF: 495E and 0000-07FF: C15E.

UZE Version 2.xx of 31.October 1995

Version 2xx is an extension of the Version 1.xx. It introduces named programs. Routines can be accessed using their names. There may be sub-names of many nestings and up to 3 unsigned integer parameters can be passed to the programm. This has been made possible without any major change over version 1.xx. Only the A-command has a new vector on initialization. This vector can be reset and the UZE runs just like version 1.xx.

Version 2.00
Version 2.00 is the test version that runs outside the 32K EPROM. It must be loaded into RAM. The added program part has an origin of 40,000. It can be loaded using UZETERM:

^T {File to load:} UZE200.UZE {Load address:} 0

The first 32,768 bytes are just loaded over the EPROM and do not have any effect. From address 40,000 in RAM, the extensions are loaded. The extensions include version 2.01 and 2.1a. AUXY-command execution vector is not altered, since it is still in EPROM of version 1.xx. It must be manually set by:


Now, the AUXY command can be used in the new and enhanced fashion.

Version 2.01
Version 2.01 includes the enhancements that come with the extended AUXY-command use. Two public delay subroutines are included and a label where to jump to, to output a string of characters defined in memory.

Version 2.1a
Version 2.1a is just like version 2.01 but includes dedicated named procedures for the ADA-950225 dual channel 8-bit analog-digital-analog converter with a 1-bit in- and output. The eternal loop as defined by DumyAp and ILoopV is initialized for HPMAN. ADA-950225 can run in the HPMAN-mode without intervention and controls the Selective Voltmeter / Waveanalyzer HP3581C autonomously. However, the automatic can be interrupted to access more features of the ADA-950225 and to use the UZE fully in version 2.01.


The BIOS provides the most simple housekeeping operations, 7 commands, 3 public procedures, and a couple of public subroutines. The UZE BIOS makes extensive use of system variables through which the system can be configured to special needs. There are enough tools built in to test most of the software just by using a terminal program on the host platform and with additional downloadable code, software can be deviced to test the hardware fully.

The UZE BIOS uses Z80 interrupt mode 2. The interrupt precedence is CTC-SIO-PIO. Interrupt mode 0 and 1 may be set by a loaded application. The vector for mode 0 and 1 interrupts and for non-maskable interrupts can be set by loading the appropriate system variables. The system has a instruction queue return stack (IQRS) which can hold 31 instructions (actually 32, but the RET-instruction for interrupt mode 1 will be overwritten). If a program executes, it should push the interrupted programm address onto the IQR-stack (see IQPush), after verifying (IQTest) that there is enough room to hold it and, if necessary, dump the oldest entry (IQDump).

Memory Map

The system word and byte variables, the system buffer and instruction queue stack are identified later in this document.

0000RST0 Cold-Boot address
0008RST1 Console Input Status restart
0010RST2 Console Output Status restart
0018RST3 Cleared-To-Send Status restart, patched to 0074h
0020RST4 Console Input restart
0028RST5 Console Output restart
0030RST6 Interrupt Mode-0 restart. Loads addr from IM0Vec
0038RST7 Interrupt Mode-1 restart. Loads addr from IM1Vec
0040CmdLst Command List for T, E, D, U, H, M, A and Else
0050IM2Lst Interrupt Mode-2 table
0064PubVec constant points to PubPro (100 decimal)
0066Non-maskable interrupt vector. Loads addr from NMIVec
006D3 spare bytes
0070Dummy Application
0074Patch from RST3, enables transmitter after CTS high
007E2 spare bytes
0080CoolSt Cool-start address. System setup, destructive boot. WarmSt,
SioIsr, Commands, Procedures, Subroutines, SVInit-Table, Version
7FFFLast firmware address
8000Soft application and data storage area 32,512 bytes minus stack
FEFFStack bottom, grows backward to 8000
FF00SysWrd System Words, 42 unsigned word variables
FF54SysByt System Bytes, 14 unsigned byte variables
FF62AllInt All interrupt, 10 interrupt service jumps
FF80SysBuf System Default Buffer 64 bytes
FFC0IQRS Instruction Queue Return Stack (32 commands)
FFFFRET-instruction for command A. May be overwritten with care.
LabelUseful Hardware AddressesAddr
ctc0CTC channel 016
ctc1CTC channel 117
ctc2CTC channel 218
ctc3CTC channel 319, used
sioadSIO-A data24
sioacSIO-A command25
siobdSIO-B data26, used
siobcSIO-B command27, used
pioadPIO-A data28
pioacPIO-A command29
piobdPIO-B data30
piobcPIO-B command31
wdtsrWDT st-by reg240
wdtcrWDT command241
dciprDaisy-chain Int precedence reg244

General Considerations

Any application should run as an infinite loop which can be interrupted when a character is received. Interrupt mode 2 should be active and a controlling host computer connected to SIO-B. The BIOS provides for an infinite loop with DumyAp programm in page 0 at 0070h, 112 decimal. DumyAp loads the execution address contained in system variable ILoopV which initially points to DumyAp. The serial interface is set to 9600 baud, no parity, eight data and and one stop bit. If the host runs in a PC-/MS-DOS environment, the communications port can be set with the DOS command

MODE COMn:9600,n,8,1


A command is invoked by its corresponding letter. The entry is case insensitive. This command interrupts the currently running program and this program is re-entered after the command has executed, except for the T-command (see below). Most of the commands need one or more parameters. The first parameter follows immediately after the command letter. A parameter can only have decimal numbers. A parameter must be delimited by any non-numeric character, i.e. a blank, a comma, a full stop (in this document, "," is used if another parameter follows and "." to indicate start of execution). As long as numeric characters are entered as a parameter decimal value, they are accepted up to the first non-numeric character. The numbers are assembled to a 16-bit unsigned word value. If the parameter value entered exceeds 65,535, only the remainder of that value divided by 65,536 will be taken as value. There are no overrun checks. If 100000 is entered, the parameter becomes 34,464. Negative numbers are not accepted. The current command number is stored in system byte variable CurCmd and the preceding one in OldCmd. The command numbers are:

T=0, E=1, D=2, U=3, H=4, M=5, A=6, else=7

T(ASK — Syntax: T<addr>.
A Task is a programm that executes immediately after it is accepted. It replaces the return address on the system stack of the interrupted routine by the new task-address and finishes the interrupt service routine. The ISR ends with a RETI-statement. Interrupts are enabled and execution continues at task-address. This programm must be an infinite loop with the interrupt enabled or must return to a looping programm. System variable ILoopV contains (or at least should contain) an entry address into an infinite interruptable loop.

The parameter <addr>, i.e. the task execution start address, is loaded into system variables CTaddr and CTpntr. CTcntr is reset and CTbyte unknown.

CTaddr=<addr> | CTbyte=? | CTpntr=<addr> | CTcntr=0

E(xecute — Syntax: E<addr>.
A programm is only executed after the interrupted programm terminates. This command pushes the contents of ILoopV onto the instruction queue return stack, dropping the value that has longest be on that stack if there is not room enough to hold the contents of ILoopV. The execution start address of this command replaces the value in the ILoopV system variable. As soon as the interrupted routine finishes and returns to the dummy application, the address contained in the system variable ILoopV is fetched and the loop is exitted. The executing programm should pop back the last value on the IQR-stack and jump to that execution address. The stack pointer for the instruction queue return stack can be found in system variable IQRSP.

Up to 32 programs can thus execute in a nested environment, the last entered will be the first to execute. It should be noted that each new program to execute should pop the return address from the system stack (is on top) and load it into ILoopV. The program then terminates either by jumping to DumyAp or by loading the address contained in ILoopV and jumping there.

The parameter <addr>, i.e. the task execution start address, is loaded into system variables CEaddr and CEpntr. CEcntr is reset and CEbyte unknown.

CEaddr=<addr> | CEbyte=? | CEpntr=<addr> | CEcntr=0

D(ownload to UZE-System — Syntax: D<addr>,<count>,<data> … <data> (<count> times <data>).
The Download command expects the number of bytes stated in the second parameter. The data flow will be stored starting at the address stated in the first parameter upwards in memory, i.e. towards higher address. No check is done for data overrunning system variables.

The data bytes may be binary bytes or two ascii hex characters for each byte if D-Flag is set with Mode-command (see below). In case of the default mode, 8-bit data bytes will be accepted. In case of hex-mode, the double number of bytes must be sent, two for each byte. Hex-ascii characters accepted are [0,9], [A,F] and [a,f]. There must be no delimitting character between bytes. If two characters do not make up a valid hex-value [00,FF], this byte is translated and stored as zero.

The parameter <addr>, i.e. the download start address, is loaded into system variables CDaddr and CDpntr. CDcntr is reset and CDbyte to count. After download is finished, the system variables are set as:

CDaddr=<addr> | CDbyte=<count> | CDpntr=<addr>+<count> | CDcntr=0

CDaddr and CDbyte are unchanged and reflect the entered parameters. CDpntr points to the first memory location not used by the downloaded data. If the download was successfull, CDcntr is zero, otherwise, the remaining, non-received number of bytes are stored here.

Download is a non-interruptable programm which returns to the interrupt service routine in the firmware. From here, it returns to the interrupted programm.

U(pload from UZE-System — Syntax: U<addr>,<count>. (data follows immediately).
Sends number of bytes stated in second parameter starting at memory address stated in first parameter and continuing towards the higher memory to the requesting host computer. The data sent may be 8-bit binary bytes or, if U-Flag was set with Mode-command, as two byte hex-ascii characters. In case of binary data, each byte follows its previous one. In case of hex-asci, the double number of bytes are sent. There are no delimiters between the hex-ascii characters that make up a byte.

The parameter <addr>, i.e. the upload start address, is loaded into system variables CUaddr and CUpntr. CUcntr is reset and CUbyte to count. After upload is finished, the system variables are set as:

CUaddr=<addr> | CUbyte=<count> | CUpntr=<addr>+<count> | CUcntr=0

CUaddr and CUbyte are unchanged and reflect the entered parameters. CUpntr points to the memory location of the first unsent byte. If the upload was successfull, CUcntr is zero, otherwise, the remaining, non-sent number of bytes are stored here.

Upload is a non-interruptable programm which returns to the interrupt service routine in the firmware. From here, it returns to the interrupted programm.

H(ello — Syntax: H.
This command uploads the number of bytes contained in system variable CHbyte from address contained in CHaddr. Initially, CHaddr points to byte variable Prompt and CHbyte is 1. The variables CHaddr and CHbyte may be changed with two DNLD-commands, each sending two bytes that make up a word. The contents of these variables may also be changed by any application program. The public procedure WhoWho (see below) is provided to upload the last BIOS-version.The system variables CHaddr, CHbyte, CHpntr and CHcntr are left unaltered.

M(onitor, Mode and Call — Syntax: see below
This command is a multimode command working with bit-flags. It was mainly conceived with low-level debugging in mind when only a terminal program can be used with the UZE system. There are four flags, all of which are initially reset:

  • U-Flag: Bit 0 set. Upload will be in hex-ascii. If reset, binary.
  • D-Flag: Bit 1 set. Download will be expected in hex-asci. If reset, binary.
  • P-Flag: Bit 2 set. Expects 4 parameters to be entered.
  • C-Flag: Bit 3 set. Calls a public subroutine.

Mode 0, U- and/or D-Flag: – Syntax: M<mode> where <mode> = [0,3]
The parameter <mode> is stored in system byte variable MonMod and can be in the range [0,3].

Mode P-Flag: – Syntax: M<mode>,<p1>,<p2>,<p3>,<p4>.
The parameter <mode> is stored in system byte variable MonMod and can be in the range [4,7]. The parameters p1 through p4 are stored in the system variables as shown below:

CMaddr = <p1> | CMbyte = <p2> | CMpntr = <p3> | CMcntr = <p4>

Mode C-Flag: – Syntax: M<mode>,<addr>.
The parameter <mode> is stored in system byte variable MonMod and can be in the range [8,15]. Flag-P cannot execute because Flag-C takes precedence, otherwise, <mode> could only be [8,11]. In this mode, any subroutine can be jumped to. Since a subroutine traditionally ends with a RET-statement, it returns to the end of the interrupt service routine as any other command also does, but without a return statement. This mode is extremely powerfull for debugging programms.

A(uxillary Version 1.xx — Syntax: A[to be defined].
This is a special command that can be user tailored. It works like a command, but its execution address is vectored. The system variable CAaddr holds the vector where command execution should beginn. Upon startup of the UZE system, CAaddr holds the memory top address (65'535). There, a Z80 RET-instruction can be found. This returns the command to the interrupt service routine and continues from there at the interrupted program.

If the user wishes to define a command with AUXY, this command must end with a RET-instruction. On the top of the stack is the address of the ending part of the interrupt service routine.

A(uxillary Version 2.xx — Syntax: Aname{,name{,name{,name ...{,param1{,param2{,param3}}}}}}.
With version 2.xx of the UZE firmware, the execution address of AUXY in CAaddr is loaded with ExtCmd. An input string is expected to be entered into SysBuf. The string cannot exceed 63 bytes. The string can contain names (alpha characters only, they are converted to upper case [A;Z]), up to 3 un-signed integer parameters (numeric characters only [0;9]), delimitting commas (,) and a termination (.). All other characters are ignored.

A name must be specified in memory and may only contain alpha characters. Names and parameters must be delimitted with a comma (,). The input must be terminateds by a full stop (.). If an attempt is made to enter more than 63 characters, the 64th is forced to be a full stop and parsing of the input line starts. If a name cannot be found, a question mark (?) is uploaded, the parsing and AUXY-command is terminated.

The AUXY-command functions exactly as the E(xecute command does (see EXEC). The start address of the currently running and interrupted program can be found in ILoopV. This address is pushed onto the interrupt queue return stack (IQRS) and the CFA (code field address of the named procedure is put into ILoopV. AUXY then returns from interrupt and the old programm resumes. As soon as it terminates, the new procedure takes action.

Notes on defining names

The search for names assumes a linked list. The label must hold a constant pointing to the next routine, creating a linked list. After the pointer constant, the name must be defined as a string of bytes in upper case alpha characters. The last alpha character must be lower case to indicate the last character. This makes possible the use of variable length names. After the last (lower case) character, either executable code begins, or a constant is stored.

The first word defined must be "VEr" (Version, see VER). The first free location must hold 3 bytes with the value of 255.

Versio:  dw  LISTVW   ;label, points to next program
         db  'VEr'    ;name
          ....        ;CFA or PFA (Code or Parameter Field Adress)
ListVW:  dw  SETVAR
         db  'LISt'
SetVar:  dw  Dummy
         db  'SETVAr'
Dummy:   dw  65535     ;can be burnt with new next address
         db  255       ;can be burnt with new name

Each named programm called via the A-command must terminate by jumping to the label Home: JP HOME. This will clean up the stack and pops the IQRS. See also description of non-public subroutines CmdNam, CmdAdr and FetPar.

Special Subroutines for Extended A-command use (Version 2.xx)

Special subroutines had to be developped for the extended A-command. They are described below:

This subroutine waits for input from the downloader. If the character received is an alpha character [A;z] it is converted to upper case and inserted in the SysBuf (system buffer); if it is a numeric character [0;1] or a delimitter comma [,],it is also stored in the SysBuf. If a full stop is entered [.], querying is terminated. Any other code received is ignored. If the SysBuf pointer-counter reaches the end of the 64 byte SysBuf, a full stop is automatically inserted, input query aborted and returned.

This is the input buffer parser. It is derived from the 10K EXT_BA (extended BASIC) Issue 2, Version 2.2 of June 24, 1984 for SCBS (Sinclair Based Computer System, a derivate of the Sinclair ZX81). However, the Ext_Ba parser expected the length of the routine rather than a pointer to the next routine. Using a linked list with a pointer to the next routine is an improvement over a linked list using the routines length.

The character in ROM is compared against the character found in the SysBuf. If it does not match, the ROM-character is converted to upper case and another test is performed. If it matches, the word could be found.

The start for match in ROM starts at the address pointed to by the HL register pair. HL must point to the first label which holds the address of the following word. The system variable param4 (SysWrd+70) must point to one byte before the first byte to be checked in the SysBuf. Parsing stops at the delimitting character (, or .). The address of the delimitting character is stored in param4 variable.

If the word could be found, its PFA or CFA is stored into system variable param1 (SysWrd+64) and the A register set to 1.

If the search was unsuccessfull, the A register returns 0.

On Entry: HL = Start of list in ROM
(param4) = address of delimitter before name or SysBuf-1
On Exit: (param4)= address of delimitter following name
If A=1: success --> (param1) = CFA or PFA of name
if A=0: no success

Fetch Parameter is the parameter parsing subroutine. It makes use of AscBin subroutine to calculate the unsigned integer value of a numeric string. It expects in param4 system variable (SysWrd+70) the address of the delimitting byte before the number in the SysBuf. The A register gives the number, in which location the received value has to be stored. This might either be param1, param2 or param3 (SysWrd+64, +66, +68) for A=[1;3].

Only the last 5 numeric characters make up the integer. No overrun check is performed. See the GetAsc subroutine description for a detailed description of assets and limitations.

On Entry: A = parameter number [1;3]
(param4) = address of delimitter before parameter or SysBuf-1
On Exit: (param4) = address of delimitter following parameter
(param1) = unsigned integer (if A was 1 on entry)
(param2) = unsigned integer (if A was 2 on entry)
(param3) = unsigned integer (if A was 3 on entry)

The Z80 CPU can be interrupted by four different interrupts, one is a hardware, nonmaskable one, the other three are maskable ones. For interrupt handling, this BIOS provides the following means.

Non-Maskable Interrupt NMI: the non-maskable hardware generated interrupt perforrms a restart to 0066h or 102 decimal. This interrupt may be used. After restarting the UZE, the vector contained in system NMIVec is fetched and a jump performed. NMIVec is loaded with the warm start address. A return from non maskable interrupt is performed (RETN). If the vector is altered for a user defined NMI-service routine, it must end with a RETN instruction. Hardware should be built with a NMI-switch (as e.g. UZE-930117 and ADA-950225).

Interrupt Mode 0: the software generated maskable interrupt mode 0 is 8080 compatible. Upon reset, this mode is selected and performs a RST0 (restart 0). This performs a cold boot. The interrupting device usually generates the restart number (0 to 7) but this BIOS uses restarts 0 through 6 already for various purposes (see restarts, below). However, number 7 is vectored and may be altered (RST-30h). The service routine address is contained in system variable IMode0, on reboot set to IM0Ret-label. There, interrupts are enabled and a return from interrupt instruction (RETI) is executed. The user may read IMode0 variable and may jump to the address contained therein at the end of his service routine.

Interrupt Mode 1: This software generated maskable interrupt performs a restart to memory location 38h. Here, the vector is fetched from the system variable IMode1. IMode1 initially contains the address IM1Ret. Here, interrupts are re-enabled and a RETI instruction executed. To modify this, proceed exactly as described for interrupt mode 0.

Interrupt Mode 2: This system uses this interrupt mode. Whenever an application prefers to use another interrupt mode, it must be reset to mode 2 by the instruction IM2 at the end. This mode must have the I-register set for the high address byte pointer, the low address byte pointer is issued by the interrupting device. The I-register is set to 0 by the BIOS upon startup. A vector table in page zero is provided and the device should issue the following vector:

50h = 80d : SIO-A
52h = 82d : SIO-B used by BIOS
54h = 84d : PIO-A
56h = 86d : PIO-B
58h = 88d : CTC-0
5Ah = 90d : CTC-1
5Ch = 92d : CTC-2
5Eh = 94d : CTC-3
60h = 96d : spare
62h = 98d : spare

These vectors point to a predefined, but not fully programmed jump list. This jump list is in RAM and may be altered by the user. It starts at FF62h (65,378d). Each entry is 3 bytes long and the same sequence as in the vector table applies. Except for SIO-B (2nd entry), all vectors are initialised to jump to the warm start boot entry. If a service routine is plugged in, it should end with a RETI instruction.

The restarts are used by the BIOS for fast and code efficient handling of small routines, particularly for console input and output handling.

RST0 = RST-00: COLDST Cold boot restart. Sets up UZE system. Continues at coolboot to test memory, than at warm boot to reset stack and initialise SIO-B for RS232C operation.

RST1 = RST-08: INSTAT – Input Status. This restart has two modes, selected with the carry flag. If the carry flag is set on entry, this restart is only exitted when a character is pending for read. If the carry flag is not set, the zero flag returns the state of the receiver. If the zero flag is reset (NZ), a character is pending, if the zero flag is set (Z), the receive buffer is empty. The status can be queried in 7.5 µs. If return on pending character is desired and a character is pending already, the flag is returned within 8.75 µs. The port is queried each 10.25 µs.

On Entry: CY  
On Exit: A = SIO-B RR0 (bit 0)
NZ = byte ready in rx-buffer
Z = rx-buffer empty
On Entry: NC 
On Exit: A = SIO-B RR0, always NZ

RST2 = RST-10: OTSTAT – Output Status. This restart has also two modes that work in exactly the same manner as InStat. If the carry flag is set on entry, the restart returns to the caller only after the transmit buffer is empty. If the carry flag is reset on entry, the zero flag reports on the tx-buffer status. If the zero flag is reset, the tx-buffer is empty, if it is set, there is still an unsent character in the buffer. The status can be queried in 7.5 µs (NC). If return on empty tx-buffer is demanded, the flag can be returned within 8.75 µs if the buffer is already empty when the restart is entered. The port is queried each 10.25 µs.

On Entry: CY  
On Exit: A = SIO-B RR0 (bit 2)
NZ = tx-buffer empty, ready for next
Z = tx-buffer holds unsent byte
On Entry: NC 
On Exit: A = SIO-B RR0, always NZ

RST3 = RST-18: CTSTAT – Clear-To-Send Status. Again a restart with two modes, selected with the carry flag. If the carry flag is not set, the zero flag returns the state of the CTS-line within 7.5 µs. A set zero flag (Z) indicates a high (i.e. invalid) CTS-line. If the zero flag is not set (NZ), the CTS-line is valid (i.e. low). If the carry flag is set, the restart returns only after the CTS-line is low. The restart enables the transmitter at the moment, the CTS-line becomes active. The transmit enable must only be performed, when the CTS-line changed to high during a transmission. If the carry flag is set on entry and the CTS-line is low, the restart returns to the calling routine within 8.75 µs. The CTS-line is checked each 20.25 µs.

On Entry: CY  
On Exit: A = SIO-B RR0 (bit 5)
NZ = CTS active low
Z = CTS inactive high
On Entry: NC  
On Exit: A = SIO-B RR0, always NZ

RST4 = RST-20: CONIN – Console Input. This restart waits until there is a character available in the receive buffer, reads it and returns with it in the A register. It makes use of InStat restart with the carry flag set. Provided a character is pending in the receive buffer, the byte is returned within 17.75 µs.

On Entry:    
On Exit: A = byte read, Flags = CY, NZ

RST5 = RST-28: CONOUT – Console Output. This restart waits until the CTS-line is low and the transmit buffer void. If both conditions are true, the byte contained in register A is sent. Immediately after putting the transmit character into the transmit buffer, the routine returns to the caller. This frees the CPU for other tasks while the byte is assembled to a serial data stream ant sent off. Provided the CTS-line is active and the transmit buffer ready to accept a data byte, the restart returns within 28 µs.

On Entry: A = byte to send
On Exit: A = byte being sent, Flags = CY, NZ

RST6 = RST-30: Mode-0 restart. Describtion see above.

RST7 = RST-38: Mode-1 restart. Describtion see above.

Address access of public procedure and subroutines locations

The address 100 decimal (64h) holds the firmly set system constant PubVec. This constant can be read using a upload command from address 100 as:


Note that the lower byte is first, the higher last. They have to be reversed and converted to decimal. With this address, the table containing the execution addresses of the various procedures and subroutines can be dumped or selectively uploaded with the U-flag set. The list contains the addresses of the following entry points (each entry is 2 bytes long):

UseEndaddress of first unprogrammed byte in EPROM
UZEVeraddress of oldest EPROM-version. WhoWho uses this.
WhoWhoWho-is-Who public procedure
DumpItDump-It public procedure
CrLfPCarriage return Line feed public procedure
AscBinascii to binary public subroutine
BinAscbinary to ascii public subroutine
BinDecbinary to decimal public subroutine
ChkAFcheck A to F public subroutine
ChkNbrcheck number pubic subroutine
CrLfScarriage return line feed public subroutine
DecBindecimal to binary public subroutine
Div16divide by 16 public subroutine
DmpAscdump ascii public subroutine
GetAscget ascii public subroutine
IQDropinstruction queue return stack drop public subroutine
IQDumpinstruction queue return stack dump public subroutine
IQPopinstruction queue return stack pop public subroutine
IQPushinstruction queue return stack push public subroutine
IQTestinstruction queue return stack test public subroutine
LinDmpline dump public subroutine
MulTenmultiply by ten public subroutine
RTSgoRequest-To-Send go, active low public subroutine
RTStopRequest-To-Send stop, inactive high public subroutine
SetParset paramter public subroutine
SetVarset variable public subroutine
SDelayshort delay with 6.5µs resolution *)
LDelaylong delay with 426ms resolution *)
Versi0entry label to upload an ascii string terminated by code 255 *)
*) Version 2.xx only.

Public Procedures

Public procedures are an extension of the predefined commands. They can, however, not be directly accessed via a command letter. To use them, they must be prepared. So far, only three such procedures are defined and are an invaluable help to debugging.

None of the public routines alters any of the CPU-registers. If they are executed using the E-command (which they should), the instruction queue return stack is popped properly. Each procedure returns to the address contained in ILoopV.

The carriage return line feed procedure uploads two bytes with the values 13 and 10. (CrLfP procedure should not be confused with subroutine CrLfS.)

Usage: E<crlfp>.

Without a memory dumper, life is dumb and very hard indeed for a system tester. DumpIt can dump memory by uploading hex ascii characters from any memory location for any number of bytes (within the range of 16 bits, of course). If zero bytes are given to dump, at least one line with 16 bytes (77 data bytes) is uploaded. At the start of the procedure, a carriage return, line feed sequence is issued.

aaaa : bb bb bb bb bb bb bb bb  bb bb bb bb bb bb bb bb | cccccccccccccccc<cr><lf>
aaaa : bb bb bb bb bb bb bb bb  bb bb bb bb bb bb bb bb | cccccccccccccccc<cr><lf>
aaaa : bb bb bb bb bb bb bb bb  bb bb bb bb bb bb bb bb | cccccccccccccccc<cr><lf>

The DumpIt procedure must be prepared with the mode 4 command and executed with the execute command. The parameter <addr> gives the start address and <bytes> the number of bytes to dump. This value is divided by 16. The resulting number of lines will be uploaded, except if <bytes> is lower than 16, one line will be uploaded anyway. The <dummy> parameters may be any value and are not used.

Usage: M4,<addr>,<bytes>,<dummy>,<dummy>,E<DumpIt>.

After DumpIt has terminated, the system variables in the mode-block are altered:

CMaddr=<addr> | CMbyte=<bytes> | CMpntr=<addr>+<bytes> | CMcntr=<dummy> | Param3=CMpntr

Who is who prepares the H-command to upload the latest EPROM version. The oldest version pointer can be linked to a more recent one. These text strings can be anywhere in memory, even in RAM, provided the list links to it. After procedure WhoWho has executed, the H command will be different.

Usage: E<whowho>.

Public Subroutines

A public subroutine can be called externally by using the M8 command or called internally. No CPU-register is altered by the public subroutine. Calling them externally is usually for debugging and testing purposes only.

To access a public-declared subroutine from outside through the E(xecute command, be sure to embed the call within a small program:

  absadr:  call public-subroutine
           call iqpop
           jp   dumyap

and use as: E<absadr>.

The system variable HexChr is expected to hold two valid hex-ascii characters. These characters are converted to a binary value which is returned in the A-register. If the two characters in the system variable HexChr do not make up a valid hex-value, the A-register returns zero. Note that the character for the high nibble is at the place of the low byte of a variable (at the lower memory address) and the lower nibble character at the high byte position (higher in memory). No CPU-register can be read by any command. There is not much sense in calling this subroutine by command M8. Except for register A which returns the value and the flag register, no other CPU-register is changed.

This subroutine expects a byte in the A-register. It is converted into 2 hex-ascii characters which are stored in system variable HexChr. Since the CPU-registers cannot be loaded by any command, it makes no sense calling this subroutine with the M8-command. Rather, the user may wish to access it by a running application program. No registers are altered by this subroutine. The two characters found in system variable HexChr are arranged such, that the high nibble character is at the low byte position. Assuming that the converted byte should be output, the following procedure could be used:

  ld   hl,(HexChr)  ;get 2 hex-ascii characters into HL-register
  ld   a,l          ;get high nibble ascii-character
  rst  conout       ;upload it
  ld   a,h          ;get low nibble ascii-character
  rst  conout       ;upload it

An unsigned word integer is expected in SysBuf+0, low byte at SysBuf+0, high byte at SysBuf+1. This unsigned integer value is converted into a five byte string holding the decimal representation of the value with leading zeroes, if any. SysBuf+2 holds the ten-thousands, SysBuf+3 the thousands, etc. and SysBuf+7 the units. This string can be uploaded as thus: U65410,5.

This public subroutine checks whether the byte contained in the A-register is in the range of 'A' through 'F' or 'a' through 'f'. It is used together with ChkNbr to test for a valid hex-ascii nibble character. The character test is case insensitive. No registers are altered except the flag register which returns the outcome of the test:

NC:character in A-register is ['A','F'] or ['a','f']
CY:character in register-A is any other character

This public subroutine checks whether the byte contained in the A-register is in the range of '0' through '9' or 'a' through 'f'. It is used together with ChkAF to test for a valid hex-ascii nibble character. The character test is case insensitive. No registers are altered except the flag register which returns the outcome of the test:

NC:character in A-register is ['0','9']
CY:character in register-A is any other character

This public subroutine should not be confused with the public procedure CrLfP. CrLfS could be called externally with the M8-command, the use of CrLfP with the E-command is preferred, however. The primary objective of the inclusion of this subroutine is to be called from a running application. It sends the codes 13 (0Dh, carriage return) and 10 (0Ah, line feed) in this order to the console. No register is altered by CrLfS. Note that the subroutine waits until the CTS-line is ready and returns only when line feed character is loaded in the tx-buffer.

A five byte numeric string is expected in SysBuf+2 through SysBuf+7. Leading zeroes are mandatory if the value represented by the string is less than 10,000. This string is converted to an unsigned binary value stored in SysBuf+0 and SysBuf+1. The low byte is in SysBuf+0, the high one in SysBuf+1. The decimal value can be downloaded as: D64410,5,00023. Note: No check for number validity is performed.

This extremely fast public subroutine divides the unsigned integer value in the BC-register pair by 16 in just 31.25 µs in any case. The BC-register pair returns the integer result of the division. Except for the B- and C-registers, no other CPU-register is changed.

This is a part from the DumpIt public procedure. It converts from the address contained in Param3 16 bytes to their respective ascii character. Byte values below 32 decimal and above 127 decimal are representated by a dot ".". This string is stored at SysBuf+0. The string is 18 bytes: 16 for the ascii-characters and 2 for the cr/lf-sequence. The address contained in Param3 is incremnted 16 times. See also LinDmp public subroutine.

Gets from the console one parameter and stores its binary 16-bit value in either system variable Param1 through Param4. The Param-variable must be set by loading the system byte variable Param0 with a number 1 to 4.

Usage: D<Param0>,1,<paramer_number>E<GetAsc>,<value>.

<parameter_number> must be in the range [1,4] binary! <value> is the value to be found in variable Param<parameter_number>.

Example: M2,D<Param0>,1,04E<GetAsc>,12345.

It is easier to send the parameter number in hex than in binary from a terminal. M2 does this. 04 selects the variable Param4 which will contain 12345 after E-command has executed.

Decrements IQRSP instruction queue return stack pointer system variable twice and system byte variable IQRSDC once. Just as IQPop, but without transferring the IQRS top to ILoopV.

Moves the full IQR-stack (31 entries) up in memory as to make room for a new value to be IQPushed. The oldest entry is lost on the stack. The stack pointer (IQRSP) is not altered by IQDump! It points to the stack top.

Fetches IQRSP and decrements it twice. Fetches value on IQRS and stores it in variable ILoopV. The system byte variable IQRSDC is decremented once.

Fetches system variable IQRSP, which contains the instruction queue return stack pointer and copies the content of ILoopV onto the stack. The variable IQRSP is incremented twice. The system byte variable IQRSDC (IQRS depth counter) is incremented once.

Increments system variable IQRSP twice. If IQRSP becomes zero, the next push would erase the RET-instruction for the A command. However, one push is still possible. The system byte variable Prompt will hold the character '<' if the IQR-stack runs low. This variable should be checked after an IQTest.

This subroutine converts 16 bytes to formatted hex-ascii characters. It takes the start address of the first byte from system variable Param3. This variable is not updated. At the end, the system buffer (SysBuf) contains 58 bytes in this format:

aaaa : bb bb bb bb bb bb bb bb  bb bb bb bb bb bb bb bb |

This subroutine is called by public procedure DumpIt. The integrity of every CPU-register is absolutely assured. The subroutine AscDmp which also takes the start address from Param3 converts the 16 bytes into 7-bit ascii characters and stores them in the system buffer as 18 bytes in the form:


Bit 7 of each byte is stripped and byte values below 32 (20h) and the value 127 (7Fh) will be represented as ".". The pointer in Param3 is advanced by 16 at the end. This subroutine is called by the public procedure DumpIt. Although no register is altered by DmpAsc, it is not declared as a public subroutine. Its execution address cannot be found in the list pointed to by system constant PubVec.

Multiplies the unsigned integer contained in the HL register pair by ten within 15.5 µs.

On EntryHL = vlaue to multiply by 10
On ExitHL = HL x 10
BC = HL x 2
No other registers are altered, except the flag register.

This public subroutine can be used for receive handshake. The current UZE-BIOS does not need receive handshake. Even in mode 1 or 3, ascii-upload, the U-command cycles one byte in under 200µs, leaving the CPU idle for more than 800 µs. However, in other applications, it might be necessary to signal to the host to suspend transmission, which can be done with RTStop public subroutine. To indicate to the host that the UZE routine is again ready to receive data, the Request-To-Send line is put to active low with this subroutine. At the same time, the transmitter is enabled and any pending external status error or interrupt condition is cleared. See also RTStop.

If the receiving program cannot accept data sent by the host fast enough, this routine puts the Request-To-Send line high. The sending terminal should be put on hold. The reaction time is 16 µs. This means that from the moment any programm detects data overflow, it takes 16µs until the RTS-line becomes high. The time of the call-instruction (4.25 µs) is included in the 16µs. After 21 µs, the program calling program can continue its task. The following programm can be used to test the RTS-line go to high and back to low:

      (8000)  0034          org 32768        ;start of code in RAM
8000  0E1B    0035          ld  c,siobc
8002  0665    0036          ld  b,00000101   ;select WR5
8004  1603    0037          ld  d,3
8006  3E68    0038          ld  a,01101000b  ;RTS off + TX
8008  ED41    0039          out (c),b
800A  ED79    0040          out (c),a
800C  21FFFF  0041          ld  hl,65535
800F  2B      0042  loophl: dec hl
8010  7C      0043          ld  a,h
8011  B5      0044          or  l
8012  20FB    0045          jr  nz,loophl
8014  15      0046          dec d
8015  20F8    0047          jr  nz,loophl
8017  3E6A    0048          ld  a,01101010b  ;RTS- on + TX
8019  ED41    0049          out (c),b
801B  ED79    0050          out (c),a
801D  CD5903  0051  tstout: call IQPop
8020  C37000  0052          jp   dumyap
              0053  ;
8023  (0000)  0054          end

This programm can be implemented and run by the following procedure:


Parameters are initially entered into Param1 to Param4 system variables. Param1 is designated as C?addr, the command start address, Param2 as C?byte, the number of bytes expected, Param3 as C?pntr, the command buffer pointer, and Param4 the C?cntr, the counter variable. The question mark "?" stands for any of the valid command characters T, E, D, U, H, M and A. The start address and buffer pointer are set to the same value with this subroutine and the counter set to zero.

  • Param1 = Param1
  • Param2 = Param2
  • Param3 = Param1
  • Param4 = 0

This subroutine loads the received parameters into the appropriate variables of the desired command. SysByt+5 must contain the command number (CmdNbr), i.e. T=0, E=1, D=2, U=3, H=4, M=5 and A=6.

  • C?addr = Param1
  • C?byte = Param2
  • C?pntr = Param3 (= Param1, if SetPar was called prior to SetVar)
  • C?cntr = Param4 (= 0, if SetPar was called prior to SetVar)

SDelay (Version 2.xx)
Short-Delay routine expects in HL number of delay loops and returns it with 0 when done. HL can be in the range [0;65535]. HL=0 produces the longest (65,536) and 1 the shortest delay. The resolution (HL-HL+1) is approximately 6.5 µs.

HL=1: 17.25 µs
HL=0: 426 ms
Delay time: (HL-1) x 6.5 µs + 17.25 µs

LDelay (Version 2.xx)
Long-Delay routine expects in HL number of delay loops and returns it with 0 when done. HL can be in the range [0;65535]. HL=0 produces the longest (65,536) and 1 the shortest delay. The resolution (HL-HL+1) is approximately 425.9 ms.

HL=1: 426 ms
HL=0: 27.85 s
Delay time: HL x 425.9 ms
  • See EDN (Electronic Design News), August 18, 1983: Cass R. Leward; Z80 routine provides wide delay range.
  • See 10K-BASIC for SBCS Programmers Manual, June 1994: Subroutines Inside Ext-Ba: Delay. Horo Wernli.

Versi0 (Version 2.xx)
This entry label provides a means to upload an ascii-character string. The HL register pair must point to the 1st character to be uploaded. The text may have any character code, except code 255, which marks the end of the string.

System Variables

There are 48 unsigned word variables defined in high RAM from FF00 to FF53, 65,280 to 65,363 as listed below. The first variable MCFadr holds the result of the memory integrity test, which is performed while cool booting up. The value should be 32,767 (7FFFh). The last EPROM-address certainly fails a data write. Any other address indicates the first memory location that failed the RAM-test. RAM-testing is aborted upon the first occurence of a failed memory cell.


System Byte Variables

There are 14 unsigned byte variables defined in high RAM from FF54 to FF61, 65,364 to 65,377.

+ 0Prompt|+ 4MonMod|+ 8spare|+12spare
+ 1CurCmd|+ 5CmdNbr|+ 9spare|+13spare
+ 2OldCmd|+ 6IQRSDC|+10spare|  
+ 3Param0|+ 7spare|+11spare|  

Interrupt Mode 2 Execution Addresses

This is the jump-to table for the interrupts. The jump list can be modified. It is defined in high RAM from FF62 to FF7F, 65,378 to 65,407. The interrupt vector list is at Int2Tbl 0050, 80.

+0jpwarmstSIO-A0050 = 80FF62
+3jpsioisrSIO-B0052 = 82FF65
+6jpwarmstPIO-A0054 = 84FF68
+9jpwarmstPIO-B0056 = 86FF6B
+12jpwarmstCTC-00058 = 88FF6E
+15jpwarmstCTC-1005A = 90FF71
+18jpwarmstCTC-2005C = 92FF74
+21jpwarmstCTC-3005E = 94FF77
+24jpwarmstSpare10060 = 96FF7A
+27jpwarmstSpare20062 = 98FF7D

System Buffer and IQRS

The System buffer starts is at FF80 to FFBF, 65,408 to 65,471 and is 64 bytes long. The instruction queue return stack is at FFC0 to FFFF, 65,472 to 65,535 and is also 64 bytes long. It can hold 32 IQPush-ed instructions. However, the last memory location at FFFF, 65,535 holds the return instruction for the A-command. SysBuf = SysWrd+128.

+ 0SysBuf
+ 64IQRS top
+128IQRS bottom

Source Code

The listing generated by the Cromemco macro assembler, the symbol table and the cross reference list is provided in the Adobe Portable Document Format (PDF): uze201.pdf (38 pages).

  © 2004 - 2018 by Horo Wernli.