Вы находитесь на странице: 1из 27

;************************************************************************************************************* ;* **** MICROPROFESSOR-1 MONITOR PROGRAM ASSEMBLY SOURCE **** * ;* * ;* COPYRIGHT , MULTITECH INDUSTRIAL CORP.

1981 * ;* All rights reserved. * ;* No part of this software may be copied without * ;* the express written consent of MULTITECH * ;* INDUSTRIAL CORP. * ;* * ;* NOTE: This is the original uPF-1 monitor program source code. The binary output of the assembled code * ;* has been compared byte to byte with the original ROM and it's guaranteed to be 100% OK * ;* * ;* ASSEMBLY PROCEDURE: TASM -80 <ThisFileNameWithExtension> * ;* (Download TASM from: http://home.comcast.net/~tasm/tasmdnl.htm * ;************************************************************************************************************* .EXPORT SCAN,HEX7SG P8255 DIGIT SEG7 KIN PWCODE ZSUM .EQU .EQU .EQU .EQU .EQU .EQU 03H 02H 01H 00H 0A5H 71H ;8255 ;8255 ;8255 ;8255 control port PORT C PORT B PORT A ;Power-up code ;This will make the sum of all monitor codes to be zero I I I I

; The following EQUATEs are used for timing. Their values depend on the CPU clock frequency. ; The uPF--1 clock frequency is 1.79 MHz. COLDEL F1KHZ F2KHZ MPERIOD ; ; ; ; ; .EQU .EQU .EQU .EQU $C9 $41 $1F $2A ;Column delay time for routine SCAN and SCAN1 ;Delay count for 1KHz square wave, used by routine TONE1K ;Delay count for 2KHz square wave, used by routine TONE2K ;1KHz and 2KHz threshold, used by tape input routine PERIOD

The following EQUATEs are used for tape routines. If the quality of the tape recorder is good, the user may change '4 4 2 8' to '2 2 1 4'. This will in fact double the tape data rate. If the quality of tape recorder is poor, the user may change '4 4 2 8' to '6 6 3 12'. This will improve error performance but will slow down data rate. Although the data format is changed, the tape is still compatible in each case because only the ratio is detected in the tape read. .EQU .EQU .EQU .EQU 4 4 2 8

ONE_1K ONE_2K ZERO_1K ZERO_2K

;************************************************************************************************************* ; I/O port assignment (8255 PIO) ; ; PORT A (Address 00H) ; ; bit 7 ----- Tape Input ; bit 6 ----- 'USER KEY' on keyboard, active low ; bits 5,4,3,2,1,0 = Rows of the keyboard matrix (active low inputs) ; ; PORT B (Address 01H): 7 segments (+ decimal point) of display LEDs, active high ; ; bit 7 -- segment d ; bit 6 -- decimal point ; bit 5 -- segment c ; bit 4 -- segment b ; bit 3 -- segment a ; bit 2 -- segment f ; bit 1 -- segment g ; bit 0 -- segment e ; ; PORT C (Address 02H): ; ; bit 7 -- Tape and tone output ; bit 6 -- BREAK enable. NMI (CPU pin 17) will go to low five M1's ; (M1 = Machine Cycle 1) after this bit goes to low. ; This bit is connected to the RESET input of an external counter ; bit 5,4,3,2,1,0 = Columns of the keyboard matrix and also the display matrix, ; they are active high. (bit 5 is the leftmost column) ; ;************************************************************************************************************* ; - CPU RESET ; There are two cases that will generate a RESET signal: ; (i) Power-up ; (ii) 'RS' key pressed ;

; In both cases, the following actions are taken: ; a) Interrupts are disabled and set to mode '0' (IM0). ; Register I is set to 00 ; b) Initial user's PC is set to the lowest RAM address. ; c) User's SP is set to 1F90H ; d) User's I register is set to 00 and user's interrupt flip-flop is disabled ; e) BREAKPOINT is disabled ; f) The contents of 0x1FEE and 0x1FEF (which store an address) are set to 0x0066 ; this will make instruction RST 38h (Opcode FFh) have the same effect as BREAK. ; ; Memory location POWERUP is used to distinguish power-up from RESET key. Location (POWERUP) ; contains random data when the uPF-1 is powered-up, but contains PWCODE (0xA5) thereafter. ;************************************************************************************************************* .ORG LD DJNZ LD OUT ; ; 0 B,0 $ A,90H (P8255),A ;Z80 begins execution at 0000h ;Power-up delay ;Set 8255 chip as: PORT_A=Input, PORT_B & PORT_C=Output. ;The control word to send to command port is 0x90 are cleared to 0. It is necessary to disable

When the control word is sent out to 8255 all output ports BREAK and deactivate all I/O by sending 0xC0 to PORT_C LD OUT LD LD CP CALL A,$C0 (DIGIT),A SP,SYSSTK A,(POWERUP) PWCODE NZ,INI

;Setup initial system's stack ;If the content of location POWERUP is not equal to PWCODE ;then call subroutine INI, otherwise is a 'hot' reset and ;the program continues.

;************************************************************************************************************* ; Here, lowest RAM address are determined by checking wether address 0x1000 is RAM. ; If test is true then user's PC is set to 0x1000, otherwise is set to 0x1800. LD CALL JR LD LD LD HL,1000H RAMCHK Z,PREPC H,18H (USERPC),HL H,0

PREPC:

; Address 28h and 30h are reserved for BREAK (RST 28H) and software BREAK (RST 30h) so ; we must skip the following memory area and resume execution of monitor at location RESET1. JR RESET1

;************************************************************************************************************* .ORG 28H ; ; ; ; ; ; Address 28H is the entry point of BREAK trap. If a location is set as a breakpoint using key 'SBR', what the monitor does is change the content of this location with 0xC7 (Opcode for RST28H) BEFORE transfering control to the user's program. In this way, when the user's program passes over the breakpoint address the monitor takes control of the user's program restoring the original content of the breakpoint location and making everything look transparent to the user. The following instructions make the stack manipulation to achieve this. EX DEC EX LD JR (SP),HL HL (SP),HL (HLTEMP),HL CONT28

RST28:

;************************************************************************************************************* .ORG 30H ; Instruction RST 30H (Opcode 0xF7) is usually used as software break or as a terminator of user's program. ; The effect of this instruction is to save all user's registers and return control to monitor program. RST30: JR NMI

;************************************************************************************************************* ; Reset resumes here. As stated before a jump was necessary to skip locations for handling RST 28H & 30H RESET1: LD JR (USERIF),HL RESET2 ;Set user's I reg. and user's interrupt flip-flop both to 00 ;Again, reset routine must skip reserved memory area.

;************************************************************************************************************* ; The following byte makes the sum of the monitor's ROM to be zero. Is used in self-test routine ROMTEST .BYTE ZSUM

;************************************************************************************************************* .ORG 38H ; ; ; ; ; ; Entry point of RST 38H (Opcode 0xFF) or MODE 1 Interrupt. This routine fetches the address stored at 0x1FEE,0x1FEF and then jumps to this address. At the begining of the monitor program, this address is set to 0x0066 which is the address for NMI service, in that way software break with RST 38H instruction has the same effect as pressing the MONI key, wich also causes a hardware break via NMI. By changing the contents of 0x1FEE,0x1FEF the user can define his own service routine. The next 3 instructions push the contents of this two locations onto the stack. PUSH LD EX HL HL,(IM1AD) (SP),HL

RST38:

; At this point the top of the stack contains the address of the user-defined service routine, so the ; following RET instruction retrieves this address from stack and jumps to it. RET ;************************************************************************************************************* ; This is the continuation of the BREAK service routine, or RST28h CONT28: LD (ATEMP),A

; Since the monitor has changed the contents of user's program at break address (remember the previous ; explanation of what happens when 'SBR' key is pressed) the next 3 instructions restore the original content ; at breakpoint address. BRAD contains the break address and BRDA contains the original data at break address. LD LD LD HL,(BRAD) A,(BRDA) (HL),A

; The following OUT instruction enables the hardware break circuitry (see schematic for further details). ; Enabling it will have the inmediate effect of causing a NMI after 5 M1's. (M1=Machine Cycle 1, which is a ; physical Z80 signal that activates once per each CPU instruction) LD OUT LD LD NOP RET A,10000000B (DIGIT),A A,(ATEMP) HL,(HLTEMP)

;1st ;2nd ;3rd ;4th

M1 M1 M1 M1 instruction at previously set breakpoint is executed. generated and control is then transfered again to the

; Here the control returns to user's program and the ; After finishing executing this instruction, a NMI is ; monitor. RESET2: LD LD HL,USERSTK (USERSP),HL

;Set user's SP

; The TEST address contains a general purpose flag for monitor's own use. Illegal key-in error handling ; routine and automatic zero leading uses this flag. In the next 2 instruction this flag is cleared. XOR LD A (TEST),A

; Data shown in the uPF1 display is stored in a 6 byte data area (one byte for each digit) pointed to by IX. ; In the following instruction, IX is set to show 'upF--1' LD IX,MPF_I

; At this point we are near address 0066h (NMI service address) so we must skip this area. Monitor resumes ; execution at SESSTO JP SETST0

;************************************************************************************************************* .ORG 66H ; Entry point for NMI. NMI will occur when MONI key is pressed (Hardware break) or when user program is ; software-breaked The following instructions save all user's registers and also checks the validity of ; user's stack pointer. NMI: LD (ATEMP),A ;Save A register

LD OUT LD OUT LD RGSAVE: LD POP LD LD LD LD LD PUSH PUSH EXX PUSH PUSH PUSH EXX EX PUSH EX PUSH PUSH PUSH PUSH

A,90H (P8255),A A,$C0 (DIGIT),A A,(ATEMP) (HLTEMP),HL HL (ADSAVE),HL (USERPC),HL HL,(HLTEMP) (USERSP),SP SP,USERIY+2 IY IX HL DE BC AF,AF' AF AF,AF' HL DE BC AF

;Control word to be sent to 8255 ;PORT_A as input, PORT_B and PORT_C as output. ;Disable break and all LEDs. ;Restore A register ;Save HL register ;Load HL with return address fetched from stack ;Save this return address also in ADSAVE address ;Set user's PC to this return address ;and restore HL original content. ;Set user's SP to current SP ;Save other registers by pushing them onto the stack

; The next 2 instructions save the I (Interrupt Vector) register. The interrupt flip-flop (IFF2) is copied ; into the parity flag (P/V). The current interrupt status (enabled or disabled) can be determined by testing ; this parity flag LD LD A,I (USERIF+1),A IFF2 into the user's interrupt flip-flop ;If PO=true then flag P/V is zero

; The next 4 instructions save LD JP LD LD LD

SETIF:

A,0 PO,SETIF A,1 (USERIF),A SP,SYSSTK

;Set SP to system stack SP. If the user's SP points to a location which is not in RAM, then

; The next 8 instructions check user's ; 'eRR-SP' is displayed. LD LD DEC CALL JR DEC CALL JR HL,(USERSP) IX,ERR_SP HL RAMCHK NZ,SETST0 HL RAMCHK NZ,SETST0

; If the user's stack and system's stack are overlayed ; following instructions: LD NOP NOP LD ADD JR LD SCF JR IX,SYS_SP DE,-USERSTK+1 HL,DE C,SETST0 IX,DISPBF

then display 'SYS-SP'. This checking is done by the

;Set carry flag to indicate the user's SP is OK. BRRSTO

; STATE is a memory location that contains the current monitor status. It will be described in detail later. ; STATE 0 means 'fixed display pattern'. 'uPF--1' or 'SYS-SP' messages belong to this category. ; The next 2 instructions set this variable to zero. SETST0: BRRSTO: XOR LD LD LD A (STATE),A A,(BRDA) HL,(BRAD) ;Clears A register and also sets Carry flag = 0 ;Restore the data at break address

LD

(HL),A

; If the user's SP is legal (i.e. the carry flag is set) then dispaly user's PC and data at this address ; Otherwise display one of this fixed messages: "uPF--1" , "eRR-SP" or "SYS-SP" CALL C,MEMDP2

;************************************************************************************************************* ; This is what monitor program does all the time: scan display and keyboard and when a key is pressed take ; the proper action. MAIN: LD CALL CALL JR SP,SYSSTK SCAN BEEP MAIN ;Set SP to system stack ;Scan display and input keys (SCAN will not return until ;a key is pressed) ;After a key is pressed a small beep will sound. ;keep doing this all the time

;************************************************************************************************************* ; Routine KEYEXEC takes the proper action according the key pressed. It uses the code returned by SCAN, ; which is stored in A. There are 32 posible key codes rangibg from 00 to 0x1F. ; Three cases will be considered depending on the value of the key returned. ; ; Case 1: Codes between 0x00 and 0x0F which correspond to HEXADECIMAL KEYS (0,1...D,E,F). This keys are ; processed in routine KHEX. ;************************************************************************************************************* KEYEXEC: CP $10 JR C,KHEX ; ; ; ; ; If the key pressed is NOT hexadecimal then it must be a FUNCTION or SUB-FUNCTION key, this means that the previous numeric entry has finished. Bit 0 of TEST flag (mentioned earlier) must be set at the beginning of a new numeric entry. If bit 0 of TEST is set then the data buffer will be automatically cleared when a hexadecimal key is entered. This is acomplished by the next two instructions. LD SET ; ; ; ; ; ; HL,TEST 0,(HL)

Case 2: Codes between 0x10 & 0x17 ( +, -, GO, STEP, DATA, SBR, INS, DEL) There is no specific state corresponding to these keys, the response to them depends on the current value of "state" and "minor-state". (e.g. the response to '+' depends on the current context, it is illegal when the display is showing 'uPF--1' but is legal when the display is in the 'address-data' form.) In this monitor program the keys ( +, -, GO, STEP,DATA, SBR, INS,DEL) keys are called SUB-FUNCTION keys. All of them are branched by table KSUBFUN and routine BRANCH. SUB CP LD JP $10 8 HL,KSUBFUN C,BRANCH

; ; ; ;

Case 3: Codes between 0x18 & 0x1F (PC, ADDR, CBR, SBR, REG, MOVE, RELA, TAPE WR, TAPE RD) These keys are named FUNCTION-KEYS, since they are acceptable at any time. When one of this keys is pressed the monitor will unconditionally enter a new state. STMINOR will contain the "minor-state", which is required to process some sub-function keys (e.g. +,-) LD SUB LD LD IX,DISPBF 8 HL,STATE (HL),A

;Set the STATE to key-code minus 18H. The STATE is updated ;here and will be modified later by local service routines ;if the function is PC, ADDR or CBR. For other function keys ;STATE will not be modified later. ;Set STMINOR to 0 ;KFUN is the base address of the branch table and A has ; a table offset.

LD LD LD JP

HL,STMINOR (HL),0 HL,KFUN BRANCH

;************************************************************************************************************* ; The possible values of STATE and their meaning are: ; ; 0 = FIXED ; Display a fixed pattern, i.e. 'uPF--1' ; 1 = ADDRESS ; The hex key entered is interpreted as a memory address. ; 2 = DATA ; The hex key entered is interpreted as a memory data. ; 3 = REG ; Display the pattern 'Reg- ' and expect a register name to be entered. ; 4 = MOVE ; Expect parameters for MOVE function ; 5 = RELA ; Expect parameters for RELA function ; 6 = TAPEWR ; Expect parameters for TAPE WRITE function ; 7 = TAPERD ; Expect parameters for TAPE READ function ; 8 = RGADDR ; Entered Hex key will be interpreted as address name for registers ; 9 = RGDATA ; Entered Hex key will be interpreted as data for registers

;************************************************************************************************************* ; Subroutine name conventions: ; ; (1) K???? K stands for Key and ???? is the key name, i.e. KINS corresponds to 'INS' key. Each time a ; key with code ???? is pressed The routine with the name K???? will be executed. All this ; routines are branched by table KFUN and KSUBFUN. ; ; (2) H???? H stands for Hexadecimal and ???? is the current STATE, i.e. routine HDA will be executed if ; the entered key is hexadecimal and current STATE is 2 (DATA). All H???? routines are branched ; by table HTAB. ; ; (3) I???? I stands for increment ('+' key) and ???? is the current STATE, i.e. IMV will be executed ; when STATE is 4 (MOVE) and '+' key is entered. all I???? routines are branched by table ITAB ; ; (4) D???? D stands for decrement ('-' key) and ???? is the current STATE, i.e. all D???? routines are ; branched by table DTAB. ; ; (5) G???? G stands for GO ('GO' key) and ???? is the current STATE, i.e. all G???? routines are branched ; by table GTAB. ;************************************************************************************************************* ; Hexadecimal keys and '+', '-' or 'GO' function keys may be entered after different function keys. ; The monitor program uses branch tables and the value of STATE to determine the current function and branch ; to the proper entry point. ; ;************************************************************************************************************* ; Routine KHEX is executed when hexadecimal keys are pressed (See case 1 before). It uses HTAB and STATE ; for further branching KHEX: BR1: LD LD LD JP C,A HL,HTAB A,(STATE) BRANCH ;Save A register in C (Remember: A holds the hex key code)

;************************************************************************************************************* ; Routine KINC is branched by KSUBFUN table and executed when '+' is pressed, it uses ITAB and STATE for ; further branching KINC: LD JR HL,ITAB BR1

;************************************************************************************************************* ; Routine KDEC is branched by KSUBFUN table and executed when '-' key is pressed. It uses DTAB and STATE ; for further branching KDEC: LD JR HL,DTAB BR1

;************************************************************************************************************* ; Routine KGO is branched by KSUBFUN table and executed when 'GO' key is pressed. It uses GTAB and STATE ; for further branching KGO: LD JR HL,GTAB BR1

;************************************************************************************************************* ; Routine KSTEP is branched by KSUBFUN table and executed when 'STEP' key is pressed. KSTEP: CALL TESTM ;Check if the left 4 digits of the display are memory address. ;If not, disable all LEDs as a warning to the user. This display ;blanking is done by routine IGNORE ;This data will be output to port B to enable BREAK. ;This is done by routine PREOUT

JP LD JP

NZ,IGNORE A,10000000B PREOUT

;************************************************************************************************************* ; Routine KDATA is branched by KSUBFUN table and executed when 'DATA' key is pressed. KDATA: not. CALL RET TESTRG: CP JP MEMDP2 8 C,IGNORE ;If yes, display the data of that address and set STATE to (DATA) ;Check if the status is 8 or 9 (RGAD or RGDA). ;If not, ignore this key by blanking out the display CALL JR TESTM NZ,TESTRG ;Check if the left 4 digits of the display are memory address. ;If not, branch to TESTRG to check whether the display is reg. or

CALL RET

REGDP9

;If yes, display register and set status to 9 (RGDA)

;************************************************************************************************************* ; Routine KSBR is branched by KSUBFUN table and executed when 'SBR' (set breakpoint) key is pressed. KSBR: CALL JP LD CALL JP LD CALL RET TESTM NZ,IGNORE HL,(ADSAVE) RAMCHK NZ,IGNORE (BRAD),HL MEMDP2 ;Check if the display is in ADDRESS-DATA form. ;If not, ignore this key by blanking out the display ;If yes, get the address being displayed now. ;Check if this address is in RAM space. ;If not, ignore the 'SBR' key by blanking ;If yes, then set this address as a breakpoint ;Display the data of break address and set STATE to 2 (DA).

;************************************************************************************************************* ; Routine KINS is branched by KSUBFUN table and executed when 'INS' (insert) key is pressed. KINS: CALL JP LD NOP LD INC LD CALL JP LD LD CP JR CP JP LD LD TESTM NZ,IGNORE HL,(ADSAVE) (STEPBF),HL HL (STEPBF+4),HL RAMCHK NZ,IGNORE DE,$1DFE A,H $1E C,SKIPH1 $20 C,IGNORE D,$27 (STEPBF+2),DE ;Check if the display is in ADDRESS-DATA form. ;If not, ignore this key by blanking out the display ;If yes, get the adress being displayed now. ;? ;Store this address in STEPBF and the next address in STEPBF+4 for ;later use ;Check if the address to be inserted is in RAM. ;If not, ignore the INS key by blanking ;If the address to be inserted is in the range of 1800-1DFF, then ;store 1DFE into STEPBF+2 ;Otherwise, ignore the INS key.

SKIPH1:

;************************************************************************************************************* ; When one byte is inserted at some address, all data below this address will be shifted down one position. ; The last location will be shifted out and therefore lost. The RAM is divided into 3 blocks as long as INS ; is concerned, this blocks are: 1800-1DFF,1E00-1FFF and 2000-27FF. The second block cannot be inserted ; because it contains system data. Each block is independent from the other when shift is performed so the ; data shifted out of the first block will not be propagated to the next block. The shift is acomplished by ; block transfer instruction in subroutine GMV. This routine needs 3 parameters which are described in the ; following lines: ; STEPBF: Starting Address (2 bytes) ; STEPBF+2: Ending Adress (2 bytes) ; STEPBF+4: Destination Address (2 bytes) DOMV: CALL GMV XOR A LD LD LD CALL RET (DE),A HL,(STEPBF+4) (ADSAVE),HL MEMDP2 ;After the RAM has been shifted down, the data of the address to be ;inserted is cleared to zero. ;Register DE contains inserted address after GMV is performed. ;Copy the data in (STEPBF+4) to (ADSAVE) ;Display the address and its data, also set STATE to 2

;************************************************************************************************************* ; Routine KDEL is branched by KSUBFUN table and executed when 'DEL' (delete) key is pressed. KDEL: CALL JP LD NOP LD CALL JP LD routine GMV ;in step-buffer. (See coments on routine KINS for details.) LD CP JR CP A,H $1E C,SKIPH2 $20 (STEPBF+4),HL RAMCHK NZ,IGNORE DE,$1E00 TESTM NZ,IGNORE HL,(ADSAVE) ;Check if display is in ADDRESS-DATA form. ;If not, ignore this key by blanking out the display ;DEL is similar to INS except that the memory is shifted up ;instead of down. (See coments on routine KINS for details.) ;Get the address being displayed now, ;(this is the address to be deleted) ;??? ;Check if address is in RAM. ;If it isn't ignore key by blanking the display ;The following instructions prepare the parameters for

SKIPH2:

JP LD LD INC LD JR

C,IGNORE D,$28 (STEPBF+2),DE HL (STEPBF),HL DOMV

;************************************************************************************************************* ; Routine KPC is branched by KFUN table and executed when 'PC' (Program Counter) key is pressed. KPC: LD LD CALL RET ;************************************************************************************************************* ; Routine KCBR is branched by KFUN table and executed when 'CBr' (Clear breakpoint) key is pressed. KCBR: returns, CALL LD CALL corresponding ;data. Also sets variable STATE to 2 RET ;************************************************************************************************************* ; Routine KREG is branched by KFUN table and executed when 'REG' (Register) key is pressed. KREG: IX LD IX,REG_ ;Routine SCAN uses IX as a pointer to the display buffer. Setting ;to REG will make SCAN display 'Reg-' and decode user's flag F ;and F' to binary display format. This format will be used later ;when user requires the monitor to display decoded flag by pressing ;keys 'SZXH' and 'XPNC' CLRBR (ADSAVE),HL MEMDP2 ;Call subroutine CLRBR to clear breakpoint. When this routine ;HL always contains FFFF. ;Store FFFF into (ADSAVE) ;Routine MEMDP2 displays the address in (ADSAVE) and its HL,(USERPC) (ADSAVE),HL MEMDP2 ;Store the user's PC into (ADSAVE) ;Routine MEMDP2 displays the address in (ADSAVE) and its ;corresponding data. Also sets variable STATE to 2

CALL RET

FCONV

;************************************************************************************************************* ; Routine KADDR is branched by KFUN table and executed when 'Addr' (Address) key is pressed. KADDR: STATE CALL RET MEMDP1 ;Display the address stored in (ADSAVE) and set system variable ;to 1 (Address mode)

;************************************************************************************************************* ; Functions 'Move','Rela','Read Tape' and 'Write Tape', all require from one to three parameters. ; These parameters are stored in address STEPBF (Step Buffer). On the other hand, address STMINOR (minor ; status) contains the number of parameters that has been entered. For MOVE or RELA functions, the default ; value of the first parameter is the address stored in ADSAVE memory address. On the other hand, there is no ; default value for the first parameter (filename) of the Read and Write tape routines.When function keys are ; pressed, STMINOR is automatically reset to zero. ;************************************************************************************************************* ; Routines KMV and KRL are branched by KFUN table and executed when 'Move' or 'Rela' keys are pressed. KMV: KRL: LD LD HL,(ADSAVE) (STEPBF),HL ;Store the contents of ADSAVE into STEPBF as default value ;of first parameter.

;************************************************************************************************************* ; Routines KWT and KRT are branched by KFUN table and executed when 'WRTape' or 'RDTape' keys are pressed. KWT: KRT: CALL RET STEPDP ;Display the parameter that is being entered now by calling STEPDP

;************************************************************************************************************* ; The following subroutines, all following the format Hxxx are the service routines for hexadecimal keys ; corresponding to each STATE. They are all branched by table HTAB and STATE HFIX: illegal. HDA: JP IGNORE ;When the display is in fixed pattern, hexadecimal keys are ;IGNORE disables all LEDs as a warning to the user. LD CALL JP HL,(ADSAVE) RAMCHK NZ,IGNORE ;Get the address being displayed now from (ADSAVE) ;Check if address is in RAM. ;If not, ignore this key blanking the display

CALL subfunction, LD A. RLD

PRECL1 A,C

;If this is the first hex key entered after function or ;reset the data of that address to 00h ;The key code is saved in C register at routine KHEX, restore it to ;Rotate the key code (4 bits) into the address obtained above in HL ;Display the address and data then set STATE to 2 (DA).

CALL MEMDP2 RET HAD: the LD RLD INC RLD CALL RET HRGAD: HRGFIX: LD LD LD ADD LD CALL RET A,C HL MEMDP1 LD CALL HL,ADSAVE PRECL2

;If this is the first hex key after function key is entered, set ;contents of (ADSAVE) to 00h. ;The key-code is saved in C register by routine KHEX. ;Shift the address being displayed by one digit. ;Display the address and its data. Also, set STATE to 1.

A,C IX,DISPBF HL,STMINOR A,A (HL),A REGDP8

;The key-code is the register name. Double its value and store it ;into STMINOR. ;Display register and set STATE to 8. (RGAD)

HRT: HWT: HRL: HMV: parameter bytes)

CALL CALL LD RLD INC RLD CALL RET

LOCSTBF PRECL2 A,C HL STEPDP LOCRGBF PRECL1 A,C REGDP9

;Use STMINOR and STEPBF to calculate the address of current ;in step buffer ;If this is the first hex key entered, clear the parameter (2 ;by calling PRECL2. ;C contains the key code. ;Rotate the key code 1 digit to the left ;Display the parameter. ;Calculate the address of the register being modified. ;If this is the first hex key entered, then clear the register ;Rotate user's register 1 digit to the left. (C holds the key-code) ;Display the register and set STATE to 9 (RGDA)

HRGDA:

CALL CALL LD RLD CALL RET

;************************************************************************************************************* ; The following subroutines, all following the format Ixxx are the service routines for '+' ; corresponding to each STATE. They are all branched by table ITAB and STATE IFIX: IRGFIX: IAD: IDA: JP LD INC LD CALL RET IGNORE HL,(ADSAVE) HL (ADSAVE),HL MEMDP2 ;'+' key is illegal for state FIX or RGFIX, so ignore it.

;Increase the address being displayed now (In ADSAVE) by 1. ;Display the address and data the set state to 2.

IRT: IWT: IRL: IMV:

ISTEP:

LD INC CALL JR DEC JP CALL RET

HL,STMINOR (HL) LOCSTNA NZ,ISTEP (HL) IGNORE STEPDP

;STMINOR contains the parameter count, increment it by one. ;Check if the count is overflowed. ;If not overflowed, continue at ISTEP. ;Otherwise, restore the count and ignore the '+' key. ;Display the parameter at step buffer.

IRGAD: IRGDA:

LD INC LD CP JR LD CALL RET

HL,STMINOR (HL) A,$1F (HL) NC,IRGNA (HL),0 REGDP9

;In these states, the STMINOR contains the register name. ;Increase it by 1.

;If it reaches the last one, reset it to the first one ;Display the register contents and set STATE to 9.

(00h). IRGNA:

;************************************************************************************************************* ; The following subroutines, all following the format Dxxx are the service routines for '-' ; corresponding to each STATE. They are all branched by table DTAB and STATE DFIX: DRGFIX: DAD: DDA: JP LD DEC LD CALL RET IGNORE HL,(ADSAVE) HL (ADSAVE),HL MEMDP2 ;'-' key is illegal for these states. Ignore it. ;Decrease the address being displayed now (in ADSAVE) by one. ;Display the address and data and set STATE to 2 (DA).

DRT: DWT: DRL: DMV:

LD DEC CALL JR

HL,STMINOR (HL) LOCSTNA NZ,DSTEP (HL) IGNORE STEPDP HL,STMINOR (HL) A,$1F (HL) NC,DRGNA (HL),$1F REGDP9

;In these states, STMINOR contains the parameter count. Decrease it ;by one. ;If overflow occurs, restore STMINOR and ignore the '-' key. ;continue at DSTEP. ;Display the parameter. ;In this state, STMINOR contains the register name. ;Decrease register name by one ;If it goes below zero, set it to the highest value (1Fh) ;Display the register and set STATE to 9

Otherwise DSTEP: DRGAD: DRGDA: INC JP CALL RET LD DEC LD CP JR LD CALL RET

DRGNA:

;************************************************************************************************************* ; The following subroutines, all following the format Gxxx are the service routines for 'GO' ; corresponding to each STATE. They are all branched by table GTAB and STATE GFIX: GRGFIX: GRGAD: GRGDA: GAD: GDA:

JP LD LD

IGNORE HL,(BRAD) (HL),$EF

;'GO' key is illegal for these states, so ignore it. ;Get the breakpoint address. ;0EFh is the op-code for RST28H ;The contents of breakpoint address is changed to RST 28H ;before the control is transfered to user's program. This will ;cause a trap when the user's program passes this point. ;Load 0FFh in memory location TEMP. ;Test the user's IFF (interrupt FlipFlop), depending on result ;two opcodes will be inserted at address TEMP+1 and TEMP+2 ;if IFF=0, then the instructions are 'EI' and 'RET' ;(0C9h is the opcode for RET, and 0FBh is for 'EI') ;if IFF=1, then the instructions are 'DI' and 'RET' ;0F3h is the opcode for 'DI', since H hasn't changed, ;Restore user's register by setting SP to REGBF (Reg. buffer) ;and continuosly popping the stack.

PREOUT:

LD LD LD BIT LD JR LD

A,$FF (TEMP),A A,(USERIF) 0,A HL,$C9FB NZ,EIDI L,$F3 (TEMP+1),HL SP,REGBF AF BC

modify L EIDI:

LD LD POP POP

POP POP EX POP EX EXX POP POP POP EXX POP POP LD LD LD LD PUSH LD EX LD OUT LD JP

DE HL AF,AF' AF AF,AF' BC DE HL IX IY SP,(USERSP) (USERAF+1),A A,(USERIF+1) I,A HL HL,(ADSAVE) (SP),HL A,(TEMP) (DIGIT),A A,(USERAF+1) TEMP+1

;Restore user's SP. ;Temporarily save A ;Restore user's I ;The next 3 instructions push the address being displayed now ;(which is in ADSAVE) This address will be treated as ;user's new PC. ;Output 0FFh to port B of 8255. when A=10111111 break is ;enabled, when A=FF then break is disabled. When break is ;enabled, a non-maskable interrupt (NMI) will occur 5 M1's ;after the out instruction. ;1st M1, Restore A ;2nd M1, ;Execute the two instructions stored in RAM. They are: ; EI (or DI) ;3rd M1 ; RET ;4th M1 ;The starting address of user's program has been pushed onto ;the top of the stack. RET pops out this address and transfers ;Control to it. The first M1 of user's program will be the 5th ;M1 after OUT. If breakpoint is enabled, NMI will occur after ;this instructions is completed. This is how the single-step ;functionality is achieved. ;Load parameters from step buffer into registers. ;Also check if the parameters are legal. After GETP we have: ;HL = start address of source ;BC = Lenght to MOVE. ;Jump to ERROR if the parameters are illegal (i.e. ending ;address is lower than starting address) ;Load destination address into DE ;Compare HL and DE to determine move direction (up or down) ;Move down: ;HL = destination address ;HL = destination address + length ;HL= end address of destination ;DE = end address of destination ;HL = end address of source ;Block transfer instruction ;DE = Last address move ;Continue at ENDFUN. ;Move up. HL is destroyed by SBC HL,DE so we must restore HL. ;block transfer instruction ;DE = last address moved ;Continue at ENDFUN ;Load starting address into DE. ;Increase this address twice. This is because relative jumps ;are 2 bytes long. ;Load destination address into HL ;Calculate difference between starting and destination address ;Check if the offset is between +127 (007Fh) and -128 (FF80h). ;If the offset is positive, both H and bit 7 of L must be zero ;If offset is negative then H and bit 7 of L must be FF and 1. ;In both cases, adding H with bit 7 of L results in 0 ;Rotate bit 7 of L into carry flag. ;ADD H and bit 7 of L. ;Branch to ERROR if the result is nonzero. ;Save the offset into the next byte of opcode. (DJNZ or JR)

GMV:

LD CALL

HL,STEPBF GETP

JR LD SBC JR EX ADD DEC EX LD LDDR INC JR MVUP: ADD LDIR DEC JR LD INC INC LD OR SBC LD

C,ERROR DE,(STEPBF+4) HL,DE NC,MVUP DE,HL HL,BC HL DE,HL HL,(STEPBF+2) DE ENDFUN HL,DE DE ENDFUN DE,(STEPBF) DE DE HL,(STEPBF+2) A HL,DE A,L

GRL:

RLA LD ADC JR LD DEC LD

A,H A,0 NZ,ERROR A,L DE (DE),A

ENDFUN:

LD CALL RET

(ADSAVE),DE MEMDP2

;Save DE into ADSAVE. ;Display this address and its data.Set STATE to 2

;*************************************************************************************************************** ******** GWT: CALL SUM1 ;Load parameters from step buffer into registers. ;Check if the parameters are legal. If legal, calculate the ;sum of all data to be output to tape JR C,ERROR ;Branch to ERROR if the parameters are illegal. (i.e.lenght is ;negative) LD (STEPBF+6),A ;Store the checksum into STEPBF+6 LD HL,4000 ;Output 1KHz square wave for 4000 cycles (This is a leading CALL TONE1K ;sync signal) LD HL,STEPBF ;Output 7 bytes starting at STEPBF: ; 2 BYTES = filename ; 2 BYTES = Starting address ; 2 BYTES = Ending address ; 1 BYTE = Checksum LD BC,7 ; (TOTAL = 7 bytes) CALL TAPEOUT ;Writes the data to tape LD HL,4000 ;Output 2KHz square wave for 4000 cycles. This is the middle ;sync signal, during this middle sync, the file name CALL TONE2K ;will be displayed CALL GETPTR ;Load parameters into registers. (Starting,ending and lenght) CALL TAPEOUT ;Output user's data. LD HL,4000 ;Output 4000 cycles of 2KHz square wave, this is the trailing CALL TONE2K ;sync signal. ENDTAPE: ERROR: LD JR LD JP DE,(STEPBF+4) ENDFUN IX,ERR_ SETST0 ;DE=last address ;Continue at ENDFUN ;IX points to '-Err' buffer ;Set state to 0.

;************************************************************************************************************* GRT: LD HL,(STEPBF) ;Temporarily save filename. LD (TEMP),HL LEAD: LD A,01000000B ;The 7th bit is connected to display's decimal point OUT (SEG7),A ;When searching for the filename, the display is initially ;blank. If the data read from MIC is an acceptable 0 or 1, ;then the displays becomes '.... ..' LD HL,1000 LEAD1: CALL PERIOD ;At the return of routine PERIOD the carry flag has a value ;depending on the data read: ;If C=0, then the tape input is 1Khz, ;If C=1 then the tape input isn't 1Khz JR C,LEAD ;So program must loop until 1Khz leading sync is detected. DEC HL ;Decrease HL by one when one 1KHz period is detected. LD A,H OR L ;Check if both H and L are 0. JR NZ,LEAD1 ;Do the loop for 1000 periods. ;The leading sync is accepted if it is longer than 1000 cycles LEAD2: CALL PERIOD ;(1000 cycles = 1 second) JR NC,LEAD2 ;Wait until the complete leading sync signal pass over. LD HL,STEPBF ;Load 7 bytes from tape into STEPBF LD BC,7 CALL TAPEIN JR C,LEAD ;Jump to LEAD if input is not successful LD DE,(STEPBF) ;Input was OK, so get the filename from STEPBF CALL ADDRDP ;Convert filename into display format. LD B,150 ;Display it for 1,5 sec. FILEDP: CALL SCAN1 DJNZ FILEDP LD HL,(TEMP) ;Check if the input filename equals to the specified filename OR A SBC HL,DE JR NZ,LEAD ;If not, find the leading sync of next file LD A,00000010B ;Filename was found, so prepare segment '-' and OUT (SEG7),A ;display '---- --' CALL GETPTR ;The parameters (start and end address + checksum) have been ;loaded into STEPBF, so load them back into registers, ;calculate the block lenght and check if they are legal. JR C,ERROR ;Jump to error if the parameters are illegal, CALL TAPEIN ;Input user's data JR C,ERROR ;Jump to ERROR if input was not successful. CALL SUM1 ;Calculate the sum of all input data. LD HL,STEPBF+6

CP JR JR

(HL) NZ,ERROR ENDTAPE

;Compare it with the checksum calculated previously and stored ;in tape. Jump to ERROR if they don't match (Checksum error) ;Checksum OK, continue at ENDTAPE

;************************************************************************************************************* ; Branch table format: ; byte 1,2 : Address of the first routine in each group. ; byte 3 : Difference between the address of 1st group and 1st routine, which is 0 in this case. ; byte 4 : Difference between the address of 2nd and 1st routine. ; byte 5 : Difference between the address of 3rd and 1st routine. ; . ; . ; . ; . ; . ; HL : Contains the address of branch table. ; A : Contains the routine number in its group ;Such branch table can save table lenght and avoid page boundary problems (1 page = 256 bytes) BRANCH: LD INC LD INC ADD LD LD LD ADD JP E,(HL) HL D,(HL) HL A,L L,A L,(HL) H,0 HL,DE (HL) ;Load the address of 1st routine in the group into DE register ;Locate the pointer of difference table. ;Load the address difference into L. ;Get the routine's read address and ;Jump to it.

;************************************************************************************************************* IGNORE: LD HL,TEST SET 7,(HL) ;Routine SCAN will check bit 7 of TEST. If it is set, all LEDs ;will be disabled as a warning to the user when an illegal key ;is entered. RET ;************************************************************************************************************* ; Power-up initialization: INI: LD IX,BLANK ;Blank display is the initial pattern ;Display the following patterns sequence, each of them lasting ;0,16 secs. ; ' ' ; ' u' ; ' uP' ; ' uPF' ; ' uPF-' ; ' uPF--' ; 'uPF--1' LD C,7 ;Pattern count INI1: LD B,$10 ;This value in B produces a 0,16 sec delay for each character INI2: CALL SCAN1 DJNZ INI2 DEC IX ;Next pattern DEC C JR NZ,INI1 LD JP LD LD A,PWCODE INI3 HL,NMI (IM1AD),HL

INI4:

;Setup the service routine vector for RST 38h which is also the ;service routine for NMI (NonMaskable Interrupt) used by ;single step execution and breakpoint.

;************************************************************************************************************* ; Clear Breakpoint: ; Setting breakpoint to address 0FFFFh has the effect of disabling it. CLRBR: LD LD RET HL,$FFFF (BRAD),HL

;************************************************************************************************************* ; Test Display Mode: ; This routine checks if the display is in 'address-data'form, i.e. if STATE is 1 or 2. The result is stored ; in Z flag. ; If Z=1 Display IS in 'address-data' form. ; If Z=0 Display IS NOT in 'address-data' form.

TESTM:

LD CP RET CP RET

A,(STATE) 1 Z 2

;************************************************************************************************************* ; Pre-clear 1 byte: ; If bit 0 of TEST is 1, load 00 into (HL), then clear this bit ; Registers destroyed: A,F PRECL1: LD OR RET LD LD LD RET A,(TEST) A Z A,0 (HL),A (TEST),A ;Update flags according to A contents ;if bit 0 of A=0, do nothing and return ;bit 0 of A = 1 so reset it ;Clear (HL) ;Clear (TEST)

;************************************************************************************************************* ; Pre-clear 2 bytes: ; If bit 0 of TEST is 1, load 00 into (HL) and (HL+1), then clear this bit ; Registers destroyed: A,F PRECL2: CALL RET INC LD DEC RET PRECL1 Z HL (HL),A HL

;************************************************************************************************************* ; Memory display format: (address-data) ; 1) A.A.A.A. the numeric ; ; 2) A A A A monitor is ; ; 3) A.A.A.A. breakpoint MEMDP1: LD LD LD JR MEMDP2: SAV12: LD LD LD LD EXX LD CALL LD CALL D D D.D. D.D. ---State is 'AD'. 4 decimal points under the address field indicate that Value entered will be interpreted as a memory address. State is 'DA'. 2 decimal points under the data field indicate that the expecting user to enter memory data. Six decimal points indicate that the address being displayed is set as a ;Next STATE = 1 ;4 decimal points active ;The 1st active decimal point is in DISPBF+2, the last is in ;DISPBF+5 ;Continue at SAV12 ;Next STATE = 2 ;2 active decimal points ;1st decimal point is in DISPBF, 2nd in DISPBF+1 ;Update STATE ;Save registers HL,BC,DE ;Address to be displayed is allways in (ADSAVE),load it into ;DE register ;Convert this address to display format and store it in ;the display buffer, (i.e. DISPBF+2 thru DISPBF+5) ;load data pointed by DE into A register ;Then convert it to 7-segment format and store it in ;the display buffer (2 rightmost chars; DISPBF and DISPBF+1)

A,1 B,4 HL,DISPBF+2 SAV12 A,2 B,2 HL,DISPBF (STATE),A DE,(ADSAVE) ADDRDP A,(DE) DATADP

;************************************************************************************************************* ; The next 3 instructions serve to refresh the data at break address every time memory is displayed. BRTEST: LD HL,(BRAD) ;Get the breakpoint address LD A,(HL) ;Get the data at breakpoint address and store it in A LD (BRDA),A ;Store A in memory at breakpoint data address (BRDA) OR A SBC HL,DE ;Check if the address to be displayed is the breakpoint ;address. JR NZ,SETPT1 ;If not, jump to SETPT1 LD B,6 ;address to be displayed is the breakpoint address, so in ;order to warn the user, monitor activates ALL display's ;decimal points. LD HL,DISPBF ;The first decimal point is in DISPBF, the 6th is in DISPBF+5 EXX SETPT1: EXX ;Restore HL,BC,DE SETPT: SET 6,(HL) ;Set decimal points ;At this point the count is in B and 1st address in HL register.

INC DJNZ RET

HL SETPT

;************************************************************************************************************* ; Display the Step Buffer and its parameter name. (STEPDP) ; ; Input: STATE and STMINOR (parameter count) ; Registers Destroyed: AF,BC,DE,HL ;************************************************************************************************************* ; Step display format: ; (this format is used when user is entering parameters for 'Move','Rela','Wrtape','Rdtape') ; Step display format looks like: ; P.P.P.P. - X ; ; 'P' is the digit of parameter, the four decimal points indicate that P.P.P.P. are editable at this moment. ; X can be one of the following characters: ; a) For 'Move' Function: ; -S = Starting Address ; -E = Ending Address ; -D = Destination Address ; b) For 'Rela' Function: ; -S = Source Address ; -D = Destination Address ; c) For 'WRTape' Function: ; -F = Filename ; -S = Starting Address ; -E = Ending Address ; d) For 'RDTape' Function: ; -F = Filename STEPDP: CALL LD INC LD CALL LD LD CALL CALL LD LD LD RET LOCSTBF E,(HL) HL D,(HL) ADDRDP HL,DISPBF+2 B,4 SETPT LOCSTNA L,A H,2 (DISPBF),HL ;Get parameter address

;Convert this parameter to display format (4 digits) and store ;it at DISPBF+2,DISPBF+3,DISPBF+4, and DISPBF+5 ;Set the decimal points (from DISPBF+2 to DISPBF+5) ;Get the parameter name ;Pattern '-' for 2nd rightmost digit

;************************************************************************************************************* ; Get the location of parameter (LOCSTBF) ; Input: (STMINOR) ; Output: HL has the address of this parameter. ; Registers destroyed: AF,HL LOCSTBF: LD ADD LD ADD LD RET A,(STMINOR) A,A HL,STEPBF A,L L,A ;Get parameter count. ;multiply parameter count by 2 since Each param. has 2 bytes ;Get base address of parameters

;************************************************************************************************************* ; Get the parameter name (LOCSTNA) ; Inputs: STATE,STMINOR ; Output: Parameter name in A and Z Flag ; Registers Destroyed = AF,DE LOCSTNA: LD SUB ADD ADD LD ADD LD LD ADD LD LD OR A,(STATE) 4 A,A A,A DE,STEPTAB A,E E,A A,(STMINOR) A,E E,A A,(DE) A ;Get STATE. (Possible states are: 4,5,6,7 each of them ;corresponding to MOVE,RELA,WRTAPE,RDTAPE. ;Change 4,5,6,7 to 0,1,2,3 ;Each STATE has 4 bytes for names, ;so A <= A*4 ;Now DE contains the address of first name for each state. ;Get parameter count ;DE <= DE+A ;Get parameter name ;Change zero flag. If the returned pattern in A is zero then ;the keys '+' or '-' must have been pressed beyond legal

RET

;parameter boundary. (Check if parameter name got from STEPTAB ;is zero)

;************************************************************************************************************* ; Register display format: ; ; 1) X X X X Y Y -State is REGAD. The numeric data entered is interpreted as a reg. name ; YY is the register name and the data for that register pair is X X X X ; 2) X X X.X. Y Y -; or ; X.X.X X Y Y -State is REGDA. The unit used here for register modification is a BYTE. ; The numeric data entered will change the byte with decimal points ; under it. Decimal points can be moved by '+' or '-' keys. ;************************************************************************************************************* ; Display register and set STATE to 8. REGDP8: LD A,8 ;STATE number in A JR RGSTIN ;************************************************************************************************************* ; Display register and set STATE to 9. REGDP9: LD A,9 ;State number in A ; Update STATE with the value previously loaded in register A, then display user's register (count is ; contained in STMINOR) ; Registers Destroyed: AF,BC,DE,HL RGSTIN: LD (STATE),A ;Update STATE. LD A,(STMINOR) ;Get the register count RES 0,A ;Registers are displayed by pair. Find the count of pair leader ;(the count of the lower one) LD B,A ;Save A temporarily. CALL RGNADP ;Find the register count and store it in DISPBF and DISPBF+1 LD A,B ;Restore A (A contains the register pair leader) CALL LOCRG ;Get the address of user's register. LD E,(HL) ;Get the register's data (2 bytes) INC HL LD D,(HL) LD (ADSAVE),DE CALL ADDRDP ;Convert data to display format and store it in display buffer LD CP here RET LD LD BIT JR INC INC SET INC SET CALL RET NZ HL,DISPBF+2 A,(STMINOR) 0,A Z,LOCPT HL HL 6,(HL) HL 6,(HL) FCONV A,(STATE) 9 ;If STATE is 9 (RGDA) then set 2 decimal points, otherwise return

;Get the register name ;If this register is a group leader then set the decimal points of ;the two central digits, otherwise set the decimal points of the ;two leftmost digits.

LOCPT:

;Set the decimal points of (HL) and (HL+1) ;Convert user's flag (F and F') to display format

;************************************************************************************************************* ; Get the patterns of register names and store them into DISPBF and DISPBF+1 ; Input: A containing register count of pair leader. ; Registers Destroyed: AF,DE,HL RGNADP: LD ADD LD LD INC LD LD RET HL,RGTAB A,L L,A E,(HL) HL D,(HL) (DISPBF),DE ;Get address of pattern table ;Get 1st pattern. ;Get 2nd pattern.

;************************************************************************************************************* ; Get the address of user's register (LOCRGBF) ; Input:Register name contained in STMINOR. ; Destroys: HL,AF LOCRGBF: LD A,(STMINOR)

LOCRG:

LD ADD LD RET

HL,REGBF A,L L,A

;************************************************************************************************************** ; Encode or decode user's flag register (FCONV) ; STMINOR contains the name of the flag being displayed now. ; Registers Destroyed: AF,BC,HL FCONV: LD OR RRA CP JR LD A,(STMINOR) A $0B Z,FLAGX C,A ;Get the register name. ;Update flags and also clear carry flag ;Name of I register = 17H,name of IFF = 16H. ;Rotate Right one bit, so both become 0BH. ;Jump to FLAGX if I or IFF are being displayed now ;Otherwise, mask out bit 1 to bit 7 of user's IFF. ;IFF is only 1 bit but monitor program uses one complete byte to ;store it. The masking of bits 1 to 7 masks out useless bits. ;This is done only when the user is not modifiying IFF. If the user ;modifiying IFF, the monitor will display whatever he enters, even if ;bit 1 to 7 are not all zero. The contents of A is preserved after ;doing it. LD LD AND LD LD CP HL,USERIF A,(HL) 00000001B (HL),A A,C $0C

is

FLAGX: otherwise. FCONV1:

;If STMINOR contains the name of SZXH, XPNC, SZXH', XPNC'. After ;rotating right one byte it will be greater than or equal to 0CH ;Decode user's flag if it is not being modified now, encode it ;Get user's F register ;Decode upper 4 bits. ;Decode lower 4 bits. ;Get user's F' register.

FCONV2:

JR LD CALL LD CALL LD LD CALL LD CALL LD RET LD CALL LD CALL LD LD CALL LD CALL LD RET

NC,FCONV2 A,(USERAF) DECODE (FLAGH),HL DECODE (FLAGL),HL A,(UAFP) DECODE (FLAGHP),HL DECODE (FLAGLP),HL HL,(FLAGH) ENCODE HL,(FLAGL) ENCODE (USERAF),A HL,(FLAGHP) ENCODE HL,(FLAGLP) ENCODE (UAFP),A

;Get the binary form of the 4 upper bits of user's F register ;Encode it ;Encode 4 lower bits ;Save the encoded result into USERAF ;Encode F' register.

;************************************************************************************************************** ; Decode bits 7,6,5 & 4 of A register (DECODE) ; Each bit is extended to 4 bits, i.e. 0 becomes 0000 and 1 becomes 0001. The output is stored in HL, which is ; 16 bit in length. After execution, bits 7,6,5,4 of A becomes bits 3,2,1,0 of A before execution. ; Registers Destroyed = AF,B,HL DECODE: DRL4: LD ADD ADD ADD RLCA ADC DJNZ RET B,4 HL,HL HL,HL HL,HL HL,HL DRL4 ;Loop 4 times ;Clear the 3 rightmost bits of HL

;The 4th bit of HL is determined by carry flag, which is the ;MSB of A register

;************************************************************************************************************** ; Encode HL register ; Each 4 bits of HL are encoded to 1 bit, so 0000 becomes 0 and 0001 becomes 1. The result is stored in bits ; 3,2,1,0 of A register. After execution, bits 7,6,5,4 of A are bits 3,2,1,0 of A before execution. ; Registers Destroyed: AF,B,HL

ENCODE: ERL4:

LD ADD ADD ADD ADD RLA DJNZ RET

B,4 HL,HL HL,HL HL,HL HL,HL ERL4

;Loop 4 times ;Shift HL left by 4 bits, bit 12 of HL will be shifted into ;carry flag

;Rotate carry flag into A register

;************************************************************************************************************** ; Calculate the sum of a memory data block. ; Input: The starting and ending address of the block to be summed is in STEPBF+2 and STEPBF+4. ; Registers Destroyed = AF,BC,DE,HL SUM1: CALL RET GETPTR C ;Get parameters from STEP buffer ;Return if the parameters are illegal

; Calculate the sum of a memory block. HL contains the starting address and BC contains the length. The result ; is stored in A. ; Registers Destroyed: AF,BC,HL are destroyed. SUM: SUMCAL: XOR ADD CPI JP OR RET A A,(HL) PE,SUMCAL A ;Clear A ;Add ;Clear Flags

;************************************************************************************************************** ; Get parameters from step buffer (GETPTR) ; Input: (STEPBF+2) and (STEPBF+3) contains the starting address. ; (STEPBF+4) and (STEPBF+5) contains the ending address. ; Output: HL register contains the starting address. BC contains the lenght. ; Carry flag = 0 -- BC Positive ; 1 -- BC Negative ; Destroyed registers = AF,BC,DE,HL GETPTR: GETP: LD LD INC LD INC LD INC LD LD OR SBC LD LD INC EX RET HL,STEPBF+2 E,(HL) HL D,(HL) HL C,(HL) HL H,(HL) L,C A HL,DE C,L B,H BC DE,HL ;Load starting address into DE

;Load ending address into HL. ;Clear Carry Flag ;Find difference (Carry flag is altered here) ;Now BC contains the length. ;Now HL contains the starting address

;************************************************************************************************************** ; Load a memory block from tape (TAPEIN) ; Input: HL -- starting address of the block ; BC -- Length of the block ; Output: ; Cy = 1 : Read Error ; Cy = 0 : Read OK ; Destroyed registers -- AF,BC,DE,HL,AF',BC',DE',HL' TAPEIN: TLOOP: XOR EX CALL LD CPI JP EX RET A AF,AF' GETBYTE (HL),E PE,TLOOP AF,AF' ;Clear Carry flag to set NO ERROR status ;Read 1 byte from tape ;Store it into memory ;Loop until length is zero.

;************************************************************************************************************** ; Read one byte from tape (GETBYTE) ; Output: E = Data Read ; Cy of F' ==> 1 -- reading error ; 0 -- reading OK

; Destroyed Registers: AF,DE,AF',BC',DE',HL' ; Byte format: ; ; start bit bit bit bit bit ; bit 0 1 2 3 4 GETBYTE: BLOOP: CALL LD CALL RR DEC JR CALL RET GETBIT D,8 GETBIT E D NZ,BLOOP GETBIT

bit 5

bit 6

bit 7

stop bit

;Get start bit. ;Loop 8 times. ;Get one data bit (Result of operation in carry flag)

;Get stop bit

;************************************************************************************************************** ; Read one bit from tape (GETBYTE) ; Output: ; Carry of F = 0 ==> Read bit is a ZERO ; Carry of F = 1 ==> Read bit is ONE ; Carry of F' = 1 ==> Read Error ; Carry of F' = 0 ==> Read OK ; ; Destroyed Registers: AF,AF',BC',DE',HL' ; Bit format: ; 0 -- 2KHz x 8cycles + 1KHz x 2cycles ; 1 -- 2KHz x 4cycles + 1KHz x 4cycles ; ; ; ; ; ; ; ; ; ; ; ; ; The The has a) b) tape-bit format of both 0 and 1 are of the same form: high freq part + low freq part. difference between 0 and 1 is the number high freq cycles and low freq cycles. Thus, a high freq period 2 meanings: It is used to count the number of high freq cycles of the current tape-bit; If a high freq period is detected immediately after a low freq period, then this period is the first cycle of next type bit and is used as a terminator of the last tape-bit.

Bit 0 of H register is used to indicate the usage of a high freq period. If this bit is zero, high freq period causes counter increment for the current tape-bit. If the high freq part has passed, bit of H is set and the next high freq period will be used as a terminator. L register is used to up/down count the number of periods. When a high freq period is read, L is increased by 1 when a low freq period is read, L is decreased by 2. (The time duration for each count is 0,5 msec) At the end of a tape-bit, positive and negative L stand for 0 and 1 respectively. EXX LD CALL INC DEC JR JR DEC DEC SET JR INC BIT JR RL HL,0 PERIOD D D NZ,TERR C,SHORTP L L 0,H COUNT L 0,H Z,COUNT ;L =(number of 2K periods) - 2*(number of 1K periods) L ;0 --- No Carry (L positive) ;1 --- Carry (L negative) ;The positive or negative sign of L corresponds to the ;tape-bit data. ;'RL L' will shift the sign bit of L into the carry flag. ;After this instruction, the carry flag contains the tape-bit. ;Restore BC' DE' and HL' AF,AF' ;Set carry flag of F' to indicate error. AF,AF' ;Save HL,BC and DE Registers ;Clear bit 0 of H and set L to zero. ;Read 1 period. ;This two instructions check if D=0, Carry flag is not affected ;If D is not zero then jump to error routine TERR (Because the ;period is too much longer than that of 1KHz.) ;If the period is short (2 KHz) then jump to SHORTP ;Period is 1KHz. ;Decrease L by 2 ;set bit 0 of H to indicate that this tape-bit has passed the ;high freq part and reaches its low freq part. ;The period is 2KHz, increase L by 1. ;If the tape-bit has passed its high freq part, high freq means ;That this bit is all over and the next bit has started.

GETBIT: COUNT:

SHORTP:

TERR:

EXX RET EX SCF EX EXX RET

;************************************************************************************************************** ; Wait for the tape to pass one period. The time duration is stored in DE. The unit is loop count. Typical value ; for 2 KHz is 28 and 56 for 1 KHz. Use (56+28)/2 as threshold. The returned result is in carry flag. ; (1K -- NC, 2K -- C)

; Registers Destroyed: AF,DE PERIOD: LOOPH: LD IN INC RLA JR LD OUT IN INC RLA JR LD OUT LD CP RET DE,0 A,(KIN) DE C,LOOPH A,11111111B (DIGIT),A A,(KIN) DE NC,LOOPL A,01111111B (DIGIT),A A,E MPERIOD ;Bit 7 of 8255's port A is conected to tape input. ;Loop until input goes low. ;Echo the tape input to uPF-1's speaker.

LOOPL:

;Echo the tape input to uPF-1's speaker. ;Compare the result with the threshold.

;************************************************************************************************************** ; Output a memory block to tape (TAPEOUT) ; Input: HL -- Starting address of the block ; BC -- lenght of the block ; Destroyed registers: AF,BC,DE,HL,BC',DE',HL' TAPEOUT: LD CALL CPI JP RET E,(HL) OUTBYTE PE,TAPEOUT ;Get byte to be "sent" ;Output to tape. ;Loop until finished

;************************************************************************************************************** ; Output one byte to tape. For tape-byte format, see coments on GETBYTE. ; Input: E contains byte to be "sent" ; Destroyed Registers: AF,DE,BC',DE',HL' OUTBYTE: OLOOP: LD OR CALL RR CALL DEC JR SCF CALL RET D,8 A OUTBIT E OUTBIT D NZ,OLOOP OUTBIT ;Loop 8 times ;Clear Carry Flag ;Output start bit ;Rotate data into carry ;Output the carry ;Set carry flag ;Output stop bit

;************************************************************************************************************** ; Output one bit to tape (OUTBIT) ; Input: data in carry flag ; Destroyed Registers: AF,BC',DE',HL' OUTBIT: OUT0: EXX LD JR LD CALL LD JR LD CALL LD CALL EXX RET ;Save BC,DE,HL H,0 C,OUT1 L,ZERO_2K TONE2K L,ZERO_1K BITEND L,ONE_2K TONE2K L,ONE_1K TONE1K ;If data=1 then output 1 ;2KHz by 8 cycles, 1Khz by 2 cycles

OUT1: BITEND:

;2KHz by 4 cycles, 1Khz by 4 cycles

;Restore registers

;************************************************************************************************************** ; U T I L I T Y S U B R O U T I N E S ;************************************************************************************************************** ;************************************************************************************************************* ; Name: TONE ; Description: Generate a tone in the uPF-1's speaker ; Input: C -- period = 2*(44+13*C) clock states ; HL -- number of periods ; Output: (none) ; Destroys: AF,BC,DE,HL ; Calls subs: (none)

;************************************************************************************************************* TONE1K: TONE2K: TONE: SQWAVE: LD JR LD ADD LD LD OUT LD DJNZ XOR SBC JR RET C,F1KHZ TONE C,F2KHZ HL,HL DE,1 A,$FF (DIGIT),A B,C $ $80 HL,DE NZ,SQWAVE

;Half period: 44+13*C states. Double for half-cycle count ;Bit-7 tapeout

;Half period delay ;Toggle output ;Decrement one count

;************************************************************************************************************* ; Name: RAMCHK ; Description: Check if a given memory address is in RAM ; Input: HL contains the address to be checked ; Output: Z=0 if ROM or unmapped, Z=1 if RAM ; Destroys: AF ; Calls subs: (none) ;************************************************************************************************************* RAMCHK: LD CPL LD LD CPL LD CP RET A,(HL) (HL),A A,(HL) (HL),A (HL)

;************************************************************************************************************* ; Name: SCAN ; Description: Scan the keyboard and the display. Loop until a key is detected and if some key is already ; pressed when this routine starts execution, then return when next key is entered. ; Input: ; IX = Points to the buffer that contains display patterns. The 6 segments of the display ; requires 6 bytes of data.(IX) contains the pattern for rightmost character while ; (IX+5) contains the pattern for leftmost character. ; Output: Internal code of the key pressed in A) ;Convert the 2 byte data stored in DE to 7-segament display format. ; Output: The output is stored in the address field of DISPBF (display buffer), most significiant digit ; in DISPBF+5. This routine is usually used by monitor only. ; Destroys: AF,B,HL,AF',BC',DE' (All other registers except IY are also changed during execution, but they ; are restored before return. ; ; Calls subs: SCAN1 ;************************************************************************************************************* SCAN: PUSH LD BIT IX HL,TEST 7,(HL) ;Save IX. ;This bit is set if the use ;has entered illegal key. The ;display will be disabled as ;a warning ;is done by replacing JR LD Z,SCPRE IX,BLANK

to

the

user.

This the display ;buffer pointer IX by BLANK.

; Wait until all keys are released for 40 ms. ; (The execution time of SCAN1 is 10 ms, ; 40 = 10 * 4.) SCPRE: LD B,4 SCNX: CALL SCAN1 JR NC,SCPRE ;If any key is pressed, re-load ;the debounce counter B by 4. DJNZ SCNX RES 7,(HL) ;Clear error-flag. POP IX ;Restore original IX. ;Loop until any key is pressed. SCLOOP: CALL JR SCAN1 C,SCLOOP

; Convert the key-position-code returned by SCANl to ; key-internal-code. This is done by table-lookup. ; The table used is KEYTAB.

KEYMAP:

LD ADD LD LD RET

HL,KEYTAB A,L L,A A,(HL)

;************************************************************************************************************* ; Name: SCAN1 ; Description: Scans both the keyboard and the display (doesn't wait for a keypress) ; Total execution time is about 10 ms (exactly 9.95 ms => 17812 clock cycles @ 1.79 MHz). ; Input: IX = Points to the buffer that contains display patterns. The 6 segments of the display ; requires 6 bytes of data.(IX) contains the pattern for rightmost character while ; (IX+5) contains the pattern for leftmost character. ; ; Output: If NO KEY was pressed, Cy=1. Otherwise Cy=0 and 'A' holds the position code of the pressed key ; (If more than one key is pressed, SCAN1 will return the highest position code.) ; ; Destroys: AF,AF',BC',DE'. ; Calls subs: None ; ; Hardware note: ; In hardware, the display and keyboard are arranged as a 6 by 6 matrix. Each cloumn corresponds to one LED ; and six key buttons. In normal operation, at most one column is active. The pattern of the active LED is the ; data output on port C of 8255. The data input from bit 0 to 5 of port A are the status of key buttons in the ; active column. All signals on I/0 port are active low. ;************************************************************************************************************* SCAN1: SCF EX EXX ;Set carry flag. AF,AF'

; ; ; ; ; ; ; ;

Carry flag of F' is used to return the status of the keyboard. If any key is pressed during one scan, the flag is reset, otherwise it is set. Initially, this flag is set. A' register is used to store the position code of the key pressed. In this routine, 36 key positions are checked one by one. C register contains the code of the key being checked. The value of C is 0 at the beginning, and is increased by 1 after each check. So the code ranges from 0 to 23H (total 36 positions). On each check, if the input bit is 0 (key pressed), C register is copied into A1. The carry flag of F1 is set also. When some key is detected, the key positions after this key will still be checked. So if more than one key are pressed during one scan, the code of the last one will be returned. LD LD LD C,0 E,11000001B H,6 A,E (DIGIT),A A,(IX) (SEG7),A B,COLDEL $ A (SEG7),A A,E 11000000B (DIGIT),A B,6 A,(KIN) D,A D C,NOKEY A,C AF,AF' C KROW IX A,E 00111111B A 11000000B E,A ;Initial position code ;Scan from rightmost digit. ;to the active column.

KCOL:

LD OUT LD OUT LD DJNZ XOR OUT LD CPL OR OUT LD IN

;Activate one colunm.

;Delay 1.5 ms per digit. ;Deactivate all display segments

;Each column has 6 keys. At this moment, bit 0,1,2,3,4,5 of ;contains the status of each of the 6 keys in the active ;Store A into D. ;Rotate D one bit to the right, so bit 0 of D will pass to ;carry flag. ;Skip next 2 instructions if the key is not pressed. ;Key-in event, so get the key position-code and store in A ;Save A & Carry in AF' (This clears carry flag of F') ;Increase current key-code by 1. ;Loop until 6 keys in the ;active colums are all checked.

A column. KROW: the LD RR JR LD EX INC DJNZ INC LD AND RLC OR LD

NOKEY:

DEC JR LD ADD EXX EX RET

H NZ,KCOL DE,-6 IX,DE AF,AF' ;Get original IX.

;************************************************************************************************************* ; Name: ADDRDP ; Description: Convert binary data to 7-segment display format. ; Input: Convert the 2 byte data stored in DE to 7-segament display format. ; Output: The output is stored in the address field of DISPBF (display buffer), most significiant digit ; in DISPBF+5. This routine is usually used by monitor only. ; Destroys: AF,HL ; Calls subs: HEX7SG ;************************************************************************************************************* ADDRDP: LD LD CALL LD CALL RET LD CALL RET HL,DISPBF+2 A,E HEX7SG A,D HEX7SG HL,DISPBF HEX7SG

DATADP:

;************************************************************************************************************* ; Name: HEX7SG ; Description: Convert binary data to 7-segment display format. ; Input: The contents of A register contains the data to be converted ; Output: Display pattern for 2 digits. Low order digit in (HL), high order digit in (HL+1). Then ; HL becomes HL+2. In this way, if a new call to HEX7SG is made with new value in A,HL points ; automatically to the correct address. ; Destroys: AF,HL ; Calls subs: HEX7 ;************************************************************************************************************* HEX7SG: PUSH CALL LD INC POP RRCA RRCA RRCA RRCA CALL LD INC RET AF HEX7 (HL),A HL AF

HEX7 (HL),A HL

;************************************************************************************************************* ; Name: HEX7 ; Description: Convert binary data to 7-segment display format. ; Input: the 4 LSB bits of A contains the data to be converted ; Output: In A itself, the 7 segment data ready for the display buffer ; Destroys: AF ; Calls subs: none ;************************************************************************************************************* HEX7: PUSH LD AND ADD LD LD POP RET HL HL,SEGTAB $0F A,L L,A A,(HL) HL

;************************************************************************************************************* ; Name: RAMTEST ; Description: RAM memory self test. ; This routine tests the RAM memory between addresses 1800h thru 1FFFh (2K of 6116 Chip). ; Input: none. ; Output: none. ; Destroys: AF,BC,HL

; Calls subs: RAMCHK ;************************************************************************************************************* RAMTEST: RAMT: TNEXT: JR HALT CPI JP RST LD LD HL,$1800 BC,$800 CALL RAMCHK Z,TNEXT ;HALT CPU if error PE,RAMT 00H ;Display 'uPF--1'

;************************************************************************************************************* ; Name: ROMTEST ; Description: Monitor ROM code self-check. ; This routine sums the contents of address 0000 thru 0800 (2K), if the sum equals 00 then it ; resets the monitor via RST 0 instruction, otherwise HALT the CPU. ; Input: none. ; Output: none. ; Destroys: AF,BC,HL ; Calls subs: SUM ;************************************************************************************************************* ROMTEST: LD LD CALL JR HALT RST HL,0 BC,800H SUM Z,SUMOK ;HALT CPU if error 00h ;Display 'uPF--1'

SUMOK:

;************************************************************************************************************* INI3: LD (POWERUP),A ;Load power-code into (POWERUP). The monitor uses this ;location to find out if the RESET was 'cold' or 'warm' LD A,$55 LD (BEEPSET),A LD LD LD LD INC LD JP BEEP: PUSH LD LD LD LD CP JR CALL POP JP A,$44 (FBEEP),A HL,TBEEP (HL),$2F HL (HL),0 INI4 AF HL,FBEEP C,(HL) HL,(TBEEP) A,(BEEPSET) $55 NZ,NOTONE TONE AF KEYEXEC ;This two instructions set the beep frequency when a key is ;pressed. ;This four instructions set the time duration of the beep ;When a key is pressed (2 bytes)

;If data at (BEEPSET) is not $55 then there is no beep sound ;when a key is pressed. ;KEYEXEC determines what action should be taken when a key is ;pressed. This routine uses the following information to ;determine the proper service routine: ; 1) The key-code, ; 2) STATE ; 3) STMINOR (Minor-State).

NOTONE:

;************************************************************************************************************* ; This are the branch tables for each key and state. The first entry of each table is a base address and ; the following entries are an offset ( 1 byte long ). In this way only one byte is needed for each jump ; instead of 2 bytes. ;************************************************************************************************************* .ORG KSUBFUN: $0737

.WORD KINC .BYTE -KINC+KINC .BYTE -KINC+KDEC .BYTE -KINC+KGO .BYTE -KINC+KSTEP .BYTE -KINC+KDATA .BYTE -KINC+KSBR

KFUN:

HTAB:

ITAB:

DTAB:

GTAB:

.BYTE .BYTE .WORD .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .WORD .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .WORD .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .WORD .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .WORD .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE

-KINC+KINS -KINC+KDEL KPC -KPC+KPC -KPC+KADDR -KPC+KCBR -KPC+KREG -KPC+KMV -KPC+KRL -KPC+KWT -KPC+KRT HFIX -HFIX+HFIX -HFIX+HAD -HFIX+HDA -HFIX+HRGFIX -HFIX+HMV -HFIX+HRL -HFIX+HWT -HFIX+HRT -HFIX+HRGAD -HFIX+HRGDA IFIX -IFIX+IFIX -IFIX+IAD -IFIX+IDA -IFIX+IRGFIX -IFIX+IMV -IFIX+IRL -IFIX+IWT -IFIX+IRT -IFIX+IRGAD -IFIX+IRGDA DFIX -DFIX+DFIX -DFIX+DAD -DFIX+DDA -DFIX+DRGFIX -DFIX+DMV -DFIX+DRL -DFIX+DWT -DFIX+DRT -DFIX+DRGAD -DFIX+DRGDA GFIX -GFIX+GFIX -GFIX+GAD -GFIX+GDA -GFIX+GRGFIX -GFIX+GMV -GFIX+GRL -GFIX+GWT -GFIX+GRT -GFIX+GRGAD -GFIX+GRGDA

;************************************************************************************************************* ; KEYTAB is a table to convert key-position-code into key-internal-code ;************************************************************************************************************* KEYTAB: K0: Kl: K2: K3: K4: K5: K6: K7: K8: K9: K0A: K0B: K0C: K0D: K0E: K0F: K10: .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE $03 $07 $0B $0F $20 $21 $02 $06 $0A $0E $22 $23 $01 $05 $09 $0D $13 ;HEX_3 ;HEX_7 ;HEX_B ;HEX_F ;NOT USED ;NOT USED ;HEX_2 ;HEX_6 ;HEX_A ;HEX_E ;NOT USED ;NOT USED ;HEX_1 ;HEX_5 ;HEX_9 ;HEX_D ;STEP

K11: K12: K13: K14: K15: K16: K17: K18: K19: K1A: K1B: K1C: KID: K1E: K1F: K20: K21: K22: K23: MPF_I:

.BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .WORD .WORD .WORD .WORD .WORD .WORD .WORD .WORD .WORD .WORD

$1F $00 $04 $08 $0C $12 $1E $1A $18 $1B $19 $17 $1D $15 $11 $14 $10 $16 $1C $30 $02 $02 $0F $1F $A1 $00 $00 $00 $00 $00 $00 $03 $03 $8F $02 $1F $AE $02 $AE $B6 $AE $1F $AE $02 $03 $03 $8F $00 $AE $8F $B3 $00 $AE $B3 $00 $00 $0F $AE $8F $00 $0F $00 $00 $00 $02 $BE $8F $03 $3F0F $A78D $B38F $3785 $3F4F $A7CD $B3CF $37C5 $3007 $30B6

;TAPERD ;HEX_0 ;HEX_4 ;HEX_8 ;HEX_C ;GO ;TAPEWR ;CBR ;PC ;REG ;ADDR ;DEL ;RELA ;SBR ;;DATA ;+ ;INS ;MOVE ;'1' ;'-' ;'-' ;'F' ;'P' ;'u'

BLANK:

ERR_:

SYS_SP:

ERR_SP:

;'r' ;'r' ;'E' ;'-' ;'P' ;'S' ;'-' ;'S' ;'Y' ;'S' ;'P' ;'S' ;'-' ;'r' ;'r' ;'E' ;'S' ;'E' ;'D' ;'S' ;'D' ;'F' ;'S' ;'E' ;'F'

STEPTAB:

REG_:

;'-' ;'G' ;'E' ;'R' ;'AF' ;'BC' ;'DE' ;'HL' ;'AF.' ;'BC.' ;'DE.' ;'HL.' ;'IX' ;'IY'

RGTAB:

.WORD .WORD .WORD .WORD .WORD .WORD SEGTAB: .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE .BYTE

$AE1F $300F $0F37 $0F85 $0F77 $0FC5 $BD $30 $9B $BA $36 $AE $AF $38 $BF $BE $3F $A7 $8D $B3 $8F $0F

;'SP' ;'IF' ;'FH' ;'FL' ;'FH.' ;'FL.' ;'0' ;'1' ;'2' ;'3' ;'4' ;'5' ;'6' ;'7' ;'8' ;'9' ;'A' ;'B' ;'C' ;'D' ;'E' ;'F'

;************************************************************************************************************* ; SYSTEM RAM AREA: ;************************************************************************************************************* USERSTK: SYSSTK: STEPBF: DISPBF: REGBF: USERAF: USERBC: USERDE: USERHL: UAFP: UBCP: UDEP: UHLP: USERIX: USERIY: USERSP: USERIF: FLAGH: FLAGL: FLAGHP: FLAGLP: USERPC: ADSAVE: BRAD: BRDA: STMINOR: STATE: POWERUP: TEST: ATEMP: HLTEMP: TEMP: IM1AD: BEEPSET: FBEEP: TBEEP: .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .BLOCK .END ;************************************************************************************************************* ; END OF MONITOR PROGRAM ;************************************************************************************************************* 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 2 4 2 1 1 2 .BLOCK .BLOCK 7 6 .ORG $1F9F .BLOCK 16 .ORG $1FAF

;Contains the address being displayed now. ;Breakpoint address ;Data of break point address ;Minor state ;State ;Power-up initialization ;Flag, bit 0 -- set when function of subfunction key is hit ; bit 7 -- set when illegal key is entered. ;Temporary storage ;Temporary storage ;See comments on routine GDA ;Contains the address of Opcode 'FF' service routine ;(RST 38H, mode 1 interrupt, etc.) ;Default value is 55H ;Beep frequency ;Time duration of beep

Вам также может понравиться