|
— 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:
M3.D65336,2,fd9cM0.
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 UZE BIOS
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.
-
| Addr | Firmware |
| 0000 | RST0 Cold-Boot address |
| 0008 | RST1 Console Input Status restart |
| 0010 | RST2 Console Output Status restart |
| 0018 | RST3 Cleared-To-Send Status restart, patched to 0074h |
| 0020 | RST4 Console Input restart |
| 0028 | RST5 Console Output restart |
| 0030 | RST6 Interrupt Mode-0 restart. Loads addr from IM0Vec |
| 0038 | RST7 Interrupt Mode-1 restart. Loads addr from IM1Vec |
| 0040 | CmdLst Command List for T, E, D, U, H, M, A and Else |
| 0050 | IM2Lst Interrupt Mode-2 table |
| 0064 | PubVec constant points to PubPro (100 decimal) |
| 0066 | Non-maskable interrupt vector. Loads addr from NMIVec |
| 006D | 3 spare bytes |
| 0070 | Dummy Application |
| 0074 | Patch from RST3, enables transmitter after CTS high |
| 007E | 2 spare bytes |
| 0080 | CoolSt Cool-start address. System setup, destructive boot. WarmSt,
SioIsr, Commands, Procedures, Subroutines, SVInit-Table, Version |
| 7FFF | Last firmware address |
-
| Addr | Software |
| 8000 | Soft application and data storage area 32,512 bytes minus stack |
| FEFF | Stack bottom, grows backward to 8000 |
| FF00 | SysWrd System Words, 42 unsigned word variables |
| FF54 | SysByt System Bytes, 14 unsigned byte variables |
| FF62 | AllInt All interrupt, 10 interrupt service jumps |
| FF80 | SysBuf System Default Buffer 64 bytes |
| FFC0 | IQRS Instruction Queue Return Stack (32 commands) |
| FFFF | RET-instruction for command A. May be overwritten with care. |
-
| Label | Useful Hardware Addresses | Addr |
| ctc0 | CTC channel 0 | 16 |
| ctc1 | CTC channel 1 | 17 |
| ctc2 | CTC channel 2 | 18 |
| ctc3 | CTC channel 3 | 19, used |
| sioad | SIO-A data | 24 |
| sioac | SIO-A command | 25 |
| siobd | SIO-B data | 26, used |
| siobc | SIO-B command | 27, used |
| pioad | PIO-A data | 28 |
| pioac | PIO-A command | 29 |
| piobd | PIO-B data | 30 |
| piobc | PIO-B command | 31 |
| wdtsr | WDT st-by reg | 240 |
| wdtcr | WDT command | 241 |
| dcipr | Daisy-chain Int precedence reg | 244 |
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
Commands
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:
CmdNam
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.
ExtAdr
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 |
FetPar
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) |
Interrupts
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.
Restarts
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:
M1.U100,2.
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):
-
| Sub | Description |
| UseEnd | address of first unprogrammed byte in EPROM |
| UZEVer | address of oldest EPROM-version. WhoWho uses this. |
| WhoWho | Who-is-Who public procedure |
| DumpIt | Dump-It public procedure |
| CrLfP | Carriage return Line feed public procedure |
| AscBin | ascii to binary public subroutine |
| BinAsc | binary to ascii public subroutine |
| BinDec | binary to decimal public subroutine |
| ChkAF | check A to F public subroutine |
| ChkNbr | check number pubic subroutine |
| CrLfS | carriage return line feed public subroutine |
| DecBin | decimal to binary public subroutine |
| Div16 | divide by 16 public subroutine |
| DmpAsc | dump ascii public subroutine |
| GetAsc | get ascii public subroutine |
| IQDrop | instruction queue return stack drop public subroutine |
| IQDump | instruction queue return stack dump public subroutine |
| IQPop | instruction queue return stack pop public subroutine |
| IQPush | instruction queue return stack push public subroutine |
| IQTest | instruction queue return stack test public subroutine |
| LinDmp | line dump public subroutine |
| MulTen | multiply by ten public subroutine |
| RTSgo | Request-To-Send go, active low public subroutine |
| RTStop | Request-To-Send stop, inactive high public subroutine |
| SetPar | set paramter public subroutine |
| SetVar | set variable public subroutine |
| SDelay | short delay with 6.5µs resolution *) |
| LDelay | long delay with 426ms resolution *) |
| Versi0 | entry 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.
CrLfP
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>.
DumpIt
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
WhoWho
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>.
AscBin
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.
BinAsc
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
BinDec
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.
ChkAF
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 |
ChkNbr
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 |
CrLfS
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.
DecBin
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.
Div16
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.
DmpAsc
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.
GetAsc
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.
IQDrop
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.
IQDump
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.
IQPop
Fetches IQRSP and decrements it twice. Fetches value on IQRS and stores it in
variable ILoopV. The system byte variable IQRSDC is decremented once.
IQPush
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.
IQTest
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.
LinDmp
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:
cccccccccccccccc<cr><lf>
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.
MulTen
Multiplies the unsigned integer contained in the HL register pair by ten within
15.5 µs.
-
| On Entry | HL = vlaue to multiply by 10 |
| On Exit | HL = HL x 10 |
| BC = HL x 2 |
| No other registers are altered, except the flag register. |
RTSgo
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.
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:
- M2.
D32768,35,0E1B066516033E68ED41ED7921FFFF2B7CB520FB1520F83E6AED41ED79CD5903C37000E32768.
SetPar
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
SetVar
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.
-
| 65,280 | Variable | | | 65,280 | Variable | | | 65,280 | Variable | | | 65,280 | Variable |
| +0 | MCFadr | | | +22 | Cecntr | | | +44 | Chpntr | | | +66 | Param2 |
| +2 | Imode1 | | | +24 | Cdaddr | | | +46 | Chcntr | | | +68 | Param3 |
| +4 | NMIVec | | | +26 | Cdbyte | | | +48 | Cmaddr | | | +70 | Param4 |
| +6 | ILoopV | | | +28 | Cdbptr | | | +50 | Cmbyte | | | +72 | HexChr |
| +8 | Ctaddr | | | +30 | Cdcntr | | | +52 | Cmpntr | | | +74 | IQRSP |
| +10 | Ctbyte | | | +32 | Cuaddr | | | +54 | Cmcntr | | | +76 | spare |
| +12 | Ctbptr | | | +34 | Cubyte | | | +56 | Caaddr | | | +78 | spare |
| +14 | Ctcntr | | | +36 | Cupntr | | | +58 | Cabyte | | | +80 | spare |
| +16 | Ceaddr | | | +38 | Cucntr | | | +60 | Capntr | | | +82 | spare |
| +18 | Cebyte | | | +40 | Chaddr | | | +62 | CAcntr | | | | |
| +20 | Cebptr | | | +42 | Chbyte | | | +64 | Param1 | | | | |
System Byte Variables
There are 14 unsigned byte variables defined in high RAM from FF54 to FF61,
65,364 to 65,377.
-
| 65,364 | Variable | | | 65,364 | Variable | | | 65,364 | Variable | | | 65,364 | Variable |
| + 0 | Prompt | | | + 4 | MonMod | | | + 8 | spare | | | +12 | spare |
| + 1 | CurCmd | | | + 5 | CmdNbr | | | + 9 | spare | | | +13 | spare |
| + 2 | OldCmd | | | + 6 | IQRSDC | | | +10 | spare | | | | |
| + 3 | Param0 | | | + 7 | spare | | | +11 | spare | | | | |
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.
-
| 65,378 | Command | Address | Device | Vector | FF60 |
| +0 | jp | warmst | SIO-A | 0050 = 80 | FF62 |
| +3 | jp | sioisr | SIO-B | 0052 = 82 | FF65 |
| +6 | jp | warmst | PIO-A | 0054 = 84 | FF68 |
| +9 | jp | warmst | PIO-B | 0056 = 86 | FF6B |
| +12 | jp | warmst | CTC-0 | 0058 = 88 | FF6E |
| +15 | jp | warmst | CTC-1 | 005A = 90 | FF71 |
| +18 | jp | warmst | CTC-2 | 005C = 92 | FF74 |
| +21 | jp | warmst | CTC-3 | 005E = 94 | FF77 |
| +24 | jp | warmst | Spare1 | 0060 = 96 | FF7A |
| +27 | jp | warmst | Spare2 | 0062 = 98 | FF7D |
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.
-
| 65,408 | Buffer |
| + 0 | SysBuf |
| + 64 | IQRS top |
| +127 | RET-instruction |
| +128 | IQRS 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).
|