JMON_SOURCE_01.asm
tec1group_Software/monitors/JMon/JmonSource/JMON_SOURCE_01.asm
;
;JMON - JIM'S MONITOR
;BY JIM ROBERTSON
;
;
;FILENAME : JMON_SRC_01.ASM
;VERSION : 1
;
;This version has been beautified by Brian Chiha, December 2021
;and was cleaned up by Mark Jelic, June 2021
;[Lovingly] RESTORED TO SOURCE FROM PDF LISTING(S) FEBRUARY 2021
;[by Craig Jones. What a champion effort! - MJ]
;
;THE PHOTOCOPIED PDF LISTING WAS CONVERTED TO A TEXT FILE VIA OCR
;THE MISSING PAGE 9 WAS TAKEN FROM ANOTHER VERSION OF THE LISTING
;PAGE NUMBERS REFER TO THE PHOTOCOPIED LISTING PDF FILE
;
;
;GLOSSARY
;
;CURRENT EDITING LOCATION (082E)
;THIS IS THE ADDRESS THAT IS USUALLY DISPLAYED IN THE ADDRESS SECTION ON THE TEC LED
;DISPLAY. IT IS THE ADDRESS THAT IS SUBJECT TO MODIFICATION BY JMON.
;
;MONITOR CONTROL BYTE (MCB) (082B)
;THIS BYTE CONTAINS THE INFORMATION OF THE CURRENT WORKING STATE OF JMON. THE INFORMATION
;HELD IN THIS BYTE IS:
;1 - THE CURRENT MODE OF JMON.
;E.G. DATA, ADDRESS OR FUNCTION (NOT SHIFT AS SHIFT IS TESTED AND HANDLED DURING THE DATA
;KEY HANDLER ROUTINE). BITS 4 AND 5 ENCODE THE CURRENT MODE IN THE FOLLOWING WAY. BOTH
;BITS ARE LOW FOR THE DATA MODE, BIT 4 IS HIGH FOR THE ADDRESS MODE, BITS 4 AND 5 ARE HIGH
;FOR THE FUNCTION MODE. BIT 4 IS CALLED THE ADDRESS/FUNCTION BIT As THE SOFTWARE ONLY
;NEEDS TO TEST THIS BIT TO FIND IF EITHER THE ADDRESS OR FUNCTION MODE IS ACTIVE. BIT 5
;IS THE FUNCTION MODE ENABLED BIT.
;2 - THE NUMBER OF THE CURRENT FUNCTION I.E. 1,2 OR 3.
;THIS IS ENCODED IN BITS 2 AND 3. IF NO FUNCTION OR FUNCTION-1 IS ENABLED THEN BOTH BITS
;ARE LOW. IF FUNCTION-2 IS SELECTED THEN BIT 2 IS HIGH AND BIT 3 IS LOW. IF FUNCTION-3 IS
;SELECTED THEN BIT 3 IS HIGH AND BIT 2 IS LOW.
;3 - THE NUMBER OF NIBBLES ENTERED
;THIS IS ENCODED IN BITS 0 AND 1. IF NO NIBBLES HAVE BEEN ENTERED IN THE CURRENT EDITING
;LOCATION THEN BOTH BIT ARE LOW. IF ONE NIBBLE HAS BEEN ENTERED THEN BIT 0 IS HIGH AND
;BIT 1 IS LOW IS TWO NIBBLES HAVE BEEN ENTERED THEN BIT 0 IS LOW AND BIT 1 IS HIGH. JMON
;USES THESE BITS WHEN DECIDING ON THE AUTO-INCREMENT FEATURE. BITS 6 AND 7 ARE NOT USED.
;
;DISPLAY BUFFER ADDRESS - (082C/D)
;THE CONTENTS OF 082C/D POINTS TO THE LOCATION IN MEMORY OF THE 6 BYTE DISPLAY BUFFER
;(0800 FOR JMON AND 0806 FOR THE STEPPER). THE DISPLAY BUFFER ADDRESS POINTS TO THE LOWEST
;ADDRESS OF THE DISPLAY BUFFER WHICH CONTAINS THE LOW ORDER DATA DISPLAY BYTE.
;
;KEY PLANT
;THE KEY PLANT IS A FAKE KEY STROKE THAT MAY BE GENERATED BY THE "DURING SCAN/REY LOOP"
;USER PATCH. THE PLANT ALLOWS JMON'S MONITOR FUNCTIONS TO BE SOFTWARE CONTROLLED E.G. YOU
;MAY WISH TO VIEW THE CONTENTS ,OF MEMORY BYTE BY BYTE. WITH THE KEY PLANT YOU CAN SET JMON
;UP TO AUTOMATICALLY INCREMENT THE CURRENT EDIT LOCATION EVERY FEW SECONDS.
;THE PLANT IS IDENTIFIED BY THE USER PATCH STORING THE REQUIRED KEY VALUE IN, AND SETTING
;BIT 7 OF THE INPUT KEY BUFFER (0820).
;
;AUTO KEY STATUS BYTE (082A)
;THIS BYTE HOLDS THE INFORMATION REQUIRED FOR THE AUTO KEY REPEAT SECTION. THE INFORMATION
;HELD IN THIS BYTE IS EITHER ONE OF THE FOLLOWING:
;A "NEXT KEY DETECTION WILL BE A FIRST DETECTION" SO JMON WILL PROCESS THE KEY IMMEDIATELY
;(BIT 7 HIGH) . A TIMER (BITS 0-6) THAT COUNTS, A DELAY FOR THE AUTO. REPEAT TIMING.
;
;KEY PRESS FLAG (0825)
;THIS FLAG IS USED TO REMEMBER IF THE ONE KEY PRESS HAS ALREADY BEEN DETECTED AND PROCESSED.
;THIS PREVENTS THE SAME KEY BEING PROCESSED EACH TIME THE SOFTWARE FINDS THAT IT IS PUSHED.
;THIS IS THE WAY IT WORKS:
;THE KEY PRESS FLAG 1S ZEROED BY THE JMON DEFAULT VARIABLES AND THIS FLAGS A "NO KEY
;PRESSED" STATE. WHEN A KEY IS DETECTED THEN THIS FLAG IS TESTED AND IF ZERO THEN THE KEY
;IS ACCEPTED AS A FIRST KEY PRESS. IN THIS CASE THE KEY PRESS FLAG IS THEN SET TO FF TO
;REMEMBER THAT THE KEY PRESS HAS BEEN DETECTED. IF A KEY IS DETECTED AND THIS FLAG BYTE
;IS NOT ZERO, THEN THE KEY IS IGNORED. WHEN THE SOFTWARE FINDS THAT NO KEY IS BEING PRESSED,
;THEN THIS FLAG IS CLEARED TO ALLOW THE NEXT KEY PRESS DETECTED TO BE PROCESSED.
;THIS FLAG IS USED BY THE RST 08, RST 10 RST 18 AND RST 20 KEYBOARD ROUTINES AS DESCRIBED
;IN ISSUE 15 TALKING ELECTRONICS AND ALSO THE STEPPER SOFTWARE.
;THE AUTO KEY REPEAT ROUTINE DOES NOT USE THIS FLAG BYTE, DO NOT CONFUSE THIS FLAG WITH
;THE AUTO KEY STATUS BYTE WHICH IS USED BY THE AUTO KEY REPEAT SECTION.

;TAPE FILE INFORMATION BLOCK
;THIS IS A 12 BYTE BLOCK THAT CONTAINS THE FOLLOWING INFORMATION:
;THE START ADDRESS OF THE BLOCK, THE NUMBER OF BYTES IN THE BLOCK, THE FILE NUMBER AND AN
;OPTIONAL GO ADDRESS OR FFFF IF OPTIONAL GO IS DISABLED. THE OTHER 4 BYTES ARE NOT USED
;AT THIS STAGE.
;THIS BLOCK IS OUTPUTTED AND INPUTTED TO AND FROM THE TAPE ON EACH TAPE OPERATION.
;
;"NEXT PC" BUFFER
;THIS IS A TEMPORARY PLACE TO SAVE THE RETURN ADDRESS WHICH IS THEN USED AS THE ACTUAL PC
;VALUE FOR THE NEXT INSTRUCTION STEPPED.
;
;FORCED HARD RESET
;THIS IS ACHIEVED BY HOLDING DOWN A KEY WHEN RELEASING THE RESET. THE HARD RESET CAUSES
;JMON TO RE-BOOT ITS VARIABLES AND ALSO MASK OFF ALL THE USER PATCHES (EXCEPT THE RESET
;PATCH). THE MAIN PURPOSE OF A FORCED HARD RESET IS TO RECOVER THE TEC IF A USER PATCH
;ENTERS A CONTINUOUS LOOP.
;

REG_TBL:    EQU     0794H - 2                           ;BASE OF REGISTER NAME TABLE
DISP_BUFF:  EQU     0800H                               ;Current displayed Address Buffer
DISP_DBUFF: EQU     0804H                               ;Current displayed Data Buffer
DISP_D2BUF: EQU     0805H                               ;Character #2 of the Data Display Buffer
DISP_STEP:  EQU     0806H                               ;Stepper's 6 Byte Display Buffer

;USER VARIABLE START LOCATION
V_KEY:      EQU     0820H                               ;KEY BUFFER
V_LCD:      EQU     0821H                               ;LCD ON/OFF FLAG
V_BEEP:     EQU     0822H                               ;SOUND ON/OFF
V_ALT_ADDF: EQU     0823H                               ;GO AT ALTERNATE GO ADDRESS IF AA
V_STEP_TMR: EQU     0824H                               ;STEPPER KEY CONTROL/TIMER
V_KEY_PRES: EQU     0825H                               ;KEY PRESS FLAG
V_SPARE1:   EQU     0826H                               ;UNUSED
V_AUTO:     EQU     0827H                               ;AUTO INCREMENT ON/OFF
V_ALT_ADDR: EQU     0828H                               ;ALT GO ADDR/SOFT RESET EDIT LOCATION
V_KAUTO:    EQU     082AH                               ;AUTO KEY STATUS BYTE
V_MCB:      EQU     082BH                               ;MONITOR CONTROL BYTE (MCB)
V_DISPLAY:  EQU     082CH                               ;DISPLAY BUFFER ADDRESS (using 7seg Display codes)
V_CEL:      EQU     082EH                               ;CURRENT EDITING LOCATION (CEL)

;The following are the JUMP addresses that a CALLED by JMON,
;after they are copied from the ROM (starting @ 071Fh) to the RAM @ 0830h, on a Hard Reset.
;They point back to routines in the ROM, so not sure why this was done.
HL_2_DIS:   EQU     0830H                               ;CONVERT HL TO DISPLAY CODE @ 01D5h
A_2_DISP:   EQU     0833H                               ;CONVERT A TO DISPLAY CODE @ 01DAh
LED_SCAN:   EQU     0836H                               ;LED SCAN ROUTINE @ 01BAh
SET_DOTS:   EQU     0839H                               ;SET LED DOTS @ 01EEh
BEEPBEEP:   EQU     083CH                               ;RESET TONES @ 0224h (TWO BEEPS)
BEEP:       EQU     083FH                               ;TONE @ 0227h
SCAN_IO:    EQU     0842H                               ;SCAN/KEY/LCD/PATCH LOOP @ 0181h
DO_DISP:    EQU     0845h                               ;SOFT JMON ENTRY L0845 @ 00B2h
LCD_DISP:   EQU     0848H                               ;LCD ROUTINE @ 023Ch

;Various other Monitor Locations to help with its functionality
PATCH_BEF:  EQU     084BH                               ;PRE-SCAN USER PATCH
PATCH_DUR:  EQU     084EH                               ;USER "DURING LOOP" PATCH
PATCH_AFT:  EQU     0851H                               ;USER "AFTER KEY" PATCH
STEP_NEXT:  EQU     0858H                               ;ADDRESS OF INSTRUCTION JUST STEPPED
STEP_CREG:  EQU     085AH                               ;CURRENT REG No. BUFFER
RE_ENTRY:   EQU     0860H                               ;RE-ENTRY ADDRESS BUFFER
STEP_PREV:  EQU     0868H                               ;"NEXT PC" BUFFER
STEP_REGS:  EQU     086Ah                               ;SHIFT 7 ROUTINE START (REG DISPLAY)
HL_SAVE:    EQU     086EH                               ;HL SAVE ON RESET
STEP_HL:    EQU     0870H                               ;STEPPER INITIAL HL
STEP_SP:    EQU     087EH                               ;Stack Pointer Save Buffer
PERI_MENU:  EQU     0880H                               ;PERIMITER MENU SETUP
PERI_D_TBL: EQU     0882H                               ;PERIMITER DATA SEGMENT TABLE
PERI_W_ADD: EQU     0884H                               ;PERIMITER WINDOW ENTRY START LOCATION
PERI_W_CUR: EQU     0886H                               ;CURRENT PERIMETER WINDOW
PERI_W_MAX: EQU     0887H                               ;TOTAL PERIMETER WINDOWS
PERI_J_ADR: EQU     0888H                               ;PERIMITER GO JUMP ADDRESS
TAPE_ACTN:  EQU     088AH                               ;TAPE OPERATION (0=LOAD, 2=TEST, 3=CHECKSUM)
PERI_W_AC1: EQU     088CH                               ;PERIMITER ACTIVE WINDOW + 1
MENU_NO:    EQU     088FH                               ;MENU ENTRY NUMBER
MENU_J_TBL: EQU     0891H                               ;MENU JUMP TABLE
MENU_A_TBL: EQU     0893H                               ;MENU ADDRESS SEGMENT TABLE
MENU_D_TBL: EQU     0895H                               ;MENU DATA SEGMENT TABLE
MENU_KEYRN: EQU     0897H                               ;MENU DATA KEY RETURN HANDLER (USE C9 IF N/A)
TAPE_FILE:  EQU     0898H                               ;TAPE FILE NAME (NUMBER)
TAPE_START: EQU     089AH                               ;TAPE START ADDRESS (DEFAULT TO FFFF)
TAPE_END:   EQU     089CH                               ;TAPE END ADDRESS
TAPE_AUTOG: EQU     089EH                               ;TAPE AUTO GO ADDRESS (DEFUALT TO FFFF)
TAPE_O_FIL: EQU     08A4H                               ;TAPE OUTPUT FILE NAME (NUMBER)
TAPE_O_STA: EQU     08A6H                               ;TAPE OUTPUT START ADDRESS
TAPE_O_LEN: EQU     08A8H                               ;TAPE OUTPUT LENGTH
TAPE_O_GO:  EQU     08AAH                               ;TAPE OUTPUT AUTO GO ADDRESS
PATCH_REQ:  EQU     08B0H                               ;RESET PATCH REQUIRED IF 0xAA IS HERE
PATCH_STA:  EQU     08B1H                               ;RESET PATCH START ADDRESS. 0x08B1-0x08B2
PATCH_VAR:  EQU     08B3H                               ;RESET PATCH VARIABLE.  0X08B4 Size of Patch
PATCH_CHK:  EQU     08B5h                               ;RESET PATCH CHECKSUM
PATCH_ADR:  EQU     08B6H                               ;RESET PATCH ADDRESS. 0x08B6-0x08B7
USER_TBL:   EQU     08C0H - 2                           ;User Table -2
RST_FLAG:   EQU     08FFH                               ;Reset Flag
JMON_UTIL:  EQU     3800H                               ;JMON UTILITIES ADDRESS START LOCATION 
JMON_UJMP:  EQU     381Eh                               ;START OF THE JUMP TABLE IN THE JMON UTILITIES

;IO Port ASSIGNMENTS
KEYBOARD:   EQU     0x00                                ;KEYBOARD ENCODER
DSCAN:      EQU     0x01                                ;DISPLAY CATHODE DRIVER LATCH
DSEGMENT:   EQU     0x02                                ;DISPLAY SEGMENT DRIVER LATCH

;DAT BOARD
P_DAT:      EQU     0x03                                ;DAT BOARD LATCH
P_LCDDATA:  EQU     0x84                                ;LCD DATA REGISTER
P_LCDINST:  EQU     0x04                                ;LCD INSTRUCTION REGISTER

;KEYBOARD REFERENCES
K_PLUS:     EQU     0x10                                ;+ KEY
K_MINUS:    EQU     0x11                                ;- KEY
K_GO:       EQU     0x12                                ;GO KEY
K_ADDR:     EQU     0x13                                ;ADDRESS KEY


;AT THE START OF JMON, HL IS SAVED IN ITS SINGLE STEPPER BUFFER ADD THE SOFT RESET DISPLAY
;VALUE IS PLACED IN THE CURRENT EDIT LOCATION BUFFER. THE ROUTINE THEN IS CONTINUED AT $0068.
ORG     $0000
            LD      (HL_SAVE), HL                       ;SAVE HL PART OF REGISTER SAVE
            LD      HL, (V_ALT_ADDR)                    ;GET SOFT RESET INITIAL EDIT
            JR      MON_START                           ;LOCATION AND CONTINUE AT 006B

;RST 08 AND RST 10 (CF AND D7)
;THESE TWO COMBINE TOGETHER TO SIMULATE A HALT INSTRUCTION. THIS IS DONE BY LOOPING UNTIL
;THE CURRENT (IF ANY) KEY PRESS IS RELEASED (RST 08), AND THEN LOOPING UNTIL A NEW KEY
;PRESS IS DETECTED (RST 10).

RST08:      RST     20H                                 ;TEST FOR KEY PRESS
            JR      Z, RST08                            ;LOOP IF KEY PRESSED
            NOP                                         ;ELSE
            NOP                                         ;MOVE
            NOP                                         ;TO
            NOP                                         ;NEXT
            NOP                                         ;RST
RST10:      RST     20H                                 ;TEST FOR KEY AGAIN
            JR      NZ, RST10                           ;LOOP IF KEY NOT PRESSED
            AND     0x1F                                ;MASK OFF JUNK BITS
            LD      I, A                                ;STORE IN INTERRUPT REGISTER
            RET                                         ;DONE

;RST 18 (DF) AND RST 20 (E7)
;RST 18 CALLS THE LED SCAN ROUTINE ONCE THEN MOVES ON INTO RST 20 THAT THEN CALLS A KEYBOARD
;READ ROUTINE.
;THE KEYBOARD MUST BE READ CONTINUOUSLY OVER A PERIOD OF TIME, AS THE DATA AVAILABLE SIGNAL
;(BIT 6, PORT 3) (USUALLY) PULSES, WHEN A KEY IS PRESSED, IN TIME WITH THE KEY ENCODER
;CHIP'S SCANNING. IF THE KEY BOARD IS READ ONLY ONCE EVERY SECOND, THEN THE SOFTWARE MAY
;AND PROBABLY) WILL TARE SEVERAL SECONDS TO DETECT THE KEY.
;THE NUMBER OF READ CYCLES FOR THE KEYBOARD IS LOADED INTO B.

RST18:      PUSH    HL                                  ;SAVE HL
            PUSH    DE                                  ;AND DE
            CALL    LED_SCAN                            ;CALL SCAN ROUTINE
            POP     DE                                  ;RECOVER DE
            POP     HL                                  ;AND HL
            NOP                                         ;NEXT RST
RST20:      PUSH    BC                                  ;SAVE BC
            LD      B, 0x20                             ;B = NUMBER OF KEYBOARD SCAN LOOPS
            CALL    KEY_READ                            ;CALL KEY READER/VALIDATER
            POP     BC                                  ;RECOVER BC
            RET                                         ;DONE

;RST 28 (EF)
;START STEPPING FROM THE INSTRUCTION FOLLOWING THE RST 28
RST28:      EX      (SP), HL                            ;GET RETURN ADDRESS FROM THE STACK
            LD      (STEP_NEXT), HL                     ;PUT IN "NEXT PC" BUFFER
            EX      (SP), HL                            ;FIX UP STACK
            EI                                          ;ENABLE INTERRUPTS
            RET                                         ;STEPPING WILL OCCUR AFTER RETURN
            DB      0xFF                                ;SPARE

;RST 30 (F7)
;TEST THE BUSY STATE OF THE LCD AND LOOP WHILE BUSY
RST30:      IN      A, (P_LCDINST)                      ;READ STATUS BIT FROM LCD
            RLCA                                        ;PUT IN CARRY
            JR      C, RST30                            ;LOOP IF LCD BUSY
            RET                                         ;DONE
            DB      0xFF,0xFF                           ;SPARE

;RST 38 (FF)
;INTERRUPT HANDLER FOR STEPPER AND BREAK-POINTS
RST38:      JP      STEPPER                             ;JUMP TO STEPPER ROUTINE
            DB      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF       ;SPARE

;JUMP TABLE FOR EXTERNAL SOFTWARE TO USE JMON ROUTINES
L0041:      JP      MENU_RTN                            ;MENU ROUTINE
L0044:      JP      PERI_RTN                            ;PERIMETER HANDLER ENTRY
L0047:      JP      MENU_SFT                            ;SOFT MENU ENTRY
L004A:      JP      ERR_ENTRY                           ;ERR-IN ENTRY
L004D:      JP      PF_ENTRY                            ;PASS/FAIL/MENU
L0050:      JP      PERI_SFT                            ;SOFT PERIMETER HANDLER ENTRY
            DB      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF  ;SPARE
            DB      0xFF,0xFF,0xFF,0xFF                 ;SPARE

;SHIFT-2 ROUTINE
;THIS STORES THE CURRENT EDIT LOCATION IN THE "NEXT PC" BUFFER. THE INTERRUPTS ARE THEN
;ENABLED AND THE PROGRAM JUMPS TO THE USER ROUTINE TO BE STEPPED. STEPPING OCCURS AT THE
;CURRENT EDIT LOCATION (CEL).
FN_STEPPER: LD      HL, (V_CEL)                         ;PUT CURRENT EDIT LOCATION IN
            LD      (STEP_NEXT), HL                     ;"NEXT PC" BUFFER
            EI                                          ;ENABLE INTERRUPTS
            JP      (HL)                                ;START STEPPING

;NMI HANDLER (IMMEDIATE RETURN)
            RETN                                        ;IGNORE NMI
            RST     38H                                 ;RESERVED
            RST     38H                                 ;FOR A "Post Burn"
            RST     38H                                 ;JUMP LOCATION

;CONTINUATION OF MONITOR
MON_START:  IM      1                                   ;SET INTERRUPT MODE 1 FOR STEPPER
            LD      (V_CEL), HL                         ;STORE SOFT RESET INITIAL CEL
            LD      HL, MON_START2                      ;LOAD HL WITH RE-ENTRY ADDRESS
            JP      SAVE_REGS                           ;JUMP TO SAVE REGISTERS


;RE-ENTRY POINT AFTER SAVING REGISTERS
MON_START2: LD      SP, V_KEY                           ;SET STACK (to the Keyboard Buffer??)
            CALL    RST_PATCH                           ;CALL RESET PATCH HANDLER
            RST     20H                                 ;LOOK FOR FORCED HARD RESET
            JR      Z, HARD_RST                         ;JUMP KEY PRESSED TO HARD RESET
            LD      A, (RST_FLAG)                       ;CHECK HARD/RESET FLAG
            CP      0xAA                                ;FOR AA
            JR      Z, SOFT_RST                         ;JUMP TO SOFT RESET IF AA

;HARD RESET
;MONITOR DEFAULT VARIABLES ARE RE-BOOTED AND USER PATCHES MASKED OFF.

HARD_RST:   LD      HL, DEF_VARS                        ;LOAD HL WITH START OF JMON DEFAULT
            LD      DE, V_KEY                           ;VARIABLES ROM TABLE
            LD      BC, 0x002B                          ;DE IS THE RAM DE(stination)
            LDIR                                        ;AND BC THE COUNT: MOVE TABLE
            LD      B, 0x03                             ;MASK OF THE THREE USER PATCHES
            LD      A, 0xC9                             ;BY PUTTING A RETURN AT THE FIRST
L0095:      LD      (DE), A                             ;LOCATION OF EACH
            INC     DE                                  ;
            INC     DE                                  ;
            INC     DE                                  ;
            DJNZ    L0095                               ;
            CALL    LCD_RESET                           ;INITIALIZE/TEST FOR THE LCD
            XOR     A                                   ;CLEAR HARD/SOFT
            LD      (RST_FLAG), A                       ;RESET FLAG

;THIS SECTION IS THE SOFT RESET SECTION. IT IS ALSO PART OF THE HARD RESET SECTION.
SOFT_RST:   LD      HL, JMON_UTIL                       ;TEST FOR JMON UTILITIES ROM
            LD      A, (HL)
            CP      0xC3                                ;AND CALL ITS RESET ROUTINE
            CALL    Z, JMON_UTIL                        ;IF REQUIRED
            CALL    BEEPBEEP                            ;CALL RESET TONE ROUTINE (BEEP BEEP)
FN_S_RST:   XOR     A                                   ;CLEAR MONITOR CONTROL BYTE
            LD      (V_MCB), A                          ;0 = DATA MODE, NO NIBBLES ENTERED

;EACH TIME A KEYBOARD INPUT OR USER PATCH "PLANT", IS PROCESSED, THE PROGRAM JUMPS BACK
;TO HERE SO THE DISPLAYS MAY BE UP-DATED.

J_DISPUPD:  LD      HL, (V_CEL)                         ;GET CURRENT EDIT LOCATION (CEL)
            LD      BC, (V_DISPLAY)                     ;AND DISPLAY BUFFER ADDRESS
            CALL    HL_2_DIS                            ;AND CONVERT CEL TO DISPLAY CODE
            LD      A, (HL)                             ;AND THEN CONVERT CONTENTS OF
            CALL    A_2_DISP                            ;CEL TO DISPLAY CODE
            CALL    SET_DOTS                            ;CALL THE SET DOTS ROUTINE
            CALL    SCAN_IO                             ;CALL SCAN/KEY/LCD/PATCH ROUTINE

;THE SECTION BELOW IS EXECUTED WHEN EITHER A KEY OR KEY "PLANT" IS DETECTED IN THE
;SCAN/KEY/LCD/PATCH ROUTINE ROUTINE
KEY_MGMT:
            LD      HL, (V_CEL)                         ;POINT HL TO CURRENT EDIT LOCATION
            LD      C, A                                ;PRESERVE INPUT KEY IN C
            LD      A, (V_MCB)                          ;GET MONITOR CONTROL BYTE (MCB)
            BIT     4, A                                ;TEST FOR ADDRESS OR FUNCTION MODE
            LD      B, A                                ;STORE MCB IN B
            LD      A, C                                ;GET INPUT KEY BACK IN A
            JR      NZ, KEY_ADDR                        ;JUMP IF ADDRESS OR FUNCTION MODE
KEY_PLUS:   CP      K_PLUS                              ;TEST FOR "+"
            JR      NZ, KEY_MINUS                       ;JUMP IF NOT TO TEST FOR "-"

;"+" KEY HANDLER-(WHEN IN DATA MODE ONLY)

            INC     HL                                  ;ADD 1 TO CURRENT EDIT LOCATION

;COMMON CEL AND MCB UP-DATER
;SEVERAL SECTIONS JUMP HERE TO STORE AN UP-DATED CEL AND CLEAR THE NIBBLE COUNTER.

L00D8:      LD      (V_CEL), HL                         ;STORE CEL
            LD      A, B                                ;GET MCB

;COMMON MCB UP-DATER
;SOME KEY HANDLER SECTION THAT DON'T REQUIRE.A NEW CEL (OR HAVE ALREADY STORED IT) JUMP HERE.

L00DC:      AND     0xFC                                ;CLEAR NIBBLE COUNTER
            LD      (V_MCB), A                          ;STORE MCB
L00E1:      JR      J_DISPUPD                           ;JUMP BACK TO UPDATE DISPLAY
KEY_MINUS:  CP      K_MINUS                             ;TEST FOR "-"
            JR      NZ, KEY_GO                          ;JUMP IF NOT TO TEST FOR "GO"

;"-" KEY HANDLER (WHEN IN DATA MODE ONLY)
            DEC     HL                                  ;DECREASE CEL ADDRESS BY ONE
            JR      L00D8                               ;JUMP TO COMMON CEL AND MCB UP-DATER
KEY_GO:     CP      K_GO                                ;TEST FOR GO
            JR      NZ, KEY_ADDR                        ;JUMP IF NOT TO TEST FOR "AD"

;"GO" HANDLER (WHEN IN DATA MODEONLY)
            LD      A, (V_ALT_ADDF)                     ;TEST FOR ALTERNATE GO ADDRESS
            CP      0xAA                                ;IF (0823)=AA
            JR      Z, L00FA                            ;JUMP IF SET FOR ALTERNATE GO ADDR
            LD      HL, (V_CEL)                         ;ELSE GET CURRENT EDIT LOCATION
            JR      L00FD                               ;SKIP ALTERNATE JUMP ADDRESS FETCH
L00FA:      LD      HL, (V_ALT_ADDR)                    ;GET ALTERNATE GO ADDRESS
L00FD:      LD      DE, DO_DISP                         ;PUT RETURN ADDRESS ON STACK
            PUSH    DE
            JP      (HL)                                ;START USER EXECUTION

;TEST HERE FOR ADDRESS KEY. IF THE KEY PRESSED IS NOT THE ADDRESS KEY, THEN A JUMP IS
;PERFORMED. OTHERWISE THE ADDRESS KEY IS PROCESSED.

KEY_ADDR:   CP      0x13                                ;TEST FOR ADDRESS KEY
            JR      NZ, L0111                           ;0= IF NOT TO DATA KEY HANDLER
            LD      A, B                                ;GET MONITOR CONTROL BYTE (MCB)
            BIT     5, B                                ;TEST FOR FUNCTION MODE AND JUMP TO
            JR      NZ, L010D                           ;CLEAR FUNCTION MODE BITS IF SO
            XOR     0x10                                ;ELSE TOGGLE ADDRESS MODE BIT
L010D:      AND     0xD3                                ;CLEAR ALL FUNCTION MODE BITS
            JR      L00DC                               ;LOOP BACK TO COMMON MCB UP-DATER

;A TEST FOR ADDRESS/FUNCTION MODE IS DONE. IF IN ADDRESS OR FUNCTION MODE A JUMP IS PERFORMED.
L0111:      LD      A, B                                ;GET MCB
            BIT     4, A                                ;TEST FOR ADDRESS OR FUNCTION MODE
            JR      NZ, KEY_CTRL                        ;JUMP IF EITHER MODE

;A TEST FOR SHIFT IS DONE AND A JUMP IS PERFORMED IF IN THE SHIFT MODE TO THE FUNCTION/SHIFT HANDLER.
            IN      A, (KEYBOARD)                       ;TEST FOR THE SHIFT KEY
            BIT     5, A                                ;AND JUMP IF SHIFT IS PRESSED
            JR      Z, KEY_FUNC                         ;TO THE FUNCTION HANDLER

;ANY TIME A DATA KEY IS PRESSED WHILE IN THE DATA MODE, IT IS PROCESSED STARTING HERE.
KEY_DATA:   LD      A, B                                ;GET MCB
            AND     0x03                                ;MASK IT DOWN TO BYTE COUNTER
            CP      0x02                                ;AND TEST FOR TWO NIBBLES ENTERED
            LD      A, B                                ;INPUT KEY VALUE BACK IN A
            JR      NZ, L0132                           ;JUMP IF NOT READY FOR AUTO INC
            PUSH    AF                                  ;SAVE MCB
            LD      A, (V_AUTO)                         ;TEST AUTO INC MASK
            OR      A                                   ;IF NOT ZERO THEN JUMP AS USER
            JR      NZ, L012F                           ;HAS SWITCHED OFF AUTO INC MODE
            INC     HL                                  ;ELSE INCREMENT CEL BEFORE ENTERING
            LD      (V_CEL), HL                         ;NEW NIBBLE AND STORE NEW CEL
L012F:      POP     AF                                  ;RECOVER MON CONTROL BYTE IN A
            AND     0xFC                                ;CLEAR BYTE COUNTER (BITS 0 AND 1)
L0132:      INC     A                                   ;ADD ONE TO NIBBLE COUNTER
            LD      (V_MCB), A                          ;STORE IT
            LD      A, (V_KEY)                          ;GET INPUT KEY FROM INPUT BUFFER
            JR      L014C                               ;JUMP TO ENTER IT

;TEST HERE FOR A CONTROL KEY WHILE IN EITHER THE ADDRESS OR FUNCTION MODE AND JUMP TO
;ENCODE THE FUNCTION NUMBER BITS (2 AND 3 OF MCB). IF NOT A CONTROL KEY, THEN TEST FOR
;THE FUNCTION MODE AND JUMP TO FUNCTION JUMP CONTROL IF SO, ELSE SERVICE DATA KEY FOR
;ADDRESS MODE.

KEY_CTRL:   LD      A, (V_KEY)                          ;GET INPUT KEY FROM INPUT BUFFER
            BIT     4, A                                ;TEST FOR CONTROL KEY (+,- OR GO)
            JR      NZ, ENC_FUNC                        ;JUMP IF CONTROL TO FUNCTION ENCODER
            BIT     5, B                                ;TEST FUNCTION MODE
            JR      NZ, KEY_FUNC                        ;JUMP IF SO TO FUNCTION JUMP CONTROL

;DATA KEY PRESS WHILE IN THE ADDRESS MODE
            LD      HL, V_CEL                           ;POINT HL TO CEL BUFFER
            RLD                                         ;AND SHIFT IN THE NEW NIBBLE
            INC     HL                                  ;AND MOVE THE OTHERS ACROSS
L014C:      RLD                                         ;THIS RLD USED BY DATA MODE ALSO
L014E:      JR      L00E1                               ;JUMP (VIA A JUMP) TO UP-DATE DISPLAYS

;FUNCTION AND SHIFT JUMP CONTROL
;BITS 2 AND 3 OF THE MONITOR CONTROL BYTE (MCB) ARE THE FUNCTION IDENTIFIER BITS.
;IF BOTH ARE ZERO THEN EITHER FUNCTION 1 IS SELECTED OR NO FUNCTION IS SELECTED. BECAUSE
;THIS IS THE ALSO THE NO FUNCTION MODE ENABLED STATE, THE SHIFT KEY, WHICH DOES NOT AFFECT
;THE MONITOR CONTROL BYTE, WILL ALSO WILL INVOKE FUNCTION 1. (THEREFORE THIS ROUTINE DOES
;NOT NEED TO TEST FOR THE SHIFT KEY).
;IF BIT 2 IS HIGH THEN FUNCTION 2 IS SELECTED AND IF BIT 3 IS HIGH THEN FUNCTION 3 IS
;SELECTED.
;DURING THIS ROUTINE, HL IS LOADED TO THE BASE OF THE REQUIRED JUMP TABLE MINUS TWO BYTES
;(ONE ENTRY). THIS IS BECAUSE THE OFFSET PROVIDED FROM THE KEYBOARD HAS BEEN INCREMENTED
;BY ONE. THIS SAVES TESTING FOR ZERO INPUT WHICH WOULD NOT ALLOW THE TABLE ACCESSING TO
;WORK CORRECTLY. THE REQUIRED BASE IS FOUND BY EXAMINING THE STATE OF THE BITS 2 AND 3 OF
;THE MONITOR CONTROL BYTE (MCB) AND LOADING HI, ACCORDINGLY.
;AS EACH ENTRY IS TWO BYTES LONG, THE TABLE POINTER (THE VALUE INSIDE HL), IS INCREMENTED
;TWICE FOR EACH DECREMENT OF THE INPUT VALUE (FROM THE KEYBOARD). WHEN THE REQUIRED TABLE
;ENTRY IS FOUND, 17 IS PUT' INSIDE CEL (VIA_ DE) AND THE ROUTINE JUMPS TO PART OF THE "GO"
;KEY ROUTINE TO CREATE A RETURN ADDRESS ON THE STACK AND EXECUTE THE SELECTED ROUTINE.

KEY_FUNC:   LD      A, B                                ;PUT MONITOR CONTROL BYTE IN A
            AND     0x0C                                ;MASK IT DOWN TO FUNCTION BITS
            LD      HL, L07E0 - 2                       ;JMON FUNCTION JUMP TABLE BASE -2
            JR      Z, L0162                            ;JUMP IF FUNCTION 1 OR SHIFT
            LD      HL, USER_TBL                        ;LOAD HL WITH USER TABLE -2
                                                        ;*** Value is 08BE as User Table is at 08C0
            CP      0x04                                ;TEST FOR FUNCTION 2
            JR      Z, L0162                            ;JUMP IF FUNCTION 2 (USER FUNCTION)
            LD      HL, JMON_UJMP                       ;OTHERWISE MUST BE FUNCTION 3
L0162:      LD      A, (V_KEY)                          ;GET INPUT KEY FROM INPUT BUFFER
            INC     A                                   ;ADD ONE IN CASE IT WAS ZERO
            LD      B, A                                ;PUT IN B TO USE AS A LOOP COUNTER
L0167:      INC     HL                                  ;LOOK THROUGH TABLE
            INC     HL                                  ;FOR RIGHT JUMP VECTOR
            DJNZ    L0167
            LD      E, (HL)                             ;PUT IT IN HL
            INC     HL                                  ;VIA DE
            LD      D, (HL)
            EX      DE, HL                              ;JUMP TO CREATE RETURN ADDRESS AND
            JR      L00FD                               ;EXECUTE SELECTED ROUTINE

;FUNCTION NUMBER ENCODER
;THIS SECTION ENCODES THE FUNCTION IDENTIFIER BITS (BITS 2 AND 3) IN THE MONITOR CONTROL
;BYTE (BITS 2 AND 3) THEN SETS THE FUNCTION ENABLE BIT (BIT 5).
;THE FUNCTION IDENTIFIER BITS ARE DERIVED FROM THE LEAST TWO SIGNIFICANT BITS OF THE INPUT
;CONTROL KEY (+, AND GO). THESE ARE SHIFTED LEFT TWICE TO ALIGN THEM TO THE FUNCTION
;SELECT BITS (BITS 2 AND 3) IN THE MCB. THE INPUT CONTROL KEY IS IN THE ACCUMULATOR ON
;ENTRY AND THE MONITOR CONTROL BYTE (MCB) IN B.

ENC_FUNC:   AND     0x03                                ;MASK DOWN CONTROL KEY
            RLCA                                        ;SHIFT IT LEFT TWICE TO ALIGN BITS 0
            RLCA                                        ;AND 1 TO FUNCTION IDENTITY BITS IN MCB
            OR      0x20                                ;SET FUNCTION MODE ENABLED FLAG
            LD      C, A                                ;SAVE IN C
            LD      A, B                                ;GET CURRENT MCB
            AND     0xD3                                ;CLEAR ANY PREVIOUS FUNCTION BITS
            OR      C                                   ;MERGE TOGETHER
            LD      (V_MCB), A                          ;STORE MCB
            JR      L014E                               ;JUMP VIA JUMPS TO UP-DATE DISPLAYS

;THIS IS THE SCAN/KEY/LCD/PATCH ROUTINE. THIS ROUTINE LOOPS SCANNING THE LED DISPLAY AND
;SERVICING THE "DURING LOOP" USER PATCH UNTIL A KEY PRESS IS VALIDATED BY THE AUTO-KEY
;REPEAT SECTION. THE INPUT KEY IS RETURNED IN THE ACCUMULATOR AND IN THE INPUT BUFFER AT
;0820 WITH THE ZERO FLAG SET AND CARRY CLEARED.
;THREE PATCHES ARE SUPPORTED IN THIS ROUTINE. THEY ARE A PATCH BEFORE LOOP, A PATCH DURING
;THE LOOP AND A PATCH AFTER A VALID KEY PRESS.
;THE "PLANT" IS A VALUE INSERTED INTO THE INPUT BUFFER (0820) BY THE DURING LOOP PATCH.
;THE "PLANT" VALUE IS IDENTIFIED BY BIT 7 OF THE INPUT BUFFER BEING SET. BIT 7 IS RESET
;BEFORE RETURNING TO SERVICE THE PLANT.
;THIS ROUTINE USES A BYTE AT 082A, CALLED THE AUTO KEY STATUS BYTE AS A FLAG AND TIMER
;TO GENERATE THE AUTO REPEAT DELAY.
J_SCANKEY:
            CALL    LCD_DISP                            ;CALL LCD ROUTINES
            CALL    PATCH_BEF                           ;CALL PRE-SCAN USER PATCH
L0187:      CALL    LED_SCAN                            ;CALL SCAN
            CALL    PATCH_DUR                           ;CALL USER "DURING LOOP" PATCH
            LD      HL, V_KEY                           ;TEST KEY INPUT BUFFER BIT 7 FOR A
            BIT     7, (HL)                             ;"PLANT" INSERTED BY USER DURING
            RES     7, (HL)                             ;PATCH: RESET BIT 7 RETURN TO
            RET     NZ                                  ;SERVICE "PLANT" IF BIT 7 NOT ZERO
            RST     20H                                 ;TEST FOR KEY PRESS VIA RST 20
            LD      HL, V_KAUTO                         ;SET HL TO POINT TO AUTO KEY STATUS
            JR      C, L019F                            ;JUMP IF A KEY IS PRESSED
            LD      (HL), 0x80                          ;ELSE SET AUTO KEY STATUS TO
            JR      L0187                               ;NO KEY STATE AND CONTINUE LOOP
L019F:      CALL    KEY_GET                             ;CALL UNIVERSAL KEY INPUTTER
            BIT     7, (HL)                             ;TEST AUTO KEY STATUS FOR FIRST KEY
            JR      NZ, L01B6                           ;JUMP IF SO TO SET LONG KEY DELAY
            DEC     (HL)                                ;ELSE COUNT DOWN KEY DELAY
            JR      NZ, L0187                           ;LOOP IF NOT READY FOR KEY REPEAT
            LD      (HL), 0x0C                          ;ELSE SET SHORT TIME DELAY BETWEEN
L01AB:      CALL    PATCH_AFT                           ;KEYS: CALL USER "AFTER KEY" PATCH
            CALL    BEEP                                ;CALL KEY TONE
            XOR     A                                   ;SET ZERO FLAG AND CLEAR CARRY
            LD      A, (V_KEY)                          ;PUT INPUT KEY IN A
            RET                                         ;AND RETURN FOR KEY SERVICE
L01B6:      LD      (HL), 0x70                          ;SET KEY TIMER FOR LONG DELAY
            JR      L01AB                               ;JUMP TO SERVICE PATCH, TONE ETC.

;THIS IS THE LED SCAN ROUTINE.
J_LEDSCAN:
            LD      B, 20H                              ;B IS THE SCAN BIT
            LD      HL, (V_DISPLAY)                     ;GET ADDRESS OF DISPLAY BUFFER
L01BF:      LD      A, (HL)                             ;GET FIRST BYTE
            OUT     (DSEGMENT), A                       ;AND OUTPUT IT TO SEGMENTS
            LD      A, B                                ;GET SCAN BIT
            OUT     (DSCAN), A                          ;OUTPUT IT TO COMMONS
            LD      B, 40H                              ;CREATE SHORT
L01C7:      DJNZ    L01C7                               ;DELAY IN B
            INC     HL                                  ;INCREASE HL TO NEXT DISPLAY BYTE
            LD      B, A                                ;GET SCAN BIT BACK IN B
            XOR     A                                   ;CLEAR THE LAST PORT OUTPUTTED TO
            OUT     (DSCAN), A                          ;TO PREVENT "GHOSTING"
            RRC     B                                   ;SHIFT SCAN BIT ACROSS TO NEXT
            JR      NC, L01BF                           ;COMMON: WHEN SCAN BIT FALLS INTO
            OUT     (DSEGMENT), A                       ;CARRY SCAN IS TERMINATED: CLEAR
            RET                                         ;PORT 2 AND RETURN

;THIS ROUTINE CONVERTS HL TO DISPLAY CODE AND STORE THE DISPLAY CODE IN A BUFFER POINTED
;TO BY BC.
J_HL2CODE:
            LD      A, H                                ;PUT H IN A
            CALL    A_2_DISP                            ;CONVERT A TO DISPLAY CODE
            LD      A, L                                ;NOW DO FOR L

;THIS SECTION CONVERTS THE BYTE IN A TO TWO DISPLAY BYTES.
J_A2CODE:
            PUSH    AF                                  ;SAVE A
            RLCA                                        ;SHIFT MSN TO LSN PLACE
            RLCA                                        ;FOR NIBBLE AT A TIME CONVERSION
            RLCA
            RLCA
            CALL    L01E3                               ;CONVERT FIRST NIBBLE
            POP     AF                                  ;RECOVER A TO CONVERT SECOND NIBBLE
L01E3:      AND     0x0F                                ;MASK OF HIGH NIBBLE
            LD      DE, SEG_TBL                         ;SET DE TO BASE OF CONVERSION
            ADD     A, E                                ;TABLE: ADD A TO BASE
            LD      E, A                                ;UPDATE POINTER
            LD      A, (DE)                             ;GET DISPLAY CODE
            LD      (BC), A                             ;STORE IN DISPLAY BUFFER
            INC     BC                                  ;INCREMENT DISPLAY BUFFER POINTER
            RET                                         ;NIBBLE CONVERSION DONE

;SET DOTS
;THIS ROUTINE SETS THE DOTS IN THE DISPLAY BUFFER. IF IN ADDRESS MODE THEN 4 DOTS ARE SET
;IN THE ADDRESS DISPLAY BUFFER, IF IN A FUNCTION MODE, THEN ONE DOT IN THE ADDRESS DISPLAY
;- RIGHT MOST FOR FUNCTION 1 SECOND RIGHT FOR FUNCTION 2 AND THIRD RIGHT FOR FUNCTION 3.
;IF IN THE DATA MODE THEN 2 DOTS IN THE DATA DISPLAY BUFFER OR ONE DOT, ON THE RIGHTMOST
;DISPLAY, IF TWO NIBBLES HAVE BEEN ENTERED AND IN THE AUTO-INCREMENT MODE.
J_SETDOTS:
            LD      B, 0x02                             ;SET B FOR 2 DOTS
            LD      HL, (V_DISPLAY)                     ;PUT DISPLAY BUFFER IN HL
            LD      A, (V_MCB)                          ;GET MONITOR CONTROL BYTE (MCB)
            BIT     4, A                                ;TEST FOR ADDRESS OR FUNCTION MODE
            JR      Z, L0214                            ;JUMP IF NOT TO DO DATA DOTS
            BIT     5, A                                ;TEST ONLY FOR FUNCTION MODE
            JR      NZ, L0206                           ;JUMP IF FUNCTION MODE
            LD      B, 4                                ;ADDRESS MODE SO SET B FOR 4 DOTS
L0200:      SET     4, (HL)                             ;SET DOT IN DISPLAY BUFFER
            INC     HL                                  ;NEXT LOCATION
            DJNZ    L0200                               ;DO 4 TIMES
            RET                                         ;DONE

L0206:      DEC     B                                   ;FUNCTION MODE: SET B FOR ONE DOT
            BIT     3, A                                ;TEST FOR FUNCTION 3
            JR      NZ, L0211                           ;JUMP IF FUNCTION 3 TO ADD HL+1
            BIT     2, A                                ;TEST FOR FUNCTION 2
            JR      NZ, L0210                           ;JUMP IF FUNCTION 2 TO ADD HL+2
L020F:      INC     HL                                  ;INCREMENT HL TO POINT TO THE
L0210:      INC     HL                                  ;REQUIRED DISPLAY BYTE
L0211:      INC     HL                                  ;
            JR      L0200                               ;JUMP TO SET DOT
L0214:      INC     HL                                  ;DATA MODE: HL NOW POINTS TO SECOND
            LD      C, A                                ;LEFT MOST DISPLAY BUFFER: SAVE MCB
            LD      A, (V_AUTO)                         ;IN C: TEST AUTO INCREMENT ENABLE
            OR      A                                   ;FLAG
            JR      NZ, L020F                           ;JUMP IF NO AUTO INCREMENT TO SET BOTH
            BIT     1, C                                ;DATA DOTS: TEST BYTE COUNTER FOR 2
            JR      Z, L020F                            ;NIBBLES: JUMP IF NOT TO SET BOTH DATA
            INC     HL                                  ;DOTS: ELSE SKIP DOT ON ONE DISPLAY
            DEC     B                                   ;AND DECREASE DOT COUNT FROM 2 TO 1
            JR      L020F                               ;JUMP TO ADJUST HL AND SET DOTS

;MASKABLE RESET TONE ROUTINE
;IF 0822 IS NOT ZERO THEN NO TONE
J_TONEX2:
            CALL    BEEP                                ;CALL TONE

J_TONE:
;MASKABLE TONE ROUTINE
            LD      A, (V_BEEP)                         ;TEST SOUND MASK
            OR      A                                   ;
            RET     NZ                                  ;NO TONE IF NOT ZERO
            LD      C, 0x40                             ;LOAD C WITH PERIOD
            LD      L, 0x31                             ;LOAD L WITH NUMBER OF CYCLES
            XOR     A                                   ;CLEAR A
L0231:      OUT     (DSCAN), A                          ;OUT TO SPEAKER
            LD      B, C                                ;
L0234:      DJNZ    L0234                               ;DELAY FOR PERIOD
            XOR     0x80                                ;TOGGLE SPEAKER BIT
            DEC     L                                   ;DECREMENT CYCLE COUNT
            JR      NZ, L0231                           ;LOOP UNTIL ZERO
            RET                                         ;DONE

;LCD ROUTINE
;IF 0821 IS NOT ZERO, THEN LCD HAS BEEN MASKED OFF BY EITHER THE USER OR THE LCD
;INTIALIZER/TESTER ROUTINE AND NO ACTION IS TAKEN ON THE LCD. THE RST 30 (F7) IS USED
;EXTENSIVELY TO TEST AND WAIT FOR THE LCD BUSY FLAG. THROUGHOUT THESE NOTES, THE INVISIBLE
;INTERNAL CURSOR ON THE LCD IS REFERRED TO AS THE CURSOR, WHILE THE ">" ON THE LCD IS
;REFERRED TO AS THE PROMPT.
J_LCD:
            LD      A, (V_LCD)                          ;TEST LCD MASK
            OR      A
            RET     NZ                                  ;NOT ZERO = LCD NOT REQUIRED OR FITTED
            LD      A, 0x80                             ;SET LCD CURSOR TO HOME
            OUT     (P_LCDINST), A
            RST     30H                                 ;WAIT UNTIL LCD READY
            CALL    LCD_LINE1                           ;CALL SET-UP AND OUTPUT FIRST LINE
            LD      A, 0xC0                             ;SET CURSOR TO BOTTOM LINE
            OUT     (P_LCDINST), A
            RST     30H                                 ;WAIT
            CALL    LCD_LINE2                           ;CALL ROUTINE TO OUTPUT BOTTOM LINE
            JR      LCD_PROMPT                          ;JUMP TO PROMPT ROUTINE

;SET-UP
;MODIFY CURRENT EDIT LOCATION ADDRESS IN HL SO THAT IT POINTS TO A BYTE AT AN ADDRESS
;ENDING IN EITHER 0 OR 8.

LCD_LINE1:  LD      HL, (V_CEL)                         ;GET CEL AND PUT LOW BYTE IN A
            LD      A, L                                ;THEN MASK OFF THE 3 LOWEST BITS
            AND     0xF8                                ;AS THE ADDR OF THE FIRST BYTE ON
            LD      L, A                                ;THE LCD WILL END WITH 0 OR 8

;OUTPUT A LINE.  FIRST DISPLAY BASE ADDRESS THEN THE NEXT FOUR BYTES. EG:
;   0900>FF AA FF FF
;WHERE A RIGHT ARROW WILL BE PLACED ON THE CURRENT ADDRESS BYTE
LCD_LINE2:  CALL    HL_2_LCD                            ;CALL "HI TO ASCII OUTPUT"
            LD      B, 04                               ;SET B FOR 4 BYTES ON A LINE
L025F:      LD      A, 0x20                             ;LOAD A WITH ASCII SPACE
            OUT     (P_LCDDATA), A                      ;CHARATER AND OUTPUT IT
            RST     30H                                 ;WAIT
            LD      A, (HL)                             ;GET BYTE TO DISPLAY
            CALL    A_2_LCD                             ;CONVERT AND OUTPUT IT
            INC     HL                                  ;POINT TO NEXT BYTE
            DJNZ    L025F                               ;DO FOR 4 BYTES
            RET                                         ;DONE

;CONVERT HL TO ASCII (VIA CONVERT A) AND OUTPUT IT
HL_2_LCD:   LD      A, H                                ;CONVERT AND
            CALL    A_2_LCD                             ;OUTPUT H
            LD      A, L                                ;THEN L

;CONVERT A TO ASCII AND OUTPUT IT
A_2_LCD:    PUSH    AF                                  ;SAVE A FOR SECOND NIBBLE
            RRCA                                        ;SHIFT HIGH NIBBLE ACROSS
            RRCA                                        ;
            RRCA                                        ;
            RRCA                                        ;
            CALL    LCD_NIBBLE                          ;CALL NIBBLE CONVERTER
            POP     AF                                  ;RECOVER LOW NIBBLE
LCD_NIBBLE: AND     0x0F                                ;MASK OFF HIGH NIBBLE
            ADD     A, 0x90                             ;CONVERT TO
            DAA                                         ;ASCII
            ADC     A, 0x40                             ;USING THIS
            DAA                                         ;AMAZING ROUTINE
LCD_OUT:    OUT     (P_LCDDATA), A                      ;OUTPUT IT
            RST     30H                                 ;WAIT
            RET                                         ;DONE

;LCD PROMPT AND MODE WORD OUTPUT
;THE 3 LOWEST BITS OF THE CURRENT EDIT LOCATION (CEL) ARE USED AS A DISPLACEMENT WHICH IS
;ADDED TO A TABLE BASE. THE TABLE ENTRIES ARE THE LCD ADDRESSES OF THE PROMPT LOCATIONS.
;IF THE AUTO INCREMENT MODE IS ON AND 2 NIBBLES HAVE BEEN ENTERED, THE DISPLACEMENT IS
;INCREMENTED SO THAT THE NEXT PROMPT ADDRESS TABLE ENTRY WILL BE ACCESSED TO MOVE THE
;PROMPT TO ITS NEXT SCREEN LOCATION. THE TABLE IS 9 ENTRIES LONG. 8 ARE FOR THE SPACES
;BETWEEN THE DATA BYTES AND THE NINTH IS TO PARK THE PROMPT AT THE TOP LEFT-HAND CORNER
;WHEN A SCREEN CHANGE IS DUE

LCD_PROMPT: LD      A, (V_CEL)                          ;GET LOW BYTE OF CEL
            AND     0x07                                ;MASK IT DOWN TO THE 3 LOWEST BITS
            LD      C, A                                ;SAVE IN C
            LD      A, (V_AUTO)                         ;TEST FOR AUTO INCREMENT MODE
            OR      A                                   ;O=ON
            LD      A, (V_MCB)                          ;GET MCB
            LD      D, A                                ;PUT MCB IN D
            JR      NZ, L029B                           ;JUMP IF AUTO INCREMENT MODE OFF
            BIT     1, A                                ;TEST FOR 2 NIBBLES ENTERED: JUMP
            JR      Z, L029B                            ;IF NOT: ELSE INCREMENT
            INC     C                                   ;DISPLACEMENT TO ADVANCE TO
L029B:      LD      A, C                                ;NEXT PROMPT LOCATION ADDRESS
            LD      HL, LCDPMT_TBL                      ;LOAD HL WITH BASE OF PROMPT
            ADD     A, L                                ;TABLE AND ADD DISPLACEMENT
            LD      L, A                                ;PUT LOW BYTE OF TABLE ADDRESS
            LD      A, (HL)                             ;IN L AND GET PROMPT ADDRESS IN A
            OUT     (P_LCDINST), A                      ;AND OUTPUT PROMPT ADDRESS TO LCD
            RST     30H                                 ;WAIT
            LD      A, 0x3E                             ;LOAD A WITH ASCII FOR ">"
            OUT     (P_LCDDATA), A                      ;OUTPUT PROMPT
            RST     30H                                 ;WAIT

;OUTPUT MODE WORD TO BOTTOM LEFT CORNER OF THE LCD.
;IF THE MODE IS EITHER DATA OR ADDR, THEN THE FOUR ASCII BYTES ARE OUTPUTTED. IF IN THE
;FUNCTION MODE, THEN ONLY THREE BYTES FROM THE TABLE ARE OUTPUTTED AND THEN THE FUNCTION
;NUMBER IS CALCULATED AND OUTPUTTED.
;NOTICE THAT FROM THE TABLE BASE THE FIRST ENTRY (DATA) HAS A ZERO DISPLACEMENT WHILE THE
;SECOND (ADDR) HAS A DISPLACEMENT OF 4 AND THE THIRD (Fs-) HAS A DISPLACEMENT OF 12.
;IF YOU LOOK AT THE TABLE AT 07AD, YOU WILL SEE THAT IT IS STAGGERED WITH THE THIRD ENTRY
;12 BYTES AWAY FROM THE BASE.

            LD      A, 0xC0                             ;SET CURSOR TO BOTTOM LINE
            OUT     (P_LCDINST), A                      ;OUTPUT
            RST     30H                                 ;AND WAIT
            LD      A, D                                ;PUT MONITOR CONTROL BYTE (MCB) IN A
            RRCA                                        ;SHIFT MODE BITS TO BITS 2 AND 3
            RRCA                                        ;TO USE AS TABLE DISPLACEMENT
            LD      D, A                                ;SAVE IN D AND MASK OFF ALL BITS
            AND     0x0C                                ;EXCEPT THE 2 THAT FLAG BETWEEN DATA,
            LD      HL, LCDFNC_TBL                      ;ADDR AND FUNCTION: A=0 IF DATA, 4 IF
            ADD     A, L                                ;ADDR, 12 IF FUNCTION, NOTE THAT TABLE
            LD      L, A                                ;IS STAGGERED (SEE 07AD): ADD A TO BASE
            CP      0xB9                                ;IF A=B9 THEN MODE IS FUNCTION MODE
            LD      BC, 0484H                           ;LOAD C WITH PORT, B WITH BYTE COUNT
            JR      Z, L02C7                            ;JUMP IF FUNCTION MDDE TO OUT 3 BYTES
L02C1:      OUTI                                        ;OUT (HL) TO (C) B=B-1
            RST     30H                                 ;HL=HL+1: WAIT FOR LCD BUSY FLAG
            JR      NZ, L02C1                           ;LOOP UNTIL B=0
            RET                                         ;DONE

L02C7:      LD      B, 0x03                             ;ONLY THREE BYTES FOR FUNCTION MODE
            CALL    L02C1                               ;CALL THE OUTPUT ROUTINE ABOVE
            LD      A, D                                ;PUT MCB (SHIFTED RIGHT TWICE) IN A
            AND     0x03                                ;MASK IT DOWN TO GET JUST THE FUNCTION
            ADD     A, 0x31                             ;NUMBER BITS: ADD ASCII "1"
            JR      LCD_OUT                             ;JUMP TO OUTPUT FUNCTION NUMBER

;-END OF MONITOR ROUTINES- (EXCEPT KEYBOARD READER AT 06AD)

;LCD PROMPT MOVING ROUTINES. (SHIFT AND FUNCTION 1)
;THESE ROUTINES ALTER THE CURRENT EDIT LOCATION ADDRESS AND STORE IT IN ITS BUFFER. WHEN
;THE RETURN IS DONE, JMON IS RE-ENTERED AT 00132 (VIA THE SOFT RE-ENTRY JUMP AT L0845, THE
;ADDRESS OF WHICH HAS BEEN PLACED ON THE STACK BY PART OF THE "GO" ROUTINE).
FN_FORW4:   LD      DE, 0x0004                          ;DE= +4
L02D6:      LD      HL, (V_CEL)                         ;PUT CEL IN HL
            ADD     HL, DE                              ;ADD TO GET NEW CEL
            LD      (V_CEL), HL                         ;STORE IN CEL BUFFER
            RET                                         ;DONE

FN_BACK4:   LD      DE, 0xFFFC                          ;DE= -4
            JR      L02D6                               ;JUMP TO ADD
FN_BACK1:   LD      DE, 0xFFFF                          ;DE= -1
            JR      L02D6                               ;JUMP TO ADD
FN_FORW1:   LD      DE, 0x0001                          ;DE= +1
            JR      L02D6                               ;JUMP TO ADD
FN_FORW8:   LD      DE, 0x0008                          ;DE= +8
            JR      L02D6                               ;JUMP TO ADD
FN_BACK8:   LD      DE, 0xFFF8                          ;DE= -8
            JR      L02D6                               ;JUMP TO ADD

;RESET PATCH CHECKER.
;TESTS FOR PATCH REQUIREMENT AND UP TO THE FIRST 256 BYTES OF THE PATCH ROUTINE. THE
;CHECKSUM FEATURE ENSURES A WAY TO CHECK THAT THE PATCH OR PATCH VARIABLES HAVE NOT BEEN
;CORRUPTED BY A SYSTEM CRASH, OTHERWISE YOU MAY NEVER REGAIN CONTROL OF THE COMPUTER UNLESS
;YOU TURN IT OFF, (AND LOSE THE CONTENTS OF YOUR MEMORY - YOU CANNOT RECOVER IT BY A FORCED
;HARD RESET AS THE USER PATCH IS EXECUTED BEFORE THE FORCED HARD RESET TEST). (A FORCED
;HARD RESET IS WHEN A KEY IS HELD DOWN WHEN THE RESET KEY IS RELEASED).
;IF YOU HAVE A NON VOLATILE MEMORY AT 0800 THE SITUATION WOULD BE ABSOLUTELY HOPELESS
;WITHOUT THIS CHECKER ROUTINE.
;A VARIABLE CAN BE PASSED TO YOUR PATCH ROUTINE IN THE "C" REGISTER. TO DO THIS THE VARIABLE
;IS PLACED AT ADDRESS LOCATION 08B3.

RST_PATCH:  LD      A, (PATCH_REQ)                      ;TEST FOR RESET PATCH REQUIRED
            CP      0xAA
            RET     NZ                                  ;RETURN IF NOT
            LD      BC, (PATCH_VAR)                     ;PUT NO OF BYTES IN B VARIABLE IN C
            LD      HL, (PATCH_STA)                     ;START IN HL
            XOR     A                                   ;CLEAR A
L0305:      ADD     A, (HL)                             ;ADD CHECKSUM
            INC     HL
            DJNZ    L0305                               ;UNTIL B=0
            LD      HL, PATCH_CHK                       ;POINT TO REQUIRED CHECKSUM
            CP      (HL)                                ;TEST FOR EQUAL
            RET     NZ                                  ;ABORT IF NOT
            LD      HL, (PATCH_ADR)                     ;ELSE GET START ADDR
            JP      (HL)                                ;AND DO RESET PATCH

;STEPPER ROUTINE
;THE STEPPER ROUTINE IS BROKEN UP INTO SEVERAL SECTIONS. THE FIRST IS THE REGISTER SAVE,
;WHERE ALL THE Z80 USER REGISTERS ARE STORED IN MEMORY.

STEPPER:    LD      (STEP_HL), HL                       ;STORE HL IN ITS REGISTER STACK SPOT
            LD      HL, STEP_CONT                       ;LOAD HL WITH RETURN ADDRESS - Was 0x0344

;MONITOR JUMPS TO HERE ON RESET TO PRESERVE USER REGISTERS.
SAVE_REGS:  LD      (RE_ENTRY), HL                      ;STORE RE-ENTRY ADDRESS IN BUFFER
            LD      HL, (STEP_NEXT)                     ;GET ADDRESS OF INSTRUCTION JUST
            LD      (STEP_PREV), HL                     ;STEPPED AND PUT IT IN "NEXT PC"
            LD      (STEP_SP), SP                       ;BUFFER: SAVE STACK POINTER VALUE
            POP     HL                                  ;GET RETURN ADDR, THIS IS THE ADDRESS
            LD      (STEP_NEXT), HL                     ;OF NEXT BYTE TO STEP: STORE IN
            LD      SP, STEP_SP                         ;"NEXT PC" BUFFER: LOAD REGISTER DUMP
            EX      AF, AF'                             ;STACK: PUSH ALTERNATE REGISTERS
            EXX                                         ;FIRST
            PUSH    HL                                  ;SAVE ALL REGISTERS
            PUSH    DE
            PUSH    BC
            PUSH    AF
            PUSH    IY
            PUSH    IX
            EX      AF, AF'
            EXX
            DEC     SP
            DEC     SP
            PUSH    DE
            PUSH    BC
            PUSH    AF
            LD      HL, (RE_ENTRY)                      ;RE-ENTER CALLING ROUTINE VIA
            JP      (HL)                                ;THE ADDRESS IT SUPPLIED AT 0860
FN_REGDIS:
            LD      SP, STEP_REGS                       ;SHIFT 7 ROUTINE START (REG DISPLAY)

;THE REGISTERS HAVE BEEN SAVED. NOW THE DISPLAY AND KEYBOARD HANDLER IS SET UP. THE STACK
;IS DECREMENTED BY TWO TO POINT TO THE "PC" BUFFER. THE ADDRESS IN THE "PC" BUFFER IS THE
;ADDRESS OF THE INSTRUCTION JUST STEPPED.
;THE NUMBER OF THE FIRST REGISTER (1 FOR "PC") IS PUT INTO THE CURRENT REGISTER NUMBER
;BUFFER.

STEP_CONT:  LD      HL, DISP_STEP                       ;CREATE NEW DISPLAY BUFFER
            LD      (V_DISPLAY), HL                     ;
            DEC     SP                                  ;DECREASE SP BY 2 TO POINT TO THE
            DEC     SP                                  ;"PC" BUFFER

;WHEN UP-DATING THE DISPLAY, THE ROUTINE MAY JUMP BACK TO HERE IF THE FIRST DISPLAY IS REQUIRED.
L034C:      LD      A, 0x01                             ;SET UP FOR THE FIRST REGISTER (PC)
            LD      (STEP_CREG), A                      ;DISPLAY

;OR HERE IF IT HAS ALTERED THE CURRENT REGISTER NUMBER IN ITS STORAGE LOCATION (085A).
L0351:      LD      A, (STEP_CREG)                      ;DISPLAY LOOP STARTS HERE

;HL IS LOADED WITH THE STACK POINTER VALUE, (WHICH POINTS TO THE "PC" BUFFER), MINUS TWO.
;THE TWO IS SUBTRACTED BECAUSE AN EXTRA TWO WILL BE ADDED TO HL DURING THE REGISTER BUFFER
;CALCULATOR (IMMEDIATELY BELOW) AS THE NUMBER OF THE FIRST REGISTER IS 1 AND NOT ZERO.
            LD      HL, 0xFFFE                          ;HL=-2
            ADD     HL, SP                              ;HL=SP-2
L0358:      INC     HL                                  ;INCREMENT HL TO POINT TO THE
            INC     HL                                  ;CURRENT REGISTER BUFFER
            DEC     A                                   ;INDICATED BY THE NUMBER IN A
            JR      NZ, L0358

;HL NOW POINTS TO THE CURRENT REGISTER BUFFER. THIS SECTION PUTS THE REGISTER(S) CONTENT(S)
;INTO HL AND CONVERTS IT TO DISPLAY CODE AND STORE THE DISPLAY CODE IN THE DISPLAY BUFFER.

            LD      A, (HL)                             ;GET 16 BIT VALUE
            INC     HL                                  ;AND PUT IT
            LD      H, (HL)                             ;BACK INTO
            LD      L, A                                ;HL
            LD      BC, (V_DISPLAY)                     ;PUT DISPLAY BUFFER ADDRESS IN BC
            CALL    HL_2_DIS                            ;CALL HL TO DISPLAY CODE ROUTINE

;THIS SECTION CALCULATES THE ADDRESS OF THE REGISTER NAME FOR THE DATA DISPLAYS. THESE
;ARE STORED IN A TABLE. THE REQUIRED REGISTER NAME IS THEN TRANSFERRED TO THE DISPLAY
;BUFFER.

            LD      A, (STEP_CREG)                      ;GET REGISTER NUMBER
            PUSH    BC                                  ;PUT NEXT DISPLAY BUFFER
            POP     DE                                  ;LOCATION INTO DE(stination)
            LD      BC, 0x0002                          ;BC IS THE NUMBER OF DATA DISPLAYS
            LD      HL, REG_TBL                         ;HL=THE BASE OF THE NAME TABLE (MINUS 2)
L0373:      ADD     HL, BC                              ;ADD TO HL 2 FOR EACH
            DEC     A                                   ;REGISTER NUMBER TO ACCESS THE
            JR      NZ, L0373                           ;CURRENT REGISTER NAME
            LDIR                                        ;MOVE REGISTER NAME INTO RAM

;THE SCAN AND KEYBOARD ROUTINE ARE NOW CALLED (VIA THE RST 18). IF A VALID KEY IS PRESSED,
;THEN THE ZERO FLAG IS SET WHEN THE RST RETURNS.

STEP_DISP:  RST     18H                                 ;SCAN/KEY READ RST
            LD      HL, V_STEP_TMR                      ;(HL)=AUTO STEP CONTROL/TIMER BYTE
            JR      Z, STEP_KEY                         ;JUMP IF VALID KEY PRESSED

;NO KEY IS PRESSED SO THE ROUTINE CHECKS FOR THE AUTO REPEAT MODE ENABLED FLAG (BIT 7 AUTO
;STEP CONTROL/TIMER BYTE, ZERO IS AUTO STEP ENABLED) AND DECREMENTS THE COUNTER IF IT IS.
;IF THE COUNTER REACHES ZERO, THEN IT IS RELOADED AND THE ROUTINE JUMPS TO RECOVER THE
;REGISTERS AND STEP THE NEXT INSTRUCTION. IF NOT IN THE AUTO MODE OR THE COUNTER DOES NOT
;REACH ZERO, THEN THE ROUTINE LOOPS BACK TO SCAN THE DISPLAY AND WAIT FOR EITHER A KEY
;PRESS OR FOR THE COUNTER TO REACH ZERO.

            BIT     7, (HL)                             ;TEST FOR AUTO INCREMENT JUMP IF NOT
            JR      NZ, STEP_DISP                       ;ENABLED TO SCAN/KEY READ LOOP
            DEC     (HL)                                ;DECREMENT COUNTER: LOOP TO
            JR      NZ, STEP_DISP                       ;SCAN/KEY READ UNTIL COUNT=0

;AT THIS POINT THE AUTO-STEP DELAY HAS REACHED ZERO AND IS RELOADED WITH THE DELAY VALUE.
;A JUMP IS THEN DONE TO RECOVER THE REGISTERS AND STEP THE NEXT INSTRUCTION.
            LD      (HL), 0x30                          ;RESET AUTO STEP DELAY, JUMP TO RECOVER
            JR      STEP_DO_GO                          ;REGISTERS AND STEP NEXT INSTRUCTION

;KEY PROCESSING STARTS HERE
;THE AUTO-STEP IS DISABLED AND THEN THE KEY IS IDENTIFIED AND HANDLED.
;THE AUTO-STEP WILL BE RE-ENABLED IF THE KEY PRESSED IS A DATA KEY.

STEP_KEY:   LD      B, A                                ;SAVE KEY
            LD      (HL), 0xFF                          ;SET AUTO STEP CONTROL/TIMER BIT 7
            LD      HL, STEP_CREG                       ;THUS DISABLING THE AUTO REPEAT MODE
            LD      A, B                                ;POINT HI, TO CURRENT REG No. BUFFER
STEP_PLUS:  CP      K_PLUS                              ;PUT INPUT IN A,TEST IT FOR "+"
            JR      NZ, STEP_MINUS                      ;JUMP IF NOT TO TEST FOR "-"

;"+" KEY HANDLER
;THE CURRENT REGISTER NUMBER IS INCREMENTED AND THEN CHECK TO SEE THAT IT HAS NOT EXCEEDED
;THE HIGHEST REGISTER NUMBER (OC). IF IT HAS, THE ROUTINE JUMPS TO RESET THE CURRENT
;REGISTER NUMBER WITH 1, OTHERWISE IT JUMPS TO THE DISPLAY LOOP.

            INC     (HL)                                ;INCREMENT REGISTER NUMBER
            LD      A, (HL)                             ;AND CHECK TO SEE IF IT LARGER
            CP      0x0D                                ;THAN HIGHEST REG No. (0C): IF LOWER
            JR      C, L0351                            ;THAN OD JUMP TO DISPLAY LOOP ELSE
            JR      L034C                               ;JUMP TO SET REGISTER NUMBER TO 1

STEP_MINUS: CP      K_MINUS                             ;TEST FOR "-"
            JR      NZ, STEP_GO                         ;JUMP IF NOT

;"-" HANDLER
;ONE IS TAKEN FROM THE CURRENT REGISTER NUMBER AND THEN IT IS CHECKED FOR ZERO. IF IT
;BECOMES ZERO, THEN THE CURRENT REGISTER NUMBER IS SET TO THE HIGHEST REGISTER NUMBER (OC)
;TO WRAP-AROUND TO DISPLAY THE LAST REGISTER.
            DEC     (HL)                                ;SUBTRACT 1 FROM REGISTER NUMBER
            JR      NZ, L0351                           ;JUMP IF NOT 0 TO UP-DATE DISPLAY
            LD      (HL), 0x0C                          ;ELSE SET TO LAST REGISTER
            JR      L0351                               ;AND UP-DATE

;TEST FOR "GO"
STEP_GO:    CP      K_GO                                ;TEST FOR "GO" AND JUMP IF NOT
            JR      NZ, STEP_AD                         ;TO TEST FOR "AD" OR DATA KEY

;"GO" KEY
;THE GO KEY CAUSES STEPPING EXECUTION TO CONTINUE.
;BEFORE STEPPING IS CONTINUED THOUGH, THE KEYBOARD IS READ AND THE PROGRAM LOOPS UNTIL
;ALL KEYS ARE RELEASED. THIS IS TO SEPARATE KEY PRESSES MEANT FOR THE STEPPER AND THOSE
;FOR THE ROUTINE BEING STEPPED. ONCE ALL KEYS ARE RELEASED, ALL THE REGISTERS ARE POPPED
;OF THE REGISTER DISPLAY STACK, THE STACK IS RESTORED TO ITS "REAL" POSITION AND THE
;INTERRUPTS RE-ENABLED. THE RETURN ADDRESS FOR THE ROUTINE BEING STEPPED, STILL THERE ON
;THE TOP OF THE REAL STACK, IS USED AS THE RETURN ADDRESS.

STEP_DO_GO: RST     20H                                 ;WAIT UNTIL ALL KEYS ARE RELEASED
            JR      Z, STEP_DO_GO                       ;BEFORE RESTARTING
            POP     HL                                  ;RECOVER ALL
            POP     AF                                  ;REGISTERS
            POP     BC                                  ;IN
            POP     DE                                  ;THE
            POP     HL                                  ;REVERSE
            POP     IX                                  ;ORDER
            POP     IY                                  ;TO
            EX      AF, AF'                             ;HOW
            EXX                                         ;THEY
            POP     AF                                  ;STORED
            POP     BC
            POP     DE
            POP     HL
            EX      AF, AF'
            EXX
            LD      SP, (STEP_SP)                       ;AND STACK POINTER
            EI                                          ;RE-ENABLE THE INTERRUPTS
            RET                                         ;RET TO STEP NEXT INSTRUCTION

;TEST FOR "AD" KEY (RETURN TO JMON)
STEP_AD:    CP      K_ADDR                              ;TEST FOR "ADDR" KEY
            JR      NZ, STEP_DATA                       ;JUMP IF NOT TO ASSUME DATA KEY
            RST     00H                                 ;RETURN TO MONITOR

;DATA KEY HANDLER (ENABLE AUTO STEP)
STEP_DATA:  LD      A, 0x20                             ;SET AND ENABLE AUTO STEP IN THE
            LD      (V_STEP_TMR), A                     ;CONTROL/TIMER BYTE (BIT 7 LOW, 20
            JR      STEP_DISP                           ;CYCLES): JUMP TO DISPLAY LOOP
;-END OF STEPPER-

;START OF MENU
;MENU IS SET-UP FOR TAPE ROUTINE HERE
;THE VARIABLES ARE MOVED FROM ROM TO RAM AND THE DISPLAY BUFFER IS SET TO 0800.

;AS THE MENU IS PRIMARILY USED FOR THE TAPE COMPONENT IT ENTRY IS PLACED PRIOR TO THE MENU
;DRIVER.  BUT THE MENU CAN BE USED ANYWHERE PROVIDED THAT MENU VARIABLES ARE SET UP AT 0x880
FN_TAPE:
            LD      HL, TAPE_P_DRIVER                   ;LOAD HL WITH START OF TAPE
            LD      DE, PERI_MENU                       ;VARIABLES: DE IS RAM DE(stination)
            LD      BC, 0018H                           ;BC IS THE COUNT
            LDIR                                        ;SHIFT VARIABLES
MENU_RTN:   LD      HL, DISP_BUFF                       ;PUT DISPLAY BUFFER AT 0800
            LD      (V_DISPLAY), HL

;MENU DISPLAY LOOP STARTS HERE
;THE MENU ENTRY NUMBER (MEN), HOLDS THE NUMBER OF THE CURRENT MENU ENTRY ON THE DISPLAY.
;ALL ACTIONS OF THE MENU DRIVER CENTRE AROUND THIS BYTE.
;THE DISPLAY ON THE TEC LED DISPLAY IS GENERATED BY SHIFTING BOTH THE DATA AND ADDRESS
;DISPLAY CODES INTO THE RAM DISPLAY BUFFER.
;ALL THE POSSIBLE DATA AND ADDRESS DISPLAY CODES ARE STORED IN SEPARATE TABLES IN ROM,
;THE BASE OF EACH IS ADDRESSED BY THE CONTENTS OF MEMORY LOCATIONS 0895 (DATA TABLE), AND
;0893 (ADDRESS TABLE).
;THE FIRST MENU ENTRY IS DENOTED BY A ZERO VALUE IN THE MENU ENTRY NUMBER (MEN). THIS
;MEANS THAT THE POSSIBLE ZERO CONDITION MUST BY DETECTED AND THE TABLE ENTRY CALCULATOR
;SECTION SKIPPED OVER. WHEN ACCESSING THE DISPLAY TABLES, THE MENU ENTRY NUMBER IS
;DECREMENTED UNTIL ZERO AND EACH TIME AN OFFSET EQUAL TO THE LENGTH OF EACH TABLE ENTRY
;(4 FOR ADDR AND 2 FOR DATA TABLES) IS ADDED TO THE POINTERS.
;AFTER THE REQUIRED ENTRIES ARE FOUND, THEY ARE MOVED INTO THE RAM DISPLAY BUFFER.

MENU_DISP:  LD      A, (MENU_NO)                        ;GET MENU ENTRY NUMBER (MEN)
MENU_RTNT:  LD      DE, (MENU_D_TBL)                    ;DE POINTS TO DATA DISPLAY TABLE
            LD      HL, (MENU_A_TBL)                    ;HL POINTS TO ADDR DISPLAY TABLE
MENU_SFT:   LD      BC, 0004H                           ;BC IS BOTH AN INDEX OFFSET AND
            OR      A                                   ;BYTE COUNTER (USED BELOW): TEST
            JR      Z, L03F9                            ;A AND SKIP CALCULATOR IF ZERO
L03F3:      ADD     HL, BC                              ;ADD 4 TO HL TO POINT TO NEXT ADDR
            INC     DE                                  ;DISPLAY AND 2 TO DE FOR NEXT DATA
            INC     DE                                  ;DISPLAY
            DEC     A                                   ;DO UNTIL A=0
            JR      NZ, L03F3
L03F9:      PUSH    HL                                  ;SAVE ADDR POINTER (not required)
            PUSH    DE                                  ;AND DATA POINTER
            LD      DE, DISP_BUFF                       ;SHIFT ACROSS ADDR DISPLAY
            LDIR                                        ;TO 0800 (BC-0004 FROM ABOVE)
            POP     HL                                  ;POP (DE) DATA DISPLAY ADDR INTO HL
            LD      C, 0x02                             ;SET PC TO SHIFT DATA DISPLAY BYTES
            LDIR                                        ;SHIFT THE BYTES TO DISPLAY RAM
            POP     HL                                  ;CLEAN UP STACK

;THIS SECTION CALLS THE SCAN/KEY/LCD/PATCH ROUTINE.
;WHEN A KEY IS DETECTED A KEY HANDLER ROUTINE IS CALLED. THIS KEY HANDLER IS COMMON TO
;BOTH THE MENU DRIVER AND THE PERIMETER HANDLER AND IS DOCUMENTED ON FURTHER.
;IF THE "GO" KEY WAS PRESSED, THE ZERO FLAG WILL BE SET WHEN THE COMMON KEY HANDLER RETURNS
;AND THE ROUTINE JUMPS TO THE GO HANDLER. IF NOT, THEN A (UNUSED BY JMON) ROUTINE (AT
;0897) IS CALLED AND FINDS AN IMMEDIATE RETURN.
;THE RETURN INSTRUCTION WAS PLACED AT 0897 WHEN THE TAPE'S MENU VARIABLES WERE SHIFTED
;FROM ROM TO RAM (SEE 0793).
;A JUMP THEN LOOPS BACK TO THE MAIN DISPLAY LOOP TO UP-DATE THE DISPLAYS IN CASE OF A NEW
;MENU ENTRY NUMBER (MEN) BEING PROVIDED BY THE KEY HANDLER.
;THE GO HANDLER IS A SIMPLE TABLE ENTRY CALCULATOR THAT USES THE MENU ENTRY NUMBER TO
;INDEX THROUGH A TABLE OF THREE BYTE JUMPS. LIKE THE DISPLAY CALCULATOR, THE ZERO POSSIBILITY
;IS TESTED FOR AND THE CALCULATOR SECTION IS SKIPPED OVER IF ZERO. WHEN THE REQUIRED TABLE
;ENTRY IS POINTED TO BY HL, IT IS THEN JUMPED TO VIA JP (HL), AND THE TABLE ENTRY,,,ITSELF
;BEING A 3 BYTE JUMP THEN JUMPS TO THE SELECTED MENU ENTRY'S ROUTINE.

            CALL    SCAN_IO                             ;CALL SCAN/KEY/LCD/PATCH ROUTINE
            LD      HL, MENU_NO                         ;POINT HL TO MENU ENTRY NUMBER
            CALL    MENU_KEY                            ;CALL COMMON KEY HANDLER
            JR      Z, MENU_GO                          ;JUMP IF KEY WAS "GO" ELSE CALL TO
            CALL    MENU_KEYRN                          ;RETURN INSTRUCTION (UNUSED BY JMON)
            JR      MENU_DISP                           ;LOOP TO MAIN DISPLAY LOOP

;MENU "GO" KEYHANDLER
MENU_GO:    LD      HL, (MENU_J_TBL)                    ;POINT HL TO BASE OF JUMP TABLE
            LD      A, (MENU_NO)                        ;GET MENU ENTRY NUMBER
            OR      A                                   ;TEST FOR ZERO
            JR      Z, L0425                            ;SKIP CALCULATOR IF ZERO
L041F:      INC     HL                                  ;FIND JUMP VECTOR FOR THE CURRENT
            INC     HL                                  ;MENU HEADING
            INC     HL
            DEC     A
            JR      NZ, L041F
L0425:      JP      (HL)                                ;AND JUMP TO THE REQUIRED ROUTINE

;PERIMETER HANDLER SET-UP ROUTINES FOR THE TAPE SOFTWARE
;WHEN GO IS PRESSED IN THE MENU HANDLER, ONE OF THE IMMEDIATE FOLLOWING ROUTINES IS EXECUTED
;(WHEN THE MENU IS WORKING WITH THE TAPE SOFTWARE). THESE ROUTINES SET-UP THE VARIABLES
;FOR THE MAIN TAPE FUNCTIONS (SAVE, TEST CS, TEST BL AND LOAD). THE TWO TESTS AND THE LOAD
;ROUTINE IS BASICALLY THE ONE ROUTINE, EXCEPT THAT EACH HAS ITS OWN PRIVATE SIGN-ON BYTE.
;LATER YOU WILL SEE THE THE ROUTINE TO LOAD OR TEST IS BASICALLY THE SAME AND THIS "SIGN-ON
;BYTE" SEPARATES THE DIFFERENT FUNCTIONS AT THE CRITICAL STAGE.
;THE COMMON SECTION FOR THE LOAD AND TESTS, SETS THE PERIMETER HANDLER TO HAVE TWO WINDOWS,
;ONE FOR THE FILE NUMBER AND ONE FOR THE OPTIONAL START ADDRESS. IT ALSO SETS THE OPTIONAL
;START WINDOW TO FFFF (NO OPTIONAL START ADDRESS BY DEFAULT) AND PUTS THE EXECUTING ADDRESS
;OP THE LOAD/TESTS ROUTINE IN THE PERIMETER "GO" JUMP ADDRESS BUFFER.
;THE SAVE SET-UP SETS THE NUMBER OF WINDOWS TO 4 AND STORES THE EXECUTING ADDRESS OF THE
;SAVE PREAMBLE ROUTINE IN THE PERIMETER "GO" JUMP ADDRESS BUFFER (0888).
;THE 4 TAPE SAVE WINDOWS ARE: THE FILE NUMBER, THE START, THE END AND THE OPTIONAL AUTO
;GO ADDRESS.
;ALL THE ABOVE ROUTINES HAVE A COMMON SET-UP AREA. THIS COMMON AREA STORES THE ROUTINE'S
;JUMP ADDRESS, IN HL, AND THE NUMBER OF WINDOWS, IN A, BOTH PROVIDED FROM THEIR OWN
;DEDICATED SECTION. THE COMMON AREA ALSO CLEARS THE "ACTIVE WINDOW NUMBER" TO ZERO SO THAT
;THE PERIMETER HANDLER WILL BE ENTERED WITH THE FIRST WINDOW (FILE NUMBER) SHOWING.

;"LOAD" SET-UP
J_TAPE_LOAD:
            XOR     A                                   ;CLEAR A FOR LOAD SIGN-ON BYTE

;COMMON AREA FOR LOAD AND TESTS
L0427:      LD      (TAPE_ACTN), A                      ;SAVE SIGN-ON BYTE IN BUFFER
            LD      A, 0x01                             ;LOAD A WITH NUMBER OF WANTED
            LD      HL, 0xFFFF                          ;WINDOWS -1 (2 WINDOWS): SET
            LD      (TAPE_START), HL                    ;OPTIONAL START WINDOW TO FFFF
            LD      HL, TAPE_INPUT                      ;LOAD HL WITH "GO" ADDR OF LOAD/TEST
            JR      L0444                               ;ROUTINE: JUMP TO STORE HL AND A

;"TEST BLOCK" SET-UP
J_TAPE_TEST:
            LD      A, 0x02                             ;2=TEST BLOCK SIGN-ON BYTE
L0439:      JR      L0427                               ;JUMP TO TEST/LOAD COMMON AREA

;"TEST CHECKSUM" SET-UP
J_TAPE_CHKS:
            LD      A, 0x03                             ;3=TEST CHECKSUM SIGN-ON BYTE
            JR      L0439                               ;JUMP TO TEST/LOAD COMMON AREA

;SAVE SET-UP
J_TAPE_SAVE:
            LD      HL, TAPE_SAVE_SETUP                 ;POINT HL TO START OF SAVE PRE-AMBLE
            LD      A, 0x03                             ;SET UP FOR 4 WINDOWS

;COMMON AREA FOR ALL SET-UPS
L0444:      LD      (PERI_J_ADR), HL                    ;STORE HL WITH GO CALL ROUTINE
            LD      (PERI_W_MAX), A                     ;STORE A WITH TOTAL PERIMITER WINDOWS
            XOR     A                                   ;SET MEN TO FIRST WINDOW (FILE NUMBER)
            LD      (PERI_W_CUR), A                     ;
            JR      L0473                               ;JUMP TO PERIMETER HANDLER

;SAVE ROUTINE PRE-AMBLE
;THE SAVE PREAMBLE FITS IN BETWEEN THE PERIMETER HANDLER AND THE ACTUAL SAVE ROUTINE. THE
;PURPOSE OF IT IS TO SHIFT ACROSS THE FILE NUMBER, THE START ADDRESS AND THE OPTIONAL GO
;ADDRESS. IT ALSO CALCULATES THE LENGTH OF THE BLOCK AND TRANSFERS IT ACROSS TO THE TAPE
;FILE INFORMATION BLOCK WHICH IS OUTPUTTED TO THE TAPE.
;IF THE END IS LOWER THAN THE START THE ROUTINE WILL JUMP TO DISPLAY "Err -In".
TAPE_SAVE_SETUP:
            LD      HL, (TAPE_AUTOG)                    ;SHIFT OPTIONAL GO TO OUTPUT BUFFER
            LD      (TAPE_O_GO), HL
            LD      HL, (TAPE_START)                    ;SHIFT START ADDRESS OF BLOCK
            LD      (TAPE_O_STA), HL                    ;TO TAPE FILE OUTPUT BUFFER
            EX      DE, HL                              ;PUT START OF BLOCK IN DE
            LD      HL, (TAPE_END)                      ;GET END OF BLOCK IN HL
            OR      A                                   ;CLEAR CARRY
            SBC     HL, DE                              ;CALCULATE NUMBER OF BYTES IN
            INC     HL                                  ;BLOCK (DIFFERENCE +1)
            JP      C, L004A                            ;JUMP IF CARRY TO "Err-In"
            LD      (TAPE_O_LEN), HL                    ;STORE COUNT IN FILE INFO OUTPUT
            LD      HL, (TAPE_FILE)                     ;SHIFT FILE NUMBER TO
            LD      (TAPE_O_FIL), HL                    ;TAPE FILE INFO OUTPUT BUFFER
            JP      TAPE_SAVE                           ;JUMP TO SAVE OUTPUT ROUTINE

;FINAL TAPE SET-UP BEFORE THE PERIMETER HANDLER. THIS PLACES FFFF IN THE OPTIONAL GO WINDOW
;BEFORE ENTERING THE PERIMETER HANDLER.

L0473:      LD      HL, 0xFFFF                          ;PUT FFFF IN OPTIONAL GO WINDOW
            LD      (TAPE_AUTOG), HL                    ;

;PERIMETER HANDLER
;THE PERIMETER HANDLER ROUTINE IS SIMILAR TO THE MENU DRIVER. THE MAJOR DIFFERENCES ARELISTED BELOW:
;THE PERIMETER HANDLER CREATES ITS OWN ADDRESS DISPLAY CODES BY CONVERTING THE CONTENTS
;OF THE ACTIVE WINDOW TO DISPLAY CODE AND THEREFORE DOES NOT REQUIRE A TABLE OF ADDRESS DISPLAY CODES.
;ANOTHER DIFFERENCE IS THE ADDRESS OF THE ROUTINE TO BE EXECUTED ON A "GO" PRESS IS SUPPLIED
;BY THE CALLING ROUTINE. THEREFORE THE PERIMETER HANDLER DOESN'T REQUIRE A JUMP TABLE AND
;ASSOCIATED CALCULATER.
;THE ONLY OTHER MAJOR DIFFERENCE IS THAT THE PERIMETER HANDLER HAS ITS OWN BUILT IN DATA
;KEY HANDLER WHILE THE MENU DOES NOT.
;THE FRONT SECTION BELOW CALCULATES THE ADDRESS OF THE ACTIVE WINDOW AND THE ADDRESS OF
;THE DATA DISPLAY FROM THE DISPLAY TABLE.
;THE MENU ENTRY NUMBER FROM THE MENU DRIVER HAS AN EQUIVALENT HERE. IT IS THE ACTIVE WINDOW
;NUMBER AND IS USEDIN IDENTICAL FASHION.

ORG     $0479
PERI_RTN:   LD      A, (PERI_W_CUR)                     ;GET NUMBER OF ACTIVE WINDOW
            LD      HL, (PERI_W_ADD)                    ;GET ADDRESS OF FIRST (FILE) WINDOW+1
            LD      DE, (PERI_D_TBL)                    ;GET BASE OF DATA DISPLAY TABLE
            OR      A                                   ;TEST ACTIVE WINDOW NUMBER FOR ZERO
            JR      Z, L048D                            ;SKIP CALCULATOR IF ZERO
L0486:      INC     DE                                  ;FINE CURRENT DATA DISPLAY
            INC     DE                                  ;AND WINDOW
            INC     HL
            INC     HL
            DEC     A
            JR      NZ, L0486

;AFTER THE ADDRESS+1 OF THE ACTIVE WINDOW IS CALCULATED, IT IS STORED IN A BUFFER (AT
;088C). EACH TIME A DATA KEY 1S PRESSED, HL IS LOADED FROM THIS BUFFER AND THEREFORE POINTS
;TO THE ACTIVE WINDOW. THE DATA CAN THEN BE SHIFTED INTO THE ACTIVE WINDOW IMMEDIATELY.

L048D:      LD      (PERI_W_AC1), HL                    ;STORE ACTIVE WINDOW ADDRESS+l

;BELOW THE DATA DISPLAY BYTES ARE PUT INTO THE DATA SECTION OF THE DISPLAY BUFFER VIA HL.
            EX      DE, HL                              ;PUT DATA DISPLAY ADDRESS IN HL
            LD      A, (HL)                             ;GET RIGHT-HAND DISPLAY BYTE IN A
            INC     HL                                  ;AND LEFT-HAND IN H
            LD      H, (HL)                             ;PUT RIGHT-HAND BYTE IN L
            LD      L, A                                ;HL HOLDS THE DATA DISPLAY BYTES
            LD      (DISP_DBUFF), HL                    ;STORE DATA DISPLAY IN BUFFER

;BELOW THE 16 BIT CONTENTS OF THE ACTIVE WINDOW ARE CONVERTED TO DISPLAY CODE ARE PLACED
;IN THE ADDRESS SECTION OF THE DISPLAY BUFFER.

            EX      DE, HL                              ;GET ACTIVE WINDOW ADDRESS FROM DE
            LD      A, (HL)                             ;AND TRANSFER
            DEC     HL                                  ;THE 16 BIT CONTENTS OF THE ACTIVE
            LD      L, (HL)                             ;WINDOW INTO HL
            LD      H, A                                ;READY TO COVERT TO DISPLAY CODE
            LD      BC, DISP_BUFF                       ;BC=DISPLAY BUFFER START
            CALL    HL_2_DIS                            ;CALL CONVERSION HL TO DISPLAY CODE

;THE DISPLAY BUFFER IS NOW SET-UP AND THE SCAN/KEY LOOP IS CALLED. WHEN A KEY IS PRESSED,
;A COMMON KEY HANDLER IS CALLED.
;THE COMMON KEY HANDLER DOES ALL THE REQUIRED PROCESSING FOR THE "+", "- " AND "AD" KEYS.
;IF EITHER THE "GO" OR A DATA KEY IS PRESSED, THEN THE HANDLER RETURNS WITH THE FLAGS SET
;TO SIGNIFY THESE KEYS.
;IF "GO" IS PRESSED THEN THE ZERO FLAG IS SET AND THE "GO" HANDLER BELOW IS EXECUTED. IF
;A DATA KEY IS PRESSED THEN THE ZERO FLAG IS CLEAR (NOT ZERO) AND CARRY FLAG IS CLEAR THE
;DATA KEY HANDLER IS EXECUTED IF THESE CONDITIONS ARE MET.

PERI_SFT:   CALL    SCAN_IO                             ;CALL SCAN/KEY/LCD/PATCH ROUTINE
            LD      HL, PERI_W_CUR                      ;POINT HL TO ACTIVE WINDOW NUMBER
            CALL    MENU_KEY                            ;CALL COMMON KEY HANDLER
            JR      NZ, PERI_D_KEY                      ;JUMP IF NOT GO KEY TO TEST FOR DATA
            LD      HL, (PERI_J_ADR)                    ;OR CONTROL KEY: ELSE GET JUMP ADDRESS
            JP      (HL)                                ;STORED BY SET-UP AND GO

;COMMON KEY HANDLER
;BECAUSE THE PERIMETER HANDLER AND THE MENU DRIVER ARE VERY SIMILAR, THEY ARE ABLE TO
;SHARE A COMMON KEY HANDLER.
;THE ACTION OF THE KEY HANDLER IS AS FOLLOWS:
;IF THE "AD" KEY IS PRESSED, THEN THE RETURN ADDRESS IS POPPED OFF THE STACK AND A RETURN
;IS DONE TO THE CALLING ROUTINE (USUALLY JMON). IF THE "GO" KEY IS PRESSED, THEN THE ZERO
;FLAG WILL BE SET AND A RETURN DONE. IT IS THEN UP TO THE CALLING ROUTINE TO SERVICE THE
;"GO" KEY.
;A DATA KEY WILL BE FLAGGED BY SETTING THE CARRY FLAG AND CLEARING THE ZERO FLAG. LIKE
;THE "GO" KEY, THE CALLING ROUTINE MUST DECIDE WHAT IT IS TO DO WITH THE DATA KEY (THERE
;IS A BUILT IN DATA KEY HANDLER FOR THE PERIMETER HANDLER).
;IF EITHER THE "+" OR "-" KEYS ARE PRESSED THEN A SPECIAL ROUTINE IS CALLED. THIS ROUTINE
;WILL ALTER THE CURRENT NUMBER OF THE ACTIVE WINDOW OR MENU ENTRY. THE RESULT IS THAT WHEN
;THE DISPLAY IS UP-DATED, THE DISPLAYS WILL BE SHIFTED TO EITHER THE NEXT DISPLAY FOR "+"
;OR TO THE PREVIOUS ONE FOR "- " AND WRAP-AROUND IF REQUIRED.

MENU_KEY:   CP      K_PLUS                              ;IS THE KEY
            JR      Z, MENU_K_HDL                       ;JUMP IF SO TO "+" HANDLER
            CP      K_MINUS                             ;IS IT "-"
            JR      Z, MENU_K_HDL                       ;JUMP IF SO TO "-" HANDLER
            CP      K_ADDR                              ;IS IT "AD"
            JR      NZ, L04C0                           ;JUMP IF NOT TO TEST FOR "GO"
            POP     HL                                  ;CLEAN UP STACK
            RET                                         ;RETURN TO JMON (OR CALLING ROUTINE)
L04C0:      CP      K_GO                                ;IS IT "GO"
            CCF                                         ;CLEAR CARRY IF NOT IF GO C=1 Z=1
            RET                                         ;IF DATA SET Z=0 C=0: RETURN

;BELOW IS THE PERIMETER HANDLER DATA KEY HANDLER/DISCRIMINATOR
;IF THE KEY WAS "+" OR "-" THEN IT HAS ALREADY BEEN HANDLED AND THIS CONDITION IS FLAGGED
;BY THE CARRY BEING SET. IN THIS CASE, A JUMP IS DONE BACK TO THE MAIN BODY TO UP-DATE
;THE DISPLAY OTHERWISE THE DATA KEY VALUE IS SHIFTED INTO THE ACTIVE WINDOW.

PERI_D_KEY: JR      C, PERI_RTN                         ;JUMP IF KEY WAS "+" OR "-”
            LD      HL, (PERI_W_AC1)                    ;POINT HL TO ACTIVE WINDOW+1
            DEC     HL                                  ;POINT TO LOW ORDER BYTE
            RLD                                         ;SHIFT IN DATA KEY VALUE
            INC     HL                                  ;AND SHIFT OTHER NIBBLES
            RLD                                         ;ACROSS
            JR      PERI_RTN                            ;JUMP BACK TO UP-DATE DISPLAY

;THIS ROUTINE IS CALLED FROM THE COMMON KEY HANDLER IF EITHER "+" OR "-" HAVE BEEN PUSHED.
;THIS ROUTINE WILL EITHER INCREMENT OR DECREMENT THE MEMORY LOCATION ADDRESSED BY HL FOR
;THE "+" AND "-" KEY RESPECTIVELY. HL WAS LOADED BY THE CALLING ROUTINE TO POINT TO ITS
;MAIN CONTROLLING BYTE. THIS IS EITHER THE CURRENT MENU ENTRY NUMBER (MENU DRIVER), OR
;THE ACTIVE WINDOW NUMBER (PERIMETER HANDLER) , BOTH OF WHICH HAVE BEEN DESCRIBED PREVIOUSLY.
;AFTER INCREMENTING OR DECREMENTING (HL), THIS ROUTINE THEN CHECKS THAT THE VALUE IN (HL)
;IS NOT GREATER THAT THE BYTE AT HL+1 (WHICH IS THE MAXIMUM NUMBER OF DISPLAYS LESS 1).
;KEEP IN MIND, IF IT UNDERFLOWED FROM ZERO IT WILL BECOME FF AND BE HIGHER THAN (HL). THIS
;SECOND BYTE (AT HL+1) IS THE NUMBER OF ALLOWABLE DISPLAYS-1 AND WAS PROVIDED BY THE ROM
;TABLE FOR THE (TAPE) MENU DRIVER, AND PROVIDED BY THE PERIMETER HANDLER SET-UP ROUTINES
;(REFER TO 042A AND 0442).
;IF THE FIRST BYTE BECOMES HIGHER THAN THE SECOND., THEN THE ROUTINE CHECKS TO SEE WHICH
;KEY WAS PRESSED. IF THE "+" KEY WAS, THEN (HL) IS CLEARED. THIS WILL CAUSE MENU OR
;PERIMETER HANDLER TO SHOW ITS FIRST DISPLAY WHEN RE-ENTERED.
;IF THE KEY WAS "-", THEN THE MAXIMUM NUMBER OF DISPLAYS-1 (WHICH IS THE SAME AS THE NUMBER
;OF THE FINAL DISPLAY) IS TRANSFERRED INTO (HL) (THE NUMBER OF THE CURRENT DISPLAY). THIS
;WILL CAUSE THE LAST DISPLAY TO BE SHOWN WHEN THE MENU DRIVER OR PERIMETER HANDLER IS
;RE-ENTERED.
;IF THERE IS NO UNDERFLOW OR OVERFLOW THEN THE ROUTINE RETURNS JUST AFTER IT HAS EITHER
;INCREMENTED OR DECREMENTED THE CURRENT NUMBER OF THE MENU ENTRY NUMBER OR ACTIVE WINDOW
;NUMBER.
;WHEN THE MENU DRIVER OR PERIMETER HANDLER ARE RE-ENTERED, THEY WILL SHOW THE NEXT DISPLAY
;FOR "+" OR THE PREVIOUS FOR "-" AND WRAP-AROUND AUTOMATICALLY IF REQUIRED.

ORG     $04D1
MENU_K_HDL: LD      C, A                                ;SAVE INPUT KEY VALUE IN C
            INC     HL                                  ;PUT MAX NUMBER OF DISPLAYS-1
            LD      B, (HL)                             ;IN B
            DEC     HL                                  ;RESET HL TO POINT TO CURRENT NUMBER
            RRCA                                        ;WAS KEY "+" OR "-"? BIT 0 WILL TELL
            LD      A, (HL)                             ;PUT CURRENT NUMBER IN A
            JR      C, L04DB                            ;JUMP IF KEY WAS "-"
            INC     A                                   ;INCREASE A BY 2
            INC     A                                   ;
L04DB:      DEC     A                                   ;DECREASE A BY ONE
            INC     B                                   ;ADD 1 TO MAX NUMBER-1: IS CURRENT
            CP      B                                   ;NUMBER EQUAL OR GREATER THAN MAX?
            JR      NC, L04E5                           ;JUMP IF SO TO UNDER/OVERFLOW HANDLER
L04E0:      LD      (HL), A                             ;ELSE STORE UPDATED CURRENT NUMBER
            XOR     A                                   ;SET ZERO FLAG
            DEC     A                                   ;CHANGE ZERO FLAG TO 0
            SCF                                         ;AND SET CARRY
            RET                                         ;DONE
L04E5:      BIT     0, C                                ;TEST FOR "+" OR "-"
            JR      NZ, L04EC                           ;JUMP IF "-" TO SET CURRENT NUMBER
            XOR     A                                   ;TO LAST DISPLAY: ELSE SET FIRST
            JR      L04E0                               ;DISPLAY: JUMP TO STORE NEW NUMBER
L04EC:      DEC     B                                   ;CORRECT MAX NUMBER-1
            LD      A, B                                ;SET A TO LAST DISPLAY NUMBER
            JR      L04E0                               ;JUMP TO STORE LAST DISPLAY NUMBER

;THIS IS THE TAPE OUTPUT ROUTINE
;THE ACTION IS AS FOLLOWS:
;A LEADER OF LOW FREQUENCY TONE IS OUTPUTTED FOLLOWED BY THE FILE INFORMATION BLOCK.
;AFTER THE FILE INFORMATION BLOCK IS OUTPUTTED, SEVERAL SECONDS OF HIGH FREQUENCY MIDDLE
;SYNC IS OUTPUTTED, THE TIME IT TAKES TO OUTPUT THE MIDDLE SYNC IS USED BY THE TAPE INPUT
;ROUTINE TO DISPLAY THE FILE NUMBER.
;THE DATA TO BE SAVED ON TAPE IS BROKEN UP INTO BLOCKS OF 256 BYTES AND OUTPUTTED WITH A
;CHECKSUM AT THE END OF EACH BLOCK. A COUNTER IS SHOWN ON THE TEC LED DISPLAY THAT SHOWS
;HOW MANY COMPLETE BLOCKS LEFT (UP TO 16 BLOCKS).
;IF THERE IS AN ODD SIZE BLOCK, IT IS OUTPUTTED AS THE LAST BLOCK.
;AFTER ALL THE BLOCKS HAVE BEEN OUTPUTTED, AN END OF FILE HIGH FREQUENCY TONE IS OUTPUTTED.

TAPE_SAVE:  LD      HL, 0x3000                          ;HL HAS NUMBER OF LEADER CYCLES
            CALL    LOW_TONE                            ;CALL LOW TONE
            LD      HL, TAPE_O_FIL                      ;HL IS START OF FILE INFORMATION BLOCK
            LD      B, 0x0C                             ;LOAD B WITH NUMBER OF BYTES TO BE
            XOR     A                                   ;OUTPUTTED: ZERO A FOR CHECKSUM
            CALL    TAPE_OUT                            ;CALL OUT BLOCK
            LD      HL, 0x5000                          ;LD HL WITH MID SYNC CYCLE COUNT
            CALL    HIGH_TONE                           ;CALL HIGH TONE
            LD      HL, (TAPE_O_STA)                    ;LOAD HL, WITH START OF OUTPUT BLOCK

;OUTPUT LOOP STARTS HERE
;THE DISCUSSION BELOW ON THE BYTE COUNTER AND BLOCK FORMATION APPLIES TO THE TAPE INPUT
;LOOP ALSO. THE TAPE INPUT LOOP DESCRIPTION WILL REFER YOU BACK TO THESE NOTES.
;THE BYTE COUNT IS PUT INTO BC AND THEN A ROUTINE TO CONVERT B (THE TOTAL NUMBER OF FULL
;BLOCKS TO BE OUTPUTTED) TO DISPLAY FORMAT AND OUTPUT IT IS CALLED.
;THE CONVERSION ROUTINE ALSO TESTS B FOR ZERO. IF B IS NOT ZERO, THE ROUTINE RETURNS WITH
;THE ZERO FLAG CLEAR (NOT ZERO) AND THE HIGH ORDER BYTE OF THE BYTE COUNT IN B IS DECREMENTED
;BY ONE AND STORED IN ITS BUFFER. THIS COUNTS DOWN THE BLOCKS. B IS THEN ZEROED SO THAT
;A FULL BLOCK (256 BYTES) WILL BE OUTPUTTED ON RETURNING.
;IF THE HIGH ORDER BYTE OF THE BYTE COUNT (IN B) IS ZERO (NO FULL BLOCK OF 256 BYTES) THEN
;C (THE LOW ORDER BYTE OF THE COUNT) IS TRANSFERRED INTO B AND THE ZERO FLAG IS SET.
;THE CONVERSION THEN RETURNS WITH THE NUMBER (IF ANY) OF REMAINING BYTES IN B.
;AFTER THE CONVERSION ROUTINE HAS RETURNED, A JUMP IS DONE IF THE ZERO FLAG IS CLEAR
;(DENOTING A NOT ZERO STATE). THIS JUMP SKIPS AHEAD TO SAVE THE FLAGS AND OUTPUT ONE FULL
;BLOCK
;IF THE ZERO FLAG IS SET, THEN THE ROUTINE BELOW CHECKS TO SEE IF THE LOW ORDER BYTE (FROM
;C) THAT HAS BEEN PLACED IN B, IS ZERO. IF THE LOW ORDER BYTE IS ZERO, THEN ALL THE BYTES
;HAVE BEEN OUTPUTTED. THE ROUTINE THEN JUMPS TO DISPLAY " -END -S".
;IF THE LOW ORDER BYTE OF THE COUNT IS NOT ZERO THEN THE ZERO FLAG IS SET AND SAVED ON
;THE STACK BEFORE WHAT ARE NOW KNOWN TO BE THE LAST IS OUTPUTTED.
;BEFORE THE DATA IS SENT TO THE TAPE, A SHORT HIGH TONE SYNC IS OUTPUTTED TO COVER THE
;SOFTWARE OVERHEAD OF THE TAPE INPUT ROUTINE, AND A IS ZEROED TO BE USED AS THE CHECK-SUM.

START_BLK:  LD      BC, (TAPE_O_LEN)                    ;LOAD BC WITH NUMBER OF BYTES
            CALL    TAPE_DISP                           ;CALL ROUTINE TO DISPLAY BLOCK COUNT
            JR      NZ, L0516                           ;AND TEST LENGTH: JUMP IF FULL BLOCK
            LD      A, B                                ;TO OUTPUT: TEST LOW BYTE OF COUNT
            OR      A                                   ;IN B IS ZERO AND JUMP TO DISPLAY
            JR      Z, END_BLOCK                        ;"-END-S" IF SO

;THE XOR A INSTRUCTION BELOW SETS THE ZERO FLAG TO SIGNIFY THAT THE BLOCK ABOUT TO BE
;OUTPUTTED IS THE FINAL BLOCK. THE ROUTINE WILL THEN DISPLAY "-END-S" (AFTER A SHORT END
;SYNC TONE).

            XOR     A                                   ;SET ZERO FLAG
L0516:      PUSH    AF                                  ;AND SAVE ON STACK

;AT THIS POINT IF THE ZERO FLAG ON THE STACK IS CLEAR (NOT ZERO STATE), THEN AFTER THE
;CURRENT BLOCK IS OUTPUTTED, THE ROUTINE WILL LOOP BACK TO START OF THE OUTPUT LOOP TO
;SEE IF THERE IS ANY MORE BYTES TO BE OUTPUTTED.
            EXX                                         ;SWAP REGISTERS
            LD      HL, 0x0214                          ;LOAD HL FOR SHORT BURST OF
            CALL    HIGH_TONE                           ;HIGH TONE
            EXX                                         ;SWAP BACK REGISTERS
            XOR     A                                   ;ZERO A FOR CHECKSUM
            CALL    TAPE_OUT                            ;CALL OUTBLOCK
            POP     AF                                  ;RECOVER FLAGS AND JUMP IF
            JR      NZ, START_BLK                       ;THERE MIGHT BE MORE TO OUTPUT

;ALL BLOCKS HAVE BEEN OUTPUTTED SO FINISH WITH A SHORT END TONE AND SET-UP END DISPLAY "-END-S".
END_BLOCK:  LD      HL, 0x1000                          ;LOAD HL WITH SHORT END TONE
            CALL    HIGH_TONE                           ;CALL HIGH TONE
            LD      A, 0x05                             ;LD A TO INDEX "END-S DISPLAY
            JP      MENU_RTNT                           ;JUMP BACK TO MENU

;THIS IS THE START OF THE TAPE INPUT SECTION.
;THE ACTION HERE IS TO DETECT A VALID LEADER BY COUNTING 1000H CYCLES OF LOW FREQUENCY
;TONE. AFTER THIS HAS BEEN DETECTED, THE ROUTINE WAITS UNTIL IT DETECTS THE START BIT OF
;THE FILE INFORMATION BLOCK. THE BLOCK IS THEN LOADED IN AND A CHECK-SUM COMPARE IS DONE.
;IF AN ERROR IS DETECTED, THE ROUTINE JUMPS TO DISPLAY "FAIL -XX", OTHERWISE THE FILE
;NUMBER IS CONVERTED TO DISPLAY FORMAT AND DISPLAYED FOR A FEW SECONDS.

TAPE_INPUT: LD      BC, 0x1000                          ;LOAD BC TO COUNT 0x1000 CYCLES
L0534:      CALL    READ_TAPE                           ;CALL PERIOD
            JR      C, TAPE_INPUT                       ;LOOP UNTIL LOW TONE IS DETECTED
            DEC     BC                                  ;COUNT LONG
            LD      A, B                                ;PERIODS
            OR      C                                   ;IF BC REACHES ZERO THEN IT IS
            JR      NZ, L0534                           ;ACCEPTED THAT A VALID FILE FOLLOWS
            LD      B, 0x0C                             ;LOAD B TO INPUT 12 BYTES AND
            LD      HL, TAPE_O_FIL                      ;POINT HL TO FILE INFO BLOCK INPUT
L0543:      CALL    READ_TAPE                           ;BUFFER: CALL PERIOD
            JR      NC, L0543                           ;AND WAIT FOR LOW TONE TO END
            CALL    LOAD_BLK2                           ;CALL INBLOCK TO GET FILE INFO BLOCK
            JR      NZ, TAPEFAIL                        ;JUMP NOT ZERO TO FAIL LOAD ROUTINE
            LD      BC, DISP_BUFF                       ;LOAD BC TO POINT TO DISPLAY BUFFER
            LD      HL, (TAPE_O_FIL)                    ;PUT FILE NUMBER INTO EL
            CALL    HL_2_DIS                            ;CONVERT HL TO DISPLAY CODE
            LD      A, 0x47                             ;PUT "F" IN DISPLAY BUFFER
            LD      (DISP_D2BUF), A                     ;FOR "FILE"
            LD      BC, 0x01F2                          ;LD BC WITH THE DISPLAY ON TIME
L055E:      PUSH    BC                                  ;SAVE ON STACK
            CALL    LED_SCAN                            ;CALL SCAN
            POP     BC                                  ;RECOVER BC
            DEC     BC                                  ;DECREMENT
            LD      A, B                                ;AND LOOP UNTIL
            OR      C                                   ;BC IS ZERO
            JR      NZ, L055E

;AFTER A FILE INFORMATION BLOCK IS LOADED AND THE FILE NUMBER DISPLAYED, A TEST IS DONE
;ON THE REQUIRED FILE NUMBER WINDOW. FIRST IT IS TESTED FOR FFFF (LOAD/TEST NEXT FOUND
;FILE). IF FFFF, THE ROUTINE SKIPS AHEAD TO LOAD/TEST THE FILE. OTHERWISE THE REQUIRED
;FILE NUMBER IS SUBTRACTED FROM THE JUST LOADED FILE NUMBER, IF THE RESULT IS ZERO THEN
;THE FILE IS THE ONE SELECTED AND IS LOADED/TESTED.
;THE OPTIONAL START WINDOW IS THEN TESTED FOR FFFF. IF IT IS, THE START ADDRESS FROM THE
;TAPE IS USED. IF THE OPTIONAL START BUFFER HAS SOMETHING OTHER THAT FFFF, THEN THE ADDRESS
;HERE IS USED AS THE START ADDRESS TO LOAD/TEST THE TAPE.

            LD      HL, (TAPE_FILE)                     ;TEST FOR FFFF IN FILE NAME WINDOW
            INC     HL
            LD      A, H
            OR      L
            DEC     HL                                  ;JUMP IF FILE WINDOW IS FFFF
            JR      Z, L057A                            ;TO INPUT FILE REGARDLESS OF ITS NUMBER
            LD      DE, (TAPE_O_FIL)                    ;ELSE TEST THAT INPUT FILE NAME
            OR      A                                   ;IS THE SAME AS THE ONE IN THE FILE
            SBC     HL, DE                              ;NUMBER WINDOW AND JUMP IF NOT
            JR      NZ, TAPE_INPUT                      ;SELECTED FILE TO LOOK FOR NEXT FILE
L057A:      LD      HL, (TAPE_START)                    ;TEST THAT OPTIONAL START ADDRESS
            INC     HL                                  ;IS FFFF
            LD      A, H
            OR      L
            DEC     HL
            JR      NZ, L0586                           ;JUMP IF NOT, ELSE USE START ADDRESS
            LD      HL, (TAPE_O_STA)                    ;PROVIDED FROM THE TAPE

;THE MAIN LOAD/TEST ROUTINE STARTS HERE.
;REFER TO THE DESCRIPTION OF THE BYTE COUNT AND BLOCK FORMATION AT THE OUTPUT SECTION
;ROUTINE (SEE 508).
;WHEN ALL THE BLOCKS HAVE BEEN INPUTTED AND THE ROUTINE JUMPS TO DISPLAY PASS/FAIL -Ld ON
;THE LED DISPLAY.
;HL IS POINTING TO THE PLACE IN MEMORY WHERE THE FILE WILL BE LOADED/TESTED.

L0586:      LD      BC, (TAPE_O_LEN)                    ;PUT NUMBER OF BYTES INTO BC
            CALL    TAPE_DISP                           ;CALL B CONVERT AND TEST
            JR      NZ, L0594                           ;JUMP IF NOT ZERO AS THERE IS AT
            LD      A, B                                ;LEAST ONE FULL BLOCK TO LOAD/TEST
            OR      A                                   ;CHECK THAT B (FORMALLY C)=0
            JR      Z, L059D                            ;JUMP IF SO AS ALL BYTES DONE
            XOR     A                                   ;ELSE SET ZERO FLAG TO REMEMBER
L0594:      PUSH    AF                                  ;SAVE FLAGS ON STACK
            CALL    LOAD_BLK                            ;CALL INBLOCK
            JR      NZ, L05A0                           ;JUMP IF LOAD/TEST FAILED
            POP     AF                                  ;RECOVER FLAGS
            JR      NZ, L0586                           ;LOOP IF THERE MIGHT BE MORE
L059D:      XOR     A                                   ;SET ZERO (SUCCESS) FLAG
            JR      TAPEFAIL                            ;JUMP TO END HANDLER
L05A0:      POP     DE                                  ;CLEAN UP STACK
TAPEFAIL:   JR      NZ, PF_ENTRY                        ;JUMP IF FAILED LOAD/TEST

;THE LOAD/TEST HAS PASSED. TEST HERE FOR OPTIONAL AUTO-GO AND FOR LOAD OPERATION (NO
;AUTO-GO FOR TEST OPERATIONS). START EXECUTION AT AUTO-GO ADDRESS IF REQUIRED.

            LD      HL, (TAPE_O_GO)                     ;PUT OPTIONAL GO ADDRESS IN HL
            INC     HL                                  ;TEST FOR FFFF
            LD      A, H                                ;AND JUMP
            OR      L                                   ;IF FFFF
            DEC     HL                                  ;AS THERE
            JR      Z, PF_ENTRY                         ;IS NO AUTO-GO
            LD      A, (TAPE_ACTN)                      ;TEST THAT A LOAD OPERATION WAS
            OR      A                                   ;DONE
            JR      NZ, PF_ENTRY                        ;SKIP JUMP IF IT WAS A TEST
            JP      (HL)                                ;ELSE AUTO START THE PROGRAM

;THE POST LOAD/TEST MENU DISPLAYS ARE SET UP HERE. IF THE LOAD/TEST FAILED THE ZERO FLAG
;IS CLEAR THE ROUTINE WILL POINT TO THE "FAIL" DISPLAY. OTHERWISE IT IS SET TO POINT TO
;THE "PASS" DISPLAY. THE DATA DISPLAY IS CALCULATED BY ADDING THE MENU ENTRY NUMBER OF
;THE JUST PERFORMED OPERATION X2, TO THE TABLE BASE OF POST LOAD/TEST DATA DISPLAYS.
;(THE MENU ENTRY NUMBER IS STILL THE SAME AS IT WAS WHEN "GO" WAS PRESS FROM THE MENU).

ORG         $05B3
PF_ENTRY:   LD      DE, TAPE_FDA_TBL                    ;LOAD DE TO BASE OF DATA DISPLAY
            LD      HL, TAPE_FAIL                       ;TABLE AND HL "FAIL" DISPLAY
            JR      NZ, L05BE                           ;TABLE:
            LD      L, 0x58                             ;ADJUST HL TO PASS IF ZERO
L05BE:      NOP                                         ;(FROM FIXED ERROR)
            LD      A, (MENU_NO)                        ;FIND WHAT OPERATION WAS PERFORMED
            RLCA                                        ;AND DOUBLE VALUE AND ADD TO HL TO
            ADD     A, E                                ;POINT DE AT POST TAPE OPERATION
            LD      E, A                                ;DATA DISPLAY ENTRY (SEE 0768-0771)
            NOP                                         ;(FROM FIXED ERROR)
            XOR     A                                   ;ZERO A
            JP      L0047                               ;JUMP TO SOFT MENU ENTRY

;THIS IS THE CONVERT/TEST B ROUTINE.
;THE VALUE IN B IS CONVERTED AND OUTPUTTED TO PORT 2.
;THEN B IS TESTED AND ONE OF THE FOLLOWING OPERATIONS IS PERFORMED. IF B=0 THEN C IS
;TRANSFERRED INTO B AND THE ZERO FLAG IS SET. IF B IS NOT 0 THEN B IS DECREMENTED, THE
;COUNT IS UP-DATED IN ITS BUFFER AND THE ZERO FLAG AND B IS CLEARED.

ORG     $05C9
TAPE_DISP:  LD      A, B                                ;PUT HIGH BYTE OF COUNT IN A
            AND     0x0F                                ;MASK TO ONE DIGIT
            LD      DE, SEG_TBL                         ;POINT DE TO DISPLAY CODE TABLE
            ADD     A, E                                ;ADD A
            LD      E, A
            LD      A, (DE)                             ;GET DISPLAY VALUE
            OUT     (DSEGMENT), A                       ;OUTPUT IT TO DISPLAY
            LD      A, B                                ;TEST HIGH BYTE
            OR      A                                   ;FOR ZERO
            JR      Z, L05E1                            ;JUMP IF ZERO
            DEC     B                                   ;ELSE DECREASE COUNT BY ONE BLOCK
            LD      (TAPE_O_LEN), BC                    ;STORE COUNT
            LD      B, 0x00                             ;LOAD B FOR 256 BYTE OUTPUT BLOCK
            OR      A                                   ;CLEAR ZERO FLAG
            RET                                         ;DONE
L05E1:      LD      B, C                                ;PUT LAST BLOCK SIZE IN B
            RET                                         ;DONE

;THIS BLOCK LOADS/TESTS THE BYTES IN FROM THE TAPE. THE NUMBER OF BYTES IS HELD IN B ON
;INPUT. AFTER THE SUB-ROUTINE THAT INPUTS A BYTE IS CALLED, A TEST AND JUMP IS DONE. THE
;TEST AND JUMP SELECT THE REQUIRED CODE TO PERFORM A LOAD OR TEST AS SELECTED FROM THE
;MENU BY THE USER. THE CHECK-SUM LOADED FROM THE TAPE HAS HAD ONE ADDED TO IT BY THE TAPE
;OUTPUT ROUTINE. THIS ADDED ONE IS REMOVED IN THIS ROUTINE BEFORE THE CHECK-SUM COMPARE
;IS DONE.

LOAD_BLK:   LD      A, (TAPE_ACTN)                      ;GET CURRENT OPERATION
            LD      C, A                                ;SAVE IN C
LOAD_BLK2:  XOR     A                                   ;CLEAR A FOR CHECKSUM
L05E8:      PUSH    AF                                  ;SAVE CHECKSUM
            CALL    LOAD_BYTE                           ;CALL GET BYTE
            BIT     1, C                                ;TEST FOR CURRENT OPERATION
            JR      NZ, L05FE                           ;JUMP IF A EITHER TEST
            LD      (HL), E                             ;ELSE STORE INPUTTED BYTE IN MEMORY
            INC     HL                                  ;POINT TO NEXT LOCATION
L05F2:      POP     AF                                  ;GET CHECKSUM
L05F3:      ADD     A, E                                ;ADD TO NEW BYTE
            DJNZ    L05E8                               ;DO UNTIL BLOCK DONE
            PUSH    AF                                  ;SAVE CHECKSUM
            CALL    LOAD_BYTE                           ;GET TAPE CHECKSUM
            POP     AF                                  ;GET MEMORY CHECKSUM
            DEC     E                                   ;CORRECT TAPE CHECKSUM
            CP      E                                   ;TEST CHECKSUMS TO SET FLAGS
            RET                                         ;BLOCK DONE
L05FE:      BIT     0, C                                ;TEST FOR WHICH TEST
            JR      NZ, L05F2                           ;JUMP IF CHECKSUM ONLY TEST
            POP     AF                                  ;GET CHECKSUM
            LD      D, A                                ;SAVE IN D
            LD      A, E                                ;GET INPUT BYTE
            CP      (HL)                                ;TEST TO MEMORY
            INC     HL                                  ;POINT TO NEXT LOCATION
            LD      A, D                                ;PUT CHECKSUM BACK IN A
            JR      Z, L05F3                            ;JUMP TO MAIN LOOP IF ALL OK
            RET                                         ;RETURN IF ERROR

;THIS ROUTINE INPUTS A SINGLE BYTE.
LOAD_BYTE:  CALL    LOAD_BIT                            ;GET START BIT
            LD      D, 0x08                             ;LOAD D FOR 8 BITS
L0610:      CALL    LOAD_BIT                            ;GET BIT
            RR      E                                   ;PUT IT IN E
            DEC     D
            JR      NZ, L0610                           ;DO FOR EIGHT BITS,

;THIS ROUTINE INPUTS A SINGLE BIT
;THE STRUCTURE OF EACH BIT IS IMPORTANT TO UNDERSTAND AT THIS POINT. A LOGIC 0 IS REPRESENTED
;BY 4 SHORT PERIODS FOLLOWED BY 1 LONG PERIOD AND A LOGIC 1 BY 2 SHORT PERIODS AND 2 LONG
;PERIODS. THESE ARE HIGH SPEED FIGURES. FOR LOW SPEED THE ABOVE COUNTS ARE DOUBLED.
;THE BITS ARE DECODED BY COUNTING THE RATIO OF SHORT PERIODS TO LONG PERIODS. A COMPLICATED
;METHOD OF COUNTING IS USED TO RESULT IN THE BIT VALUE BEING REFLECTED IN BIT 7 OF L. THE
;ROUTINE IS TERMINATED WHEN A SHORT PERIOD THAT FOLLOWED A LONG PERIOD IS DETECTED. THE
;LONG PERIOD IS FLAGGED WITH BIT 0 OF H. THE "SHORT AFTER LONG" PERIOD USED FOR TERMINATION
;IS ACTUALLY THE FIRST CELL OF THE NEXT BIT.
;THE VALUE OF THE BIT INPUTTED IS THEN POT INTO THE CARRY FLAG.

LOAD_BIT:   EXX                                         ;SWAP REGISTERS
            LD      HL, 0x0000                          ;ZERO HL
L061C:      CALL    READ_TAPE                           ;CALL TO MEASURE PERIOD
            JR      C, L0627                            ;JUMP IF SHORT PERIOD
            DEC     L                                   ;SET HIGH ORDER BIT OF L TO ONES
            DEC     L
            SET     0, H                                ;REMEMBER THAT THE LONG PERIOD
            JR      L061C                               ;HAS BEEN DETECTED: LOOP BACK
L0627:      INC     L                                   ;SHORT PERIOD SO ADD ONE TO L
            BIT     0, H                                ;TEST FOR SHORT AFTER LONG PERIOD
            JR      Z, L061C                            ;JUMP IF NOT
            RL      L                                   ;END OF BIT: PUT BIT 7,L INTO
            EXX                                         ;CARRY: SWAP REGISTERS
            RET                                         ;INPUT BIT IN CARRY

;THIS ROUTINE INPUTS AND MEASURES THE PERIOD OF EACH TAPE CELL AND COMPARES IT TO THE
;THRESHOLD BETWEEN A SHORT AND LONG PERIOD. THE CELL IS ALSO ECHOED ON THE TEC SPEAKER.

READ_TAPE:  LD      DE, 0x0000                          ;ZERO DE FOR PERIOD MEASUREMENT
L0633:      IN      A, (P_DAT)                          ;TEST TAPE LEVEL
            INC     DE                                  ;TIME PERIOD
            RLA                                         ;PUT TAPE LEVEL INTO CARRY
            JR      NC, L0633                           ;LOOP UNTIL IT GOES HIGH
            XOR     A                                   ;ECHO IT ON
            OUT     (DSCAN), A                          ;THE TEC SPEAKER
L063C:      IN      A, (P_DAT)                          ;MEASURE SECOND HALF OF CYCLE
            INC     DE                                  ;IN THE SAME FASHION AS ABOVE
            RLA
            JR      C, L063C                            ;THIS TIME LOOP UNTIL TAPE LEVEL
            LD      A, 0x84                             ;GOES LOW: ECHO IT ON TEC SPEAKER
            OUT     (DSCAN), A
            LD      A, E                                ;GET PERIOD MEASUREMENT
            CP      0x1A                                ;COMPARE IT TO THRESHOLD
            RET                                         ;TO SET FLAGS: DONE

;THIS ROUTINE OUTPUTS A BLOCK TO THE TAPE. THE NUMBER OF BYTES IS HELD IN B AND THE BLOCK
;IS ADDRESS BY HL. AFTER ALL THE BYTES HAVE BEEN OUTPUTTED, THE CHECKSUM +1, WHICH WAS
;ADDED OF AS EACH BYTE WAS OUTPUTTED, IS SENT TO THE TAPE.

L064A:      EX      AF, AF'                             ;GET CHECKSUM IN A
TAPE_OUT:   LD      E, (HL)                             ;PUT BYTE TO BE OUTPUTTED IN E
            ADD     A, E                                ;ADD FOR CHECKSUM
            EX      AF, AF'                             ;SAVE IN ALTERNATE AF
            CALL    SAVE_BYTE                           ;CALL OUT BYTE
            INC     HL                                  ;POINT TO NEXT BYTE
            DJNZ    L064A
            EX      AF, AF'                             ;GET CHECKSUM
            INC     A                                   ;INCREASE IT BY ONE
            LD      E, A                                ;PUT IT IN E

;THIS ROUTINE OUTPUTS A SINGLE BYTE IN E TO THE TAPE. THE FORMAT IS 1 START BIT, EIGHT
;DATA BITS AND 1 STOP BIT.

SAVE_BYTE:  LD      D, 0x08                             ;SET D FOR 8 BITS
            OR      A                                   ;CLEAR CARRY AND CALL OUTBIT
            CALL    SAVE_BIT                            ;TO OUTPUT BINARY ZERO FOR START BIT
L065D:      RR      E                                   ;PUT FIRST BIT IN CARRY
            CALL    SAVE_BIT                            ;CALL OUT BIT
            DEC     D
            JR      NZ, L065D                           ;DO FOR 8 BITS
            SCF                                         ;SET CARRY TO OUTPUT STOP BIT (1)

;THIS ROUTINE OUTPUTS A SINGLE BIT. IF THE CARRY IS SET, THEN A LOGIC 1 IS OUTPUTTED
;OTHERWISE A LOGIC O.
;A 1 IS REPRESENTED BY 2 SHORT AND 2 LONG PERIODS.
;A 0 IS REPRESENTED BY 4 SHORT PERIODS AND 1 LONG PERIOD.
;L IS LOADED WITH DOUBLE THE LOW SPEED CYCLE COUNT AS IT IS USED TO COUNT THE HALF CYCLES
;IN THE TONE ROUTINE. IF THE HIGH SPEED SAVE IS SELECTED, THEN THE CYCLE COUNT WILL BE
;HALVED IN THE TONE ROUTINE.

SAVE_BIT:   EXX                                         ;SWAP REGISTERS
            LD      H, 0x00                             ;ZERO H
            JR      C, L0674                            ;JUMP IF BINARY 1 IS TO BE OUTPUTTED
            LD      L, 0x10                             ;LOAD L WITH HIGH TONE CYCLE COUNT
            CALL    HIGH_TONE                           ;CALL HIGH TONE
            LD      L, 0x04                             ;LOAD L WITH LOW TONE CYCLE COUNT
            JR      L067B                               ;JUMP TO LOW TONE
L0674:      LD      L, 0x08                             ;LOAD L FOR HIGH TONE CYCLE COUNT
            CALL    HIGH_TONE                           ;FOR BINARY ONE: CALL HIGH TONE
            LD      L, 0x08                             ;LOAD L FOR LOW TONE CYCLE COUNT
L067B:      CALL    LOW_TONE                            ;CALL LOW TONE
            EXX                                         ;SWAP BACK REGISTERS
            RET                                         ;DONE

;SET-UP FOR LOW TONE (LONG PERIOD)
LOW_TONE:   LD      C, 0x29                             ;LOAD C FOR LOW TONE
            JR      L0686                               ;JUMP TO TONE ROUTINE

;SET-UP FOR HIGH TONE (SHORT PERIOD)
HIGH_TONE:  LD      C, 0x11                             ;LOAD C FOR HIGH TONE

;TONE ROUTINE
;TESTS FOR LOWSPEED SAVE. IF SO THEN IT HALVES THE CYCLE COUNT IN L.
L0686:      LD      A, (MENU_NO)                        ;FIND WHICH SPEED
            OR      A                                   ;ZERO = HIGH SPEED
            JR      NZ, L068E                           ;JUMP IF LOW SPEED
            SRL     L                                   ;ELSE HALVE CYCLE COUNT
L068E:      LD      DE, 0001H                           ;
            LD      A, 0x84                             ;TURN ON SPEAKER AND MIDDLE DISPLAY
L0693:      OUT     (DSCAN), A                          ;
            LD      B, C                                ;
L0696:      DJNZ    L0696                               ;PERIOD DELAY
            XOR     0x80                                ;TOGGLE SPEAKER BIT
            SBC     HL, DE                              ;DECREASE CYCLE COUNT
            JR      NZ, L0693                           ;JUMP IF NOT ALL CYCLES DONE
            RET                                         ;ELSE RETURN

;THIS ROUTINE SETS UP THE "ERR-IN DISPLAY ON THE PERIMETER HANDLER.
ORG     $069F
ERR_ENTRY:  LD      HL, TAPE_ERRIN                      ;POINT HL TO "Err-In" DISPLAY
            LD      DE, DISP_BUFF                       ;CODE AND DE TO RAM DEstination
            LD      BC, 0x0006                          ;BC(ount)
            LDIR                                        ;MOVE BLOCK
            JP      L0050                               ;JUNE TO SOFT PERIMETER ENTRY

;----END OF TAPE ROUTINES----
;THIS ROUTINE IS THE KEYBOARD READER/VALIDATER
;THE ACTION IS AS FOLLOWS:
;A SHORT LOOP LOOKS FOR A KEY PRESS. IF NO KEY IS PRESSED, THEN THE KEY PRESS BUFFER (0825)
;IS CLEARED THE ZERO AND THE CARRY FLAG CLEARED AND THE ROUTINE RETURNS.
;IF A KEY IS FOUND, THEN THE REMAINING LOOP COUNTS ARE WORKED OFF IN A DUMMY LOOP TO ENSURE
;EQUAL TIME IN EXECUTING THE ROUTINE.
;IF IT IS THE FIRST TIME.THAT THE KEY HAS BEEN DETECTED, THEN THE KEY PRESS FLAG WILL BE
;CLEAR. (IT WAS CLEARED BY THE MONITOR VARIABLES ON RESET). THE ROUTINE TESTS FOR THIS
;CONDITION AND IF TRUE THEN THE KEY IS ACCEPTED AS "VALID" AND FLAGGED BY A SET CARRY AND
;SET ZERO FLAG AND THE KEY PRESS FLAG IS SET TO INDICATE THE A KEY HAS BEEN DETECTED. THE
;INPUT IS THEN PLACED IN BOTH THE "I" REGISTER AND THE ACCUMULATOR. IF A KEY IS DETECTED
;BUT FOUND NOT TO BE VALID, I.E. IT HAS ALREADY BEEN DETECTED AND PROCESSED, THEN THE
;CARRY WILL BE SET BUT THE ZERO CLEARED. THIS ALLOWS THE AUTO KEY REPEAT SECTION TO KNOW
;THAT A KEY IS STILL BEING HELD DOWN. THE AUTO KEY REPEAT SECTION MAKE UP ITS OWN MIND
;WHETHER IT IS VALID OR NOT.

ORG     $06AD
KEY_READ:   IN      A, (P_DAT)                          ;TEST FOR KEY PRESSED
            BIT     6, A
            JR      Z, L06BB                            ;DA IS LOW = KEYPRESS
            DJNZ    KEY_READ                            ;LOOP LOOKING FOR KEY UNTIL B=0
L06B5:      XOR     A                                   ;CLEAR KEY PRESS FLAG
            LD      (V_KEY_PRES), A
            DEC     A                                   ;SET A TO FF AND CLEAR ZERO FLAG
L06BA:      RET                                         ;DONE
L06BB:      LD      A, (V_KEY_PRES)                     ;GET KEY PRESS FLAG
            OR      A                                   ;TEST FOR ZERO
            JR      NZ, L06C1                           ;DUMMY JUMP TO EQUALIZE TIME
L06C1:      DJNZ    L06BB                               ;FINISH LOOP
            SCF                                         ;SET CARRY
            JR      NZ, L06BA                           ;DUMMY JUMP TO RETURN
            DEC     A                                   ;SET KEY PRESS FLAG TO FF
            LD      (V_KEY_PRES), A
KEY_GET:    IN      A, (KEYBOARD)                       ;GET INPUT KEY FROM ENCODER CHIP
            AND     0x1F                                ;MASK OFF UNUSED BITS
            BIT     7, A                                ;SET ZERO FLAG (THINK ABOUT IT!)
            SCF                                         ;SET CARRY
            LD      (V_KEY), A                          ;STORE INPUT KEY
            RET                                         ;DONE

;THIS ROUTINE IS CALLED ONCE ON EVERY HARD RESET. IT INITIALIZES THE LCD THEN TESTS THAT
;IT IS THERE (IT CANNOT DO IT THE OTHER WAY AROUND AS THE LCD NEEDS TO BE INITIALIZED
;BEFORE IT WILL RESPOND INTELLIGENTLY). IF THE LCD IS FITTED THEN THE ROUTINE WILL READ
;IN AN ASCII SPACE CHARACTER (20H) OR IF THE LCD IS NOT, JUNK FROM THE DATA BUSS.
;20H IS SUBTRACTED FROM WHATEVER IS READ IN AND THE RESULT IS STORED IN THE LCD ENABLE
;BUFFER. IF THE RESULT IS ZERO THEN THE LCD IS ENABLED. IT IS VITAL TO KNOW IF THE LCD IS
;FITTED, OTHERWISE THE ROUTINE WHICH READS THE BUSY FLAG MAY LOOP FOREVER.

LCD_RESET:  LD      HL, LCDRST_TBL                      ;POINT HL TO LCD INITIALIZE TABLE
            LD      BC, 0x0404                          ;B=4 BYTES, C=PORT 4
L06DB:      LD      DE, 0500H                           ;DELAY BETWEEN
L06DE:      DEC     DE                                  ;EACH BYTE
            LD      A, D                                ;AS PER
            OR      E                                   ;LCD MANUFACTER'S
            JR      NZ, L06DE                           ;INSTRUCTIONS
            OUTI                                        ;OUTPUT (HL) TO (C). HL=HL=1,B=B-1
            JR      NZ, L06DB                           ;JUMP IF B NOT 0
L06E7:      DJNZ    L06E7                               ;SHORT DELAY
            IN      A, (P_LCDDATA)                      ;INPUT FROM LCD TO SEE IF IT'S THERE
            SUB     0x20                                ;SUBTRACT ASCII SPACE, IF LCD FITTED
            LD      (V_LCD), A                          ;RESULT WILL BE ZERO: STORE THIS IN
            RET                                         ;LCD MASK: DONE
            
            DB      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  ;FILL 
            DB      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  ;FILL 
            DB      0xFF, 0xFF, 0xFF                    ;FILL 

;AT 0700 IS THE TAPE'S MENU JUMP TABLE.
ORG     0x0700
TAPE_JP_TBL:
            JP      J_TAPE_SAVE                        ;HIGH SPEED SAVE
            JP      J_TAPE_SAVE                        ;LOW SPEED SAVE
            JP      J_TAPE_TEST                        ;TEST BLOCK
            JP      J_TAPE_CHKS                        ;TEST CHECKSUM
            JP      J_TAPE_LOAD                        ;LOAD TAPE

;BELOW ARE THE JMON DEFAULT RESET VARIABLES (A ZERO IS THE ACTIVE RAM
;STATE UNLESS OTHERWISE STATED). LOCATION
;* DENOTES CONTROL BYTES DESIGNED TO BE USER ALTERED (IN RAM).

ORG     $070F
DEF_VARS:   DB      0x00                                ;KEY BUFFER 0820
L0710:      DB      0x00                                ;LCD ON/OFF FLAG 0821*
L0711:      DB      0x00                                ;SOUND ON/OFF 0822*
L0712:      DB      0xFF                                ;GO AT ALTERNATE GO ADDRESS IF AA 0823*
L0713:      DB      0xFF                                ;STEPPER KEY CONTROL/TIMER 0824
L0714:      DB      0x00                                ;KEY PRESSED FLAG 0825
L0715:      DB      0xFF                                ;UNUSED 0826
L0716:      DB      0x00                                ;AUTO INCREMENT ON/OFF 0827*
L0717:      DB      0x00, 0x0A                          ;ALT GO ADDR/SOFT RESET EDIT LOCATION ($1000) 0828*
L0719:      DB      0x70                                ;AUTO KEY REPEAT TIMER 082A
L071A:      DB      0x00                                ;MONITOR CONTROL BYTE 082B
L071B:      DB      0x00, 0x08                          ;DISPLAY BUFFER ADDRESS 082C*
L071D:      DB      0x00, 0x09                          ;INITIAL EDITING LOCATION 082E

;BELOW ARE THE JMON INDIRECT JUMP ADDRESSES. THIS TABLE IS SHIFTED DOWN TO 0830 ON A HARD RESET.
L071F:      JP      J_HL2CODE                           ;CONVERT HL TO DISPLAY CODE 0830
L0722:      JP      J_A2CODE                            ;CONVERT A TO DISPLAY CODE 0833
L0725:      JP      J_LEDSCAN                           ;LED SCAN ROUTINE 0836
L0728:      JP      J_SETDOTS                           ;SET LED DOTS 0839
L072B:      JP      J_TONEX2                            ;RESET TONES 083C
L072E:      JP      J_TONE                              ;TONE 083F
L0731:      JP      J_SCANKEY                           ;SCAN/KEY/LCD/PATCH LOOP 0842
L0734:      JP      J_DISPUPD                           ;SOFT JMON ENTRY L0845
L0737:      JP      J_LCD                               ;LCD ROUTINE 0848

;BELOW ARE THE DISPLAY TABLES FOR THE TAPE'S MENU ADDRESS DISPLAYS AND
;THE "ERR-IN" DISPLAY THAT IS SUPERIMPOSED OVER THE PERIMETER HANDLER.
TAPE_AD_TBL:
            DB      0xA7, 0x6F, 0xEA, 0xC7              ;"SAVE"
            DB      0xA7, 0x6F, 0xEA, 0xC7              ;"SAVE"
            DB      0xC6, 0xC7, 0xA7, 0xC6              ;"TEST"
            DB      0xC6, 0xC7, 0xA7, 0xC6              ;"TEST"
            DB      0xC2, 0xEB, 0x6F, 0xEC              ;"LOAD"

L074E:      DB      0x04, 0xC7, 0x64, 0xEC              ;"-End"
TAPE_ERRIN: DB      0x04, 0xC7, 0x44, 0x44, 0x28, 0x64  ;"-Err In"
            DB      0x4F, 0x6F, 0xA7, 0xA7              ;"PASS"
TAPE_FAIL:  DB      0x47, 0x6F, 0x28, 0xC2              ;"FAIL"

;BELOW ARE THE TAPE'S MENU DATA DISPLAYS.
TAPE_DA_TBL:
            DB      0x04, 0x6E                          ;"-H"
            DB      0x04, 0xC2                          ;"-L"
            DB      0xE6, 0xC2                          ;"bL"
            DB      0xC3, 0xA7                          ;"CS"
TAPE_FDA_TBL:
            DB      0x04, 0xC6                          ;"-t" Used for last menu and first failed menu
            DB      0x04, 0xA7                          ;"-S"
            DB      0xC6, 0xE6                          ;"tb"
            DB      0xC3, 0xA7                          ;"CS"
            DB      0xC2, 0xEC                          ;"Ld"

L0772:      DB      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF      ;(UNUSED)

;BELOW IS THE PERIMETER HANDLER COMMAND STRING FOR THE TAPE SOFTWARE.
ORG      $077C
TAPE_P_DRIVER:
            DB      0xFF,0xFF                           ;BLANK
            DW      PERM_DA_TBL                         ;LED DISPLAY FOR DATA, 2 BYTES EACH
            DB      0x99,0x08                           ;STORE KEYED INFO HERE AT 0X0898
            DB      0x00,0x03                           ;NUMBER OF PERIMETER ITEMS, =4
            DB      0xFF,0xFF                           ;FUNCTION TO CALL WHEN GO PRESSED (FILLED IN BY MENU)
                                                        ;;SEE 0426-044E).

;0786 - 0788 FF ;(RESERVED FOR COMMAND STRING EXPANSION).
            DB      0xFF,0xFF,0xFF

;BELOW IS THE TAPE'S MENU DRIVER COMMAND STRING.
ORG      $0789
TAPE_M_DRIVER:
            DB      0xFF,0xFF                           ;BLANK
            DB      0x00,0x04                           ;FIRST MENU ITEM AND TOTAL NUMBER IF ENTRIES
            DW      TAPE_JP_TBL                         ;JUMP TABLE FOR MENU ITEMS
            DW      TAPE_AD_TBL                         ;MENU ADDRESS LED DISPLAY TABLE
            DW      TAPE_DA_TBL                         ;MENU DATA LED DISPLAY TABLE
            DB      0xC9                                ;TAPE'S SOFTWARE MENU DATA KEY HANDLER
                                                        ;ROUTINE JUMP VECTOR (A RETURN INSTRUCTION).
;BELOW IS THE STEPPERS DATA DISPLAY CODES.
ORG     $0794
SEGREG_TBL: DB      0x4F, 0xC3                          ;"PC"
            DB      0x6F, 0x47                          ;"AF"
            DB      0xE6, 0xC3                          ;"BC"
            DB      0xEC, 0xC7                          ;"DE"
            DB      0x6E, 0xC2                          ;"HL"
            DB      0x28, 0x6E                          ;"IX"
            DB      0x28, 0xAE                          ;"IY"
            DB      0x7F, 0x57                          ;“AF'"
            DB      0xF6, 0xD3                          ;"BC'"
            DB      0xFC, 0xD7                          ;"DE'"
            DB      0x7E, 0xD2                          ;"HL'"
            DB      0xA7, 0x4F                          ;"SP"
            DB      0xFF                                ;(UNUSED)

;START OF STAGGERED TABLE OF JMON MODE WORDS FOR LCD
ORG     $07AD
LCDFNC_TBL: DB      0x44, 0x61, 0x74, 0x61              ;"Data"
            DB      0x41, 0x64, 0x64, 0x72              ;"Addr"

;LCD INITIALIZATION CODES
ORG     $07B5
LCDRST_TBL: DB      0x38, 0x01, 0x06, 0x0C              ;0X38 - 8-BIT MODE, 2 LINES, 5x8 DOTS
                                                        ;0x01 - CLEAR DISPLAY
                                                        ;0x06 - CURSOR TO RIGHT,NO SHIFT
                                                        ;0x0C - DISPLAY ON, CURSOR OFF

;THE REST OF THE JMON MODE WORD TABLE FOR LCD *THIS TABLE NEEDS TO BE 12 BYTES FROM LCDFNC_TBL
ORG     $07B9
L07B9:      DB      0x46, 0x73, 0x2D, 0x20              ;"Fs- "

;ADDRESS TABLE OF THE LCD PROMPT LOCATIONS.
ORG     $07BD
LCDPMT_TBL: DB      0x84, 0x87, 0x8A, 0x8D, 0xC4, 0xC7, 0xCA, 0xCD, 0x80

;TAPE'S PERIMETER HANDLER DATA DISPLAYS
ORG     $07C6
PERM_DA_TBL:
            DB      0x04, 0x47                          ;"-F"
            DB      0x04, 0xA7                          ;"-S"
            DB      0x04, 0xC7                          ;"-E"
            DB      0x04, 0xE3                          ;"-G"
            DB      0xFF, 0xFF                          ;(UNUSED)

;BELOW ARE THE DISPLAY CODE EQUIVALENTS OF THE HEX DIGITS 0 TO F LISTED IN ASCENDING ORDER.
ORG     $07D0
SEG_TBL:    DB      0xEB, 0x28, 0xCD, 0xAD, 0x2E, 0xA7, 0xE7, 0x29, 0xEF, 0x2F, 0x6F, 0xE6, 0xC3, 0xEC
            DB      0xC7, 0x47                      ;MJ: Split out to allow for a Label that is used

;FINALLY AT 07E0 IS THE FUNCTION-1 AND SHIFT JUMP ADDRESSES.  ACCESS BY PRESSING "SHIFT" + "NUMBER"
;OR "ADDRESS", then "+", then "NUMBER" TO ENTER FUNCTION-! MODE
ORG     $07E0
L07E0:      DW      FN_TAPE                             ;#0 TAPE MENU SETUP TO MENU DRIVER
            DW      FN_BACK1                            ;#1 MOVE ADDRESS BACK ONE LOCATION
            DW      FN_STEPPER                          ;#2 STEPPER ROUTINE
            DW      0xFFFF                              ;#3 N/A
            DW      FN_FORW4                            ;#4 MOVE ADDRESS FORWARD FOUR LOCATIONS
            DW      FN_S_RST                            ;#5 DO A SOFT RESET
            DW      FN_BACK4                            ;#6 MOVE ADDRESS BACK FOUR LOCATIONS
            DW      FN_REGDIS                           ;#7 DISPLAY REGISTERS
            DW      FN_FORW8                            ;#8 MOVE ADDRESS FORWARD EIGHT LOCATIONS
            DW      FN_FORW1                            ;#9 MOVE ADDRESS FORWARD ONE LOCATION
            DW      FN_BACK8                            ;#A MOVE ADDRESS BACK EIGHT LOCATIONS
            DW      0xFFFF                              ;#B N/A
            DW      0xFFFF                              ;#C N/A
            DW      0xFFFF                              ;#D N/A
            DW      0xFFFF                              ;#E N/A
            DW      0xFFFF                              ;#F N/A
