Files
Digital-Research-Source-Code/CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.ASM
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1532 lines
36 KiB
NASM

;
;CP/M MACRO ASSEM 2.0 #001 MOSS 2.2 MONITOR
;
TITLE 'MOSS 2.2 MONITOR'
PAGE 68
MACLIB Z80
;
.8080
;
; MOSS MONITOR (VERSION 2.2)
;
; 20 JUNE 1980
; ALL RIGHTS RESERVED BY ROBERT B. MASON
;
; OCR PDF Documents 09-20-2014 by Larry Kraemer
; Modify Z80.LIB to add needed Macro's by Garry Kraemer
; Debugging & Corrections by Garry Kraemer - Senior Software Engineer
;
MOSS ORG 0F000H
ROM EQU 0F000H ;ROM START ADDRESS
WSVEC EQU 0 ;VECTOR FOR WARM RESTART
NBKPTS EQU 2 ;NUMBER OF BREAKPOINTS
CTRLS EQU 13H ;ASCII DC3
CR EQU 0DH ;ASCII CARRIAGE RETURN
LF EQU 0AH ;ASCII LINE FEED
FMFD EQU 0CH ;ASCII FORM FEED
BELL EQU 7 ;ASCII CNTRL CHAR TO RING THE BELL
IOBYTE EQU 3 ;ADDRESS OF I/O CONTROL BYTE
SDATA EQU 20H ;SERIAL DATA PORT BASE ADDRESS
SINTEN EQU SDATA+1 ;SERIAL INTERRUPT ENABLE REGISTER
SIDENT EQU SDATA+2 ;SERIAL INTERRUPT IDENTIFICATION REGIS
SLCTRL EQU SDATA+3 ;SERIAL LINE CONTROL REGISTER
SMDMCT EQU SDATA+4 ;SERIAL MODEM CONTROL REGISTER
SLSTAT EQU SDATA+5 ;SERIAL LINE STATUS REGISTER
SMDMST EQU SDATA+6 ;SERIAL MODEM STATUS REGISTER
;
;
SPSV EQU 6 ;STACK POINTER SAVE LOCATION
;
;
; REGISTER STORAGE DISPLACEMENTS FROM
; NORMAL SYSTEM STACK LOCATION.
;
ALOC EQU 15H
BLOC EQU 13H
CLOC EQU 12H
DLOC EQU 11H
ELOC EQU 10H
FLOC EQU 14H
HLOC EQU 31H
LLOC EQU 30H
PLOC EQU 34H
SLOC EQU 17H
TLOC EQU 35H
TLOCX EQU 25H
LLOCX EQU 20H
APLOC EQU 9
BPLOC EQU 11
CPLOC EQU 10
DPLOC EQU 13
EPLOC EQU 12
FPLOC EQU 8
HPLOC EQU 15
LPLOC EQU 14
XLOC EQU 7
YLOC EQU 5
RLOC EQU 2
ILOC EQU 3
;
; JUMP TARGETS FOR BASIC INPUT/OUTPUT
;
CBOOT: JMP INIT ;COLD START
CONIN: JMP CI ;CONS0LE INPUT
READER: JMP RI ;READER INPUT
CONOUT: JMP CO ;CONSOLE OUTPUT
PUNCH: JMP PO ;PUNCH OUTPUT
LIST: JMP LO ;LIST OUTPUT
CONST: JMP CSTS ;CONSOLE STATUS
JMP IOCHK ;PUT IOBYTE INTO (A)
JMP IOSET ;(C) HAS A NEW IOBYTE
JMP MEMCK ;MEMORY LIMIT CHECK
JMP RTS ;IODEF- DEFINE USER I/O ENTRY POINTS
JMP RTS ;SPCL- I/O CONTROL
JMP REST ;BREAKPOINT ENTRY POINT
;
; TBL CONTAINS THE ADDRESSES OF THE ACTION ROUTINES
; THE EXECUTIVE USES IT TO LOOK UP THE DESIRED ADDRESS.
TBL: DW ASGN
DW QPRT
DW QPRT
DW DISP
DW EOF
DW FILL
DW GOTO
DW HEXN
DW INPT
DW QPRT
DW QPRT
DW LEADER
DW MOVE
DW QPRT
DW OUPT
DW QPRT
DW QUERY
DW READ
DW SUBS
DW MTEST
DW QPRT
DW COMP
DW WRITE
DW XMNE
DW I8250
DW BYE
;
; THE COLD INITIALIZATION CODE
;
INIT: DI ;DISABLE INTERRUPTS
LXI SP,3FH ;USE STACK TO INITIALIZE RESTARTS
LXI H,JMP*256 ; WITH RESTART ERROR VECTORS
LXI D,RSTER
MVI B,16 ;16 TIMES (64 BYTES)
INIT1: PUSH D
PUSH H
DJNZ INIT1
;
LXI SP,FAKE-2 ;SET UP TEMPORARY STACK
MVI A,0 ;SKIP THE NEXT INST
ORG $-1 ;SAVE A BYTE HERE
;
; MEMSIZ CALCULATES THE TOP OF CONTIGUOUS RAM. IT SEARCHES
; FROM THE BOTTOM UP UNTIL A NON-RAM LOCATION IS
; FOUND. IT THEN TAKES OFF FOR MONITOR WORK SPACE
; NEEDS AND RETURNS THE VALUE IN (H,L).
MEMSIZ: PUSH B ;MOITOR START LOCATION
LXI B,ROM
LXI H,-1 ;START OF MEMORY ADDRESS SPACE
MEMSZ1: INR H
MOV A,M
CMA
MOV M,A
CMP M
CMA
MOV M,A
JRNZ MEMSZ2
;
MOV A,H ;SEE IF ON MONITOR BORDER
CMP B
JRNZ MEMSZ1
;
MEMSZ2: DCR H ;TAKE OFF WORKSPACE
LXI B,EXIT-ENDX-3*NBKPTS+1
DAD B
POP B ;(B,C) IS UNPREDICTABLE DURING INIT
RET
;
; ROUTINE MEMCHK FINDS THE CURRENT TOP OF CONTIGUOUS MEMORY
; (LESS THE MONITOR WORKSPACE) AND RETURNS THE VALUE.
;
MEMCK: PUSH H ;SAVE (H,L)
CALL MEMSIZ ;GET THE RAM SIZE
MOV A,L
SUI 60 ;TAKE OFF WORK SPACE
JRNC MEMCK0
;
DCR H
MEMCK0: MOV B,H
POP H
RET
;
FAKE: DW FAKE+2
SPHL
LXI D,EXIT
XCHG
LXI B,ENDX-EXIT
LDIR
;
LXI B,3*NBKPTS
PUSH D
POP H
DCX H
LDIR
;
LXI H,-24
DAD SP
PUSH H
INX H ;ADJUST USER STACK LOCATION
INX H
SHLD SPSV ;SAVE THE STACK INITIAL VALUE
MVI D,10 ;INITIALIZE REGISTER STORAGE AREA
INIT2: PUSH B
DCR D ;LOOP CONTROL
JRNZ INIT2
;
; INSERT I/O INIT CODE HERE
CALL RTS
CALL I8250 ;INITIALIZE THE 8250
CALL RTS
LXI H,LOGMSG ;LOG ONTO THE SYSTEM
CALL PRTWD
JMPR WINIT ;GO TO MONITOR EXECUTIVE
;
; ROUTINE EXF READS ONE PARAMETER. IT EXPECTS THE FIRST
; CHARACTER OF THE PARAMETER TO BE IN THE A REGISTER
; ON ENTRY.
EXF: MVI B,1 ;SET UP FOR ONE PARAMETER
LXI H,0
JMPR EX1 ;FIRST CHARACTER IN A ALREADY
;
; ROUTINE EXPR READS PARAMETERS FROM THE CONSOLE
; AND DEVELOPS A 16 BIT HEXADECIMAL FOR EACH ONE.
; THE NUMBER OF PARAMETERS WANTED IS IN THE B REG
; ON ENTRY. A CARRIAGE RETURN WILL TERMINATE THE
; ENTRY SEQUENCE. A BLANK OR A COMMA WILL END THE
; CURRENT PARAMETER ENTRY. EACH PARAMETER ONLY
; TAKES THE LAST 4 DIGITS TYPED IN; ANY EXCESS IS
; DISCARDED. A NON-HEX DIGIT WILL TERMINATE THE
; ENTRY SEQUENCE AND CAUSE A WARM BOOT OF THE MON.
;
AS3: DJNZ AS2 ;PART OF THE ASSIGN CODE
;
EX3: JRNZ QPRT ;NON-ZERO IS ERROR
;
EXPR1: DCR B ;MORE PARAMETERS?
RZ ;NO, RETURN
EXPR: LXI H,0 ;INITIALIZE PARAMETER
EX0: CALL ECHO ;GET NEXT NUMBER
EX1: MOV C,A ;SAVE CHAR FOR LATER USE
CALL NIBBLE
JRC EX2 ;NOT A NUMBER, JUMP
;
DAD H ;MULTIPLY BY 16
DAD H
DAD H
DAD H
ORA L ;ADD ON NEW DIGIT
MOV L,A
JMPR EX0 ;GO GET NEXT DIGIT
;
EX2: XTHL ;PUT UNDER RETURN ADDRESS ON STACK
PUSH H ;RESTORE RETURN ADDRESS
MOV A,C ;REGET THE LAST CHARACTER
CALL P2C ;TEST FOR DELIMITER
JRNC EX3 ;JUMP IF NOT CARRIAGE RETURN
;
DJNZ QPRT ;CARRET WITH MORE PARAM MEANS ERROR
;
RET
;
; MAIN ACTION ROUTINES
;
; LOGICAL ASSIGNMENT OF PERIPHERALS
;
;THIS ROUTINE CONTROLS THE ASSIGNMENT OF PHYSICAL
;PERIPHERALS TO THE FOUR LOGICAL DEVICE TYPES. IT
;ALTERS IOBYTE (MEMORY LOCATION 0003) TO MATCH THE
;CURRENT ASSIGNMENT. THE FOUR LOGICAL DEVICES ARE
;CONSOLE, READER LIST, AND PUNCH. IN ALL CASES,
;THE TTY DEVICE IS SET UP AS THE DEFAULT DEVICE.
;
ASGN: CALL ECHO ;GET THE LOGICAL DEVICE DESIRED
LXI H,ALT ;START OF CONVERSION TABLE
LXI D,APT-ALT ;DISTANCE BETWEEN LOGICAL CHOICE
MVI B,4 ;NUMBER OF LOGICAL CHOICES
AS0: CMP M ;IS THS ONE IT?
JRZ AS1 ;YES, JUMP
;
DAD D ;NO, GO TO NEXT LOGICAL ENTRY
DJNZ AS0
;
QPRT: LXI H,QMSG ;GET ADDRESS OF QUESTION MARK MSG
CALL PRTWA ;PRNT IT
; THE WARM START CODE
WINIT: LHLD SPSV ;RESET THE STACK
SPHL
WINITA: LXI H,WINIT ;RESET RETURN AND WARM START VECTOR
PUSH H
SHLD WSVEC+1
MVI A,0C3H
STA WSVEC
CALL CRLF ;START A NEW LINE
CALL DECHO ;GET THE COMMAND
SUI 'A' ;GET RID OF ASCII ZONE
JRC QPRT ;BAD COMMAND
;
CPI 'Z'-'A'+1 ;CHECK UPPER LIMIT
JRNC QPRT ;BAD COM AND
;
ADD A ;DOUBLE IT FOR TABLE OFFSET
MOV E,A ;SET UP FOR DOUBLE ADD
MVI D,0
MVI B,2 ;SET UP FOR TWO PARAMETERS
LXI H,TBL ;GET ACTION ROUTINE ADDRESS
DAD D
MOV A,M ;LOAD H,L INDIRECT
INX H
MOV H,M
MOV L,A
PCHL ;GO TO ACTION ROUTINE
;
; FILL ACTION ROUTINE
;
;THIS ROUTINE FILLS A BLOCK OF MEMORY WITH A USER-
;DETERMINED CONSTANT. IT EXPECTS THREE PARAMETERS
;TO BE ENTERED IN THE FOLLOWING ORDER:
;
;START ADDRESS
;FINISH ADDRESS
;FILL VALUE
;
FILL: CALL EXPR3 ;GET THREE PARAMETERS
FIO: MOV M,C ;PUT DOWN THE FILL VALUE
CALL HILO ;INCREMENT AND CHECK THE POINTER
JRNC FIO ;NOT DONE YET, JUMP
POP D ;RESTORE STACK POINTER IN CASE
JMPR WINIT ; STACK WAS OVERWRITTEN
;
AS1: MOV D,B ;SAVE THE COUNTER RESIDUE
MVI B,4 ;LOOP CONTROL
CALL DECHO ;GET THE NEW ASSIGNMENT
AS2: INX H ;INCREMENT POINTER
CMP M ;SEE IF THIS IS IT
JRNZ AS3
;
MOV L,B ;SAVE THE RESIDUE TO FORM ASGT
DCR L ;ADJUST VALUE
MOV B,D ;REGET THE LOGICAL RESIDUE
MVI H,3 ;SET UP THE IOBYTE MASK
DCR B ;ADJUST THIS ONE ALSO
JRZ AS5 ;NO SHFT NEEDED
;
AS4: DAD H ;SHIFT THE MASKS INTO POSITION
DAD H
DJNZ AS4 ;NOT DONE YET, JUMP
;
AS5: LDA IOBYTE
ORA H ;MASK THE DESIRED ASSIGNMENT IN
XRA H ;LOGICAL ASGT BITS NOW OFF
ORA L ;PUT IN NEW VALUE
MOV C,A
IOSET: MOV A,C
STA IOBYTE ;SAVE NEW ASSIGNMENTS
RET
IOCHK: LDA IOBYTE
RET
;
ALT: DB 'L' ;LOGICAL LIST DEVICE TABLE
DB '2' ;USER DEVICE #2
DB '1' ;USER DEVICE #1
DB 'L' ;LIST TO HIGH SPEED PRINTER
DB 'T' ;LIST TO TTY
APT: DB 'P' ;LOGICAL PUNCH DEVICE TABLE
DB '2' ;USER DEVICE #2
DB '1' ;USER DEVICE #1
DB 'P' ;PUNCH TO HIGH SPEED PUNCH
DB 'T' ;PUNCH TO TTY
ART: DB 'R' ;LOGICAL READER DEVICE TABLE
DB '2' ;USER DEVICE #2
DB '1' ;USER DEVICE #1
DB 'P' ;READER TO HIGH SPEED READER
DB 'T' ;READER TO TTY
ACT: DB 'C' ;LOGICAL CONSOLE DEVICE TABLE
DB '1' ;USER DEVICE #1
DB 'B' ;CONSOLE TO BATCH (PRINTER OR PTR)
DB 'C' ;CONSOLE TO CRT
DB 'T' ;CONSOLE TO TTY
;
; THE BYE ROUTINE IS USED TO PREVENT UNAUTHORIZED USAGE
; OF THE SYSTEM. THE SYSTEM LOCKS UP AND WILL NOT
; RESPOND TO ANYTHING OTHER THAN TWO ASCII BELL
; CHARACTERS. WHEN IT SEES THEM CONSECUTIVELY
; CONTROL IS RETURNED TO THE MONITOR WITHOUT ALTERING
; ANYTHING.
;
BYE: MVI B,2 ;SET UP FOR TWO CHARACTERS
BYE1: CALL CONI ;GO READ THE CONSOLE
CPI BELL ;SEE IF AN ASCII BELL
JRNZ BYE ;NO, START OVER AGAIN
;
CALL ECH1 ;ECHO THE BELL
DJNZ BYE1 ;NOT YET, GET NEXT ONE
;
RET ;RETURN TO MONITOR
;
; COMPARE ROUTINE
;
;THIS ROUTINE COMPARES TWO BLOCKS OF MEMORY AGAINST EACH
; OTHER. IF A DIFFERENCE IN THE RELATIVE ADDRESS
; CONTENTS IS DETECTED THE ADDRESS OF THE FIRST
; BLOCK IS DISPLAYED ALONG WITH ITS CONTENTS AND
; THE CONTENTS OF THE OTHER BLOCK'S SAME RELATIVE
; ADDRESS.
COMP: CALL EXPR3 ;GO GET THREE PARAMETERS
CMPA: LDAX B ;GET SOURCE 2 DATA
PUSH B ;SAVE SOURCE 2 POINTER
MOV B,M ;READ SOURCE 1 DATA
CMP B ;COMPARE DATA
JRZ CMPB ;JUMP IF OK
;
PUSH PSW ;SAVE SOURCE 2 DATA
CALL LADRB ;WRITE THE ADDRESS
MOV A,B ;GET SOURCE 1 DATA
CALL DASH1 ;FORMAT
POP PSW ;REGET SOURCE 2 DATA
CALL HEX1 ;OUTPUT IT
CMPB: POP B
CALL HILOXB ;INCREMENT SOURCE I POINTER AND SEE IF
JMPR CMPA ;JUMP IF NOT DONE YET
;
;
; DISPLAY ACTION ROUTINE
; THIS ROUTINE DISPLAYS A BLOCK OF MEMORY ON THE
; CURRENT CONSOLE DEVICE (CONSOLE DUMP). THE USER
; MUST SPECIFY THE START AND FINISH ADDRESSES.
; THE DISPLAY IS ORGANIZED TO DISPLAY UP TO 16 BYTES
; PER DISPLAY LTNE WITH ALL COLUMNS ALIGNED SO
; EACH COLUMN HAS THE SAME LAST HEX DIGIT IN ITS ADDRESS
;
DISP: CALL EXLF ;GO GET BLOCK LIMITS
DIS1: CALL LADRB ;DISPLAY THE START ADDRESS
MOV A,L ;SEE IF ON 16 BYTE BOUNDARY
CALL TRPLSP ;SKIP OVER TO RIGHT COLUMN
PUSH H ;SAVE (H,L)
DIS2: MOV A,M ;GET THE CONTENTS
CALL HEX1 ;OUTPUT IT
CALL HILO ;INCREMENT CHECK POINTER
JRC DIS7 ;DONE IF CARRY SET
CALL BLK ;MAKE COLUMNS
MOV A,L ;READY FOR NEW LINE?
ANI 0FH
JRNZ DIS2
;
DIS3: POP H ;REGET LINE START ADDRESS
MOV A,L ;SKIP OVER TO RIGHT SPACE
ANI 0FH
CALL TRPL2
DIS4: MOV A,M ;GET MEMORY VALUE
ANI 7FH ;STRIP OFF PARITY BIT
MOV C,A ;SET UP FOR OUTPUT
CPI ' ' ;SEE IF PRINTABLE IN ASCII
JRC DIS5 ;JUMP IF' SO
;
CPI 7EH
JRC DIS6
;
DIS5: MVI C,'.' ;ELSE, PRINT A DOT
DIS6: CALL CONOUT
CALL HILOX ;INCREMENT (H,L) AND SEE IF DONE
MOV A,L ;NOT DONE, READY FOR NEW LINE?
ANI 0FH
JRNZ DIS4 ;JUMP IF NOT
;
JMPR DIS1 ;DO THE NEXT LINE
;
DIS7: SUB E ;SKIP OVER TO START ASCII PRINTOUT
CALL TRPLSP
JMPR DIS3 ;GO PRINT THE ASCII
;
;
TRPLSP: ANI 0FH ;ISOLATE THE LOW FOUR BITS
MOV B,A ;PREPARE TO SPACE OVER TO RIGHT COLUMN
ADD A ;TRIPLE THE COUNT
ADD B
TRPL2: MOV B,A ;PUT BACK INTO B
INR B ;ADJUST COUNTER
TRPL1: CALL BLK ;DO THE SPACING
DJNZ TRPL1 ;NO, DO ANOTHER COLUMN
;
RET
;
; GO TO ACTION ROUTINE
;
; GOTO COMMAND TRANSFERS CONTROL TO A SPECIFIED ADDRESS.
; IT ALLOWS THE SELECTIVE SETTING OF UP TO TWO BREAKPOINTS
; AS WELL AS ALLOWING ANY CONSOLE INPUT TO BREAKPOINT
; THE RUN, AS LONG AS INTERRUPT 1 IS ACTIVE.
;
GOTO: CALL PCHK ;SEE IF OLD ADDRESS WANTED
JRC GO3 ; YES, JUMP
JRZ GO0 ; YES, BUT SET SOME BREAKPOINTS
CALL EXF ;GET NEW GOTO ADDRESS
POP D
LXI H,PLOC ;PUT ADDRESS IN PC LOCATION
DAD SP
MOV M,D ;LOW BYTE
DCX H
MOV M,E ;HIGH BYTE
MOV A,C
CPI CR ;SEE IF A CR WAS LAST ENTERED
JRZ GO3
;
GO0: MVI B,NBKPTS
LXI H,TLOC ;POINT TO TRAP STORAGE
DAD SP
GO1: PUSH B ;SAVE NUMBER OF BREAKPOINTS
PUSH H ;SAVE STORAGE POINTER
MVI B,2 ;SET UP TO GET A TRAP ADDRESS
CALL EXPR1 ;GET A TRAP ADDRESS
POP D ;GET THE TRAP ADDRESS INTO (D,E)
POP H ;REGET THE STORAGE ADDRESS
MOV A,D ;INSURE THE TRAP ADDRESS ISN'T ZERO
ORA E
JRZ GO2 ;JUMP IF SO
;
MOV M,E ;SAVE THE BREAKPOINT ADDRESS
INX H
MOV M,D
INX H
LDAX D ;SAVE THE INSTRUCTION FROM THE BP ADDR
MOV M,A
INX H
MVI A,RST OR 8 ;INSERT THE BREAKPOINT
STAX D
GO2: MOV A,C ;REGET THE DELIMITER TO SEE
CPI CR ; IF WE ARE DONE SETTING BREAKPOINTS
POP B ; UNLOAD THE STACK FIRST
JRZ GO3 ;YES, JUMP
;
DJNZ GO1 ;JUMP IF NOT AT BP LIMIT
;
GO3: CALL CRLF
POP H ;GET RID OF STACK JUNK
LXI H,RS9
PUSH H
LXI H,REST
SHLD 9 ;SET BREAKPOINT JUMP VECTOR ADDRESS
LXI H,24 ;FIND REGISTER SET ROUTINE ADDRESS
DAD SP
POP D ;ADJUST THE STACK
PCHL ;GO TO THE DESIRED PLACE
;
; GENERAL PURPOSE INPUT/OUTPUT ROUTINES
;
;THESE ROUTINES ALLOW BYTE BY BYTE INPUT OR OUTPUT FROM
; THE CURRENT CONSOLE DEVICE. THEY ARE INVOKED BY
; THE MONITOR "I" OR "O" COMMAND.
INPT: CALL EXPR1 ;GET INPUT PORT NUMBER
POP B ;GET PORT # INTO C REGISTER
INP E ;READ VALUE INTO E REGISTER
;
JMPR BITS2 ;GO DO A BINARY PRINT OF THE VALUE
;
OUPT: CALL EXPR ;GET THE ADDRESS AND DATA FOR OUTPUT
POP D ;DATA VALUE INTO E
POP B ;PORT INTO C
OUTP E ;DO THE OUTPUT
;
RET
;
; MOVE ROUTINE
; THIS ROUTINE EXPECTS THREE PARAMETERS, ENTERED IN THE
; SOURCE FIRST BYTE ADDRESS
; SOURCE LAST BYTE ADDRESS
; DESTINATION FIRST BYTE ADDRESS
;
MOVE: CALL EXPR3 ;GET THREE PARAMETERS
MOV1: MOV A,M ;GET NEXT BYTE
STAX B ;MOVE IT
CALL HILOXB ;GO INCREMENT CHECK SOURCE POINTER
JMPR MOV1 ;NOT THERE YET, GO DO IT AGAIN
;
;
; SUBSTITUTE ACTION ROUTINE
;
; THIS ROUTINE ALLOWS THE USER TO INSPECT ANY MEMORY LOCATION
; AND ALTER THE CONTENTS TF DESIRED AND IF THE ADDRESS
; IS IN RAM. THE CONTENtS MAY BE LEFT UNALTERED
; BY ENTERING A SPACE, COMMA OR A CARRIAGE RETURN. IF
; A CARRIAGE RETURN IS ENTER~D THE ROUTINE IS TERMINATE
; IF A SPACE OR COMMA IS ENTER~D, THE ROUTINE
; PROCEEDS TO THE NEXT LOCATION AND PRESENTS THE USER
; WITH AN OPPORTUNITY TO ALTER IT.
;
SUBS: CALL EXPR1 ;GO GET ONE PARAMETER
POP H ;GET THE START ADDRESS
SUB1: MOV A,M ;GET THE CONTENTS OF THE ADDRESS
CALL DASH1 ;DISPLAY IT ON CONSOLE AND A DASH
CALL PCHK ;GET CHECK CHARACTER
RC ;DONE IF CARRIAGE RETURN
JRZ SUB2 ;NO CHANGE IF BLANK OR
;
CPI LF ;SEE IF PREVIOUS BYTE WANTED
JRZ SUB3 ;YES, DO IT
;
PUSH H ;SAVE MEMORY POINTER
CALL EXF ;GO GET REST OF NEW VALUE
POP D ;NEW VALUE TO E REGISTER
POP H ;RESTORE MEMORY POINTER
MOV M,E ;PUT DOWN NEW VALUE
MOV A,C ;GET THE DELIMITER
CPI CR ;SEE IF DONE (CARRIAGE RETURN)
RZ ;YES, RETURN TO MONITOR
SUB2: INX H ;NO INCREMENT MEMORY PONTER
INX H ;ALLOW A FALL THROUGH ON THE NEXT INST
SUB3: DCX H ;ADJUST (H,L) AS APPROPRIATE
MOV A,L ;GET LO ADDRESS BYTE
ANI 7 ;SEE IF ON A BOUNDARY
CZ LADRB ;CALL IF ON THE BOUNDARY
JMPR SUB1 ;GO DO THE NEXT LOCATION
;
;
; MTEST ROUTINE TESTS A SPECIFIED BLOCK OF MEMORY TO
; SEE IF ANY HARD DATA BIT FAILURES EXIST. IT IS
; NOT AN EXHAUSTIVE TEST BUT JUST A QUICK INDICATION
; OF THE MEMORY'S OPERATVENESS.
;
MTEST: CALL EXLF
MTEST1: MOV A,M ;READ A BYTE
PUSH PSW ;SAVE IT
CMA ;COMPLEMENT IT
MOV M,A ;WRITE IT
XRA M ;RESULT SHOULD BE ZERO
CNZ BITS ;LOG ERROR IF NOT
MTEST2: POP PSW
MOV M,A ;RESTORE ORIGINAL BYTE
CALL HILOX ;PONT TO NEXT AND SEE IF DONE
JMPR MTEST1 ;NO, CONTINUE
;
BITS: PUSH D ;SAVE (D,E)
MOV E,A ;SAVE ERROR PATTERN IN E
CALL LADRB ;FIRST PRINT THE ADDRESS
BITS2: MVI B,8 ;LOOP CONTROL FOR 8 BITS
BITS1: MOV A,E ;GET NEXT BIT
RLC ; INTO CARRY
MOV E,A ;SAVE REST
MVI A,'0'/2 ;BUILD ASCII 1 OR 0
RAL ; CARRY DETERMINES WHICH
MOV C,A ;NOW, OUTPUT IT
CALL CONOUT
DJNZ BITS1 ;DO IT AGAIN
;
POP D
RET
;
; EXAMINE REGISTERS COMMAND INSPECTS THE VALUES OF THE
; THE REGISTERS STORED BY THE LAST ENCOUNTERED BREAKPOINT.
; THE VALUES MAY BE MODIFIED IF DESIRED.
;
XAA: INX H ;SKIP OVER TO NEXT ENTRY
INX H
XA: INR M ;SEE IF AT END OF TABLE
RZ ;COULDN'T FIND MATCH, QUIT
JP XAB ;SORT OUT BIT 7 OF TABLE
ORI 80H ;SET IT ON TEST VALUE
JMPR XAC
;
XAB: ANI 7FH ;RESET BIT 7
XAC: DCR M ;TO BE PULLED OUT IN ROM
CMP M ;SEE IF THIS IS IT
JRNZ XAA ;NO, GO TRY AGAIN
;
CALL BLK ;YES PREPARE TO SHOW CURRENT VALUE
CALL PRTVAL ;GO PRINT THE VALUE
CALL DASH ;PROMPT A NEW VALUE
CALL PCHK ;GET THE INPUT
RC ;DONE IF CARRIAGE RETURN
JRZ XF ;JUMP IF NO CHANGE DESIRED
;
PUSH H ;TO BE CHANGED, SAVE POINTER
CALL EXF ;GET THE NEW VALUE
POP H ; INTO (H,L)
MOV A,L ;GET THE N~W LOW BYTE
INX D ;ADJUST POINTER
STAX D ;PUT IT DOWN
XTHL ;RECOVER THE TABLE POINTER
MOV A,M ;GET THE ATTRIBUTES
XTHL ;SET THE STACK STRAIGHT
RLC ;SEE IF 8 BIT REGISTER
JRNC XE ;JUMP IF SO
;
INX D ;REGISTER PAIR, DO OTHER 8 BITS
MOV A,H
STAX D
XE: POP H ;RESTORE THE TABLE POINTER
XF: MOV A,C ;SEE IF IT WAS A CR
CPI CR
RZ ;DONE IF SO
XMNE: LXI H,ACTBL ;GET ADDRESS OF REGISTER LOOK-UP TABLE
XMNE1: CALL PCHK ;FIND OUT WHAT ACTION IS WANTED
JRC XG ;SHOW ALL IF CARRIAGE RETURN
;
JRZ XMNE1 ;IGNORE BLANKS OR COMMAS
CPI '''' ;SEE IF PRIMES WANTED
JRNZ XA ;NO, MUST BE SINGLE REGISTER
;
LXI H,PRMTB ;YES, SET TABLE ADDRESS
JMPR XMNE1 ; AND FIND OUT WHICH ONE
;
XG: MOV A,M
MOV C,A
INR A ;SEE IF AT END OF TABLE
RZ ;DONE IF SO
CM CRLF ;START A NEW LINE IF BIT 7 IS SET
CALL CONOUT
CALL DASH ;PROMPT FOR A NEW VALUE
CALL PRTVAL ;GO PRINT THE VALUE
CALL BLK ;FORMATTER
INX H ;POINT TO NEXT ENTRY
JMPR XG ;DO THE NEXT VALUE
;
PRTVAL: INX H ;POINT TO NEXT ENTRY
MOV A,M ;GET OFFSET AND ATTRIBUTES BYTE
ANI 3FH ;ISOLATE THE OFFSET
ADI 2 ;ALLOW FOR RETURN ADDRESS
XCHG ;RE-SWAP POINTERS
MOV L,A ;BUILD THE ADDRESS OF THE REQ CONTENTS
MVI H,0
DAD SP
XCHG ;RE-SWAP THE POINTERS
MOV A,M ;NOW FIND OUT ATTRIBUTES
MVI B,1 ;SET UP FOR SINGLE REG VALUE
RLC
JRNC PV1 ;JUMP IF SINGLE REGISTER VALUE WANTED
;
INR B ;SET UP FOR REGISTER PAIR
RLC
JRNC PV1 ;JUMP IF REGISTER PAIR IS NEXT
;
PUSH H ;SPECIAL CASE FOR MEMORY REGISTER
LDAX D ;BUILD ADDRESS IN (H,L)
MOV H,A
DCX D
LDAX D
MOV L,A
MOV A,M ;GET THE MEMORY VALUE
POP H ;RESTORE (H,L)
DJNZ PV2 ;ALWAYS JUMP
;
PV1: LDAX D ;GET THE REGISTER CONTENTS
PV2: CALL HEX1 ;OUTPUT THE VALUE
DCX D ;ADJUST THE MEMORY POINTER
DJNZ PV1
;
RET
;
ACTBL: DB 80H+'A',ALOC
DB 'B',BLOC
DB 'C',CLOC
DB 'D',DLOC
DB 'E',ELOC
DB 'F',FLOC
DB 'H',HLOC
DB 'L',LLOC
DB 80H+'M',HLOC+0C0H
DB 'P',PLOC+80H
DB 'S',SLOC+80H
DB 'I',ILOC
;
; REST OF Z 80 REGISTER OFFSETS
;
PRMTB: DB 80H+'A',APLOC
DB 'B',BPLOC
DB 'C',CPLOC
DB 'D',DPLOC
DB 'E',EPLOC
DB 'F',FPLOC
DB 'H',HPLOC
DB 'L',LPLOC
DB 80H+'M',HPLOC+0C0H
DB 'X',XLOC+80H
DB 'Y',YLOC+80H
DB 'R',RLOC
DB 0FFH
;
; GENERAL PURPOSE ROUTINES
;
;
; ROUTINE CONV CONVERTS THE LOW ORDER NIBBLE OF THE
; ACCUMULATOR TO ITS ASCII EQUIVALENT. IT
; PUTS THE RESULT INTO C FOR LATER OUTPUT.
;
CONV: ANI 0FH ;STRIP OFF BITS 4 7
ADI 90H ;PUT ON THE ASCII ZONE
DAA
ACI 40H
DAA
MOV C,A ;PUT IN OUTPUT PASS REGISTER
RET
;
; ROUTINE ECHO READS A BYTE FROM A HALF DUPLEX CONSOLE
; DEVICE THEN ECHOES THE CHARACTER BACK TO THE
; CONS0LE.
;
DECHO: CALL DASH ;PRINT A DASH
ECHO: CALL CONI ;CONSOLE READ, WRITE ROUTINE
ECH1: PUSH B ; SAVE (B,C)
MOV C,A ; PASS CHARACTER IN C REGISTER
CALL CONOUT ; OUTPUT IT
MOV A,C ; PUT CHARACTER BACK INTO A
POP B ; RESTORE (B,C)
RET
;
; ROUTINE EXPR3 GETS THREE PARAMETERS, DOES A CR LF AND
; THEN LOADS (B,C), (D,E), AND (H,L) WITH THE PARAMETERS.
EXPR3: INR B ;2 IS ALREADY IN THE B REGISTER
CALL EXPR ;GET THE PARAMETERS
POP B ;PUT PARAMETERS INTO REGISTERS
POP D
JMP CRLFA ;GO DO THE CARRIAGE RETURN SEQUENCE
;
; ROUTINE HILO INCREMENTS (H,L) IT THEN CHECKS FOR (AND
; DISALLOWS) A WRAP AROUND SITUATION. IF IT OCCURS,
; THE CARRY BIT WILL BE SET ON RETURN. IF NO WRAP-
; AROUND OCCURRED (H,L)IS COMPARED TO (D,E) AND
; THE FLAG BITS SET ACCORDINGLY.
HILO: INX H ;INCREMENT (H,L)
MOV A,H ;TEST IF ZERO
ORA L ; IN (H,L)
STC ;SET CARRY FOR (H,L)=0
RZ ;RETURN TF (H,L)=0
MOV A,E ;COMPARE(H,L) TO (D,E)
SUB L
MOV A,D
SBB H
RET ;RETURN WITH FLAGS SET
;
; ROUTINE HILOX INCREMENTS (H,L), COMPARES IT TO (D,E) AND
; IF EQUAL RETURNS CONTROL TO THE MONITOR EXECUThVE.
; OTHERWISE, CONTROL RETURNS TO THE CALLING ROUTINE.
;
HILOD: POP D ;GET RID OF RETURN ADDRESS
RET ;RETURN TO MONITOR
HILOXB: INX B ;INCREMENT (B,C)
HILOX: CALL HILO ;INC AND CHECK (H,L)
JRC HILOD ;DONE IF CARRY SET
;
CALL CONST ;SEE IF CONSOLE BREAK PENDING
ORA A
RZ ;NONE RETURN TO CONTINUE
CALL CONI ;SEE IF WAIT OR BREAK
CPI CTRLS
JRNZ HILOD ;JUMP IF BREAK
;
JMP CONI ;GO WAIT FOR NEXT CHARACTER
;
; ROUTINE NIBBLE CONVERTS THE ASCII CHARACTERS 0-9 AND
; A-F TO THEIR EQUIVALENT HEXADECIMAL VALUE. IF
; THE CHARACTER IS NOT IN RANGE, THE CARRY BIT IS SET TO
; FLAG THE ERROR.
NIBBLE: SUI '0' ;ASCII TO HEX CONVERSION
RC ; DONE IF OUT OF RANGE
CPI 'G'-'0' ;CHECK UPPER END
CMC ; TOGGLE THE CARRY BIT
RC ; DONE IF OUT OF RANGE
CPI '9'-'0'+1 ;SEE IF NUMERIC
CMC ; TOGGLE THE CARRY BIT
RNC ; DONE IF SO
SUI 'A'-'9'-1 ;SUBTRACT THE ALPHA BIAS
CPI 10 ; SET CARRY FOR INVALID CHAR
RET
;
; ROUTINE PCHK READS A CHARACTER FROM THE CONSOLE, THEN
; CHECKS IT FOR A DELIMITER. IF IT IS NOT
; A DELIMTTER A NON ZERO CONDITION IS RETURNED.
; IF IT IS A DELIMITER, A ZERO CONDITION IS RETURNED.
; FURTHER TF THE DELIMITER IS A CARRIAGE RETURN
; THE CARRY BIT IS SET. A BLANK OR A COMMA RESET'S
; THE CARRY BIT.
;
PCHK: CALL ECHO ;GET, TEST FOR DELIMITER
P2C: CPI ' ' ; BLANK?
RZ ; YES, DONE
CPI ',' ; NO COMMA?
RZ ; YES, DONE
CPI CR ; NO CARRIAGE RETURN?
STC ; SHOW IT IN CARRY BIT
RZ ; DONE IF CR
CMC ; CLEAR CARRY FOR NO DELIMITER
RET
;
; ROUTINE REST TRAPS ALL OF THE REGISTER CONTENTS WHENEVER A
; RESTART 1 INSTRUCTION IS EXECUTED. THE TRAPPED CONTEN
; ARE STORED IN THE SYSTEM STACK AREA FOR LATER ACCESS AND
; USE BY THE GOTO AND THE EXAMINE REGISTERS COMMANDS.
;
; INSERT INTERRUPT DISABLER SOFTWARE AT START OF REST:
REST: PUSH H ;SAVE ALL THE REGISTERS
PUSH D
PUSH B
PUSH PSW
CALL MEMSIZ ;GET THE MONITOR'S STACK LOCATION
XCHG
LXI H,10 ;GO UP 10 BYTES IN THE STACK
DAD SP ; TO SKIP OVER TEMP REGISTER SAVE
MVI B,4 ;PICK OFF THE REGISTER VALUES
XCHG
RS1: DCX H
MOV M,D ;SAVE IN WORK AREA
DCX H
MOV M,E
POP D
DJNZ RS1
;
POP B ;GET THE BREAKPOINT LOCATION
DCX B
SPHL ;SET THE MONITOR STACK
LXI H,TLOCX ;SET UP TO RESTORE BREAKPOINTS
DAD SP
PUSH D
MVI D,NBKPTS ;LOOP CONTROL F0R N BREAKPOINTS
RS2: MOV A,M
SUB C ;SEE IF A SOFTWARE TRAP
INX H
MOV A,M
SBB B ;MAYBE, TRY REST OF ADDRESS
JRZ RS5 ;FOUND ONE, JUMP TO RESET IT
;
RS3: INX H ;NOT FOUND, TRY NEXT ONE
INX H
DCR D
JRNZ RS2
;
RS4: INX B ;NONE FOUND
RS5: LXI H,LLOCX
POP D
DAD SP
MOV M,E ;STORE USER (H,L)
INX H
MOV M,D
PUSH B ;SAVE (B,C)
MVI C,'*' ;TYPE THE BREAK INDICATION
CALL CONOUT
POP D ;REGET THE BREAKPOINT LOCATION
MVI A,RS9/256
CMP D ;SEE IF A RET BREAKPOINT
JRZ RS6
;
INX H
INX H
MOV M,E ;RESTORE USER PROGRAM COUNTER
INX H
MOV M,D
XCHG ;PRINT THE BREAKPOINT LOCATION
CALL LADR
RS6: LXI H,TLOCX
DAD SP
LXI B,NBKPTS*256
RS7: MOV E,M ;RESTORE BREAKPOINTED LOCATIONS
MOV M,C ;RESET SYSTEM BP SAVE AREA
INX H
MOV D,M
MOV M,C
INX H
MOV A,E
ORA D
JRZ RS8 ;DO NOTHING IF ZERO
;
MOV A,M
STAX D
RS8: INX H ;SAME THING FOR OTHER
DJNZ RS7 ; BREAKPOINT
;
EXAF ;NOW SAVE THE Z-80 UNIQUES
EXX
;
PUSH H
PUSH D
PUSH B
PUSH PSW
PUSHIX
;
PUSHIY
;
LDAI
;
MOV B,A
LDAR
;
MOV C,A
PUSH B
JMP WINITA ;RETURN TO MONITOR
RS9: PUSH H ;RET BREAKPOINT ENCOUNTERED, ADJUST TH
RST 1 ;DO THE BREAKPOINT
EXIT: POP B
MOV A,C
STAR
;
MOV A,B
STAI
;
POPIX
;
POPIY
;
POP PSW
POP B
POP D
POP H
EXAF
;
EXX
;
POP D
POP B
POP PSW
POP H
SPHL
DB 0 ;PLACE FOR EI
LXI H,0
JMP 0
ENDX: EQU $
;
;ERROR HANDLERS
;
; THREE TYPES OF ERRORS ARE DETECTED: A RESTART
; ERROR AN I/O ASSIGNMENT ERROR AND CERTAIN PROGRAM
; ERRORS (DETERMINED BY THE PARTCULAR ROUTINE WHERE
; THE ERROR CONDITION WAS ENCOUNTERED.) EACH CAUSES
; A UNIQUE MESSAGE TO BE PRINTED, THEN DOES A WARM
; INITIALIZATION OF THE MONITOR. THE I/O ERROR
; CAUSES THE I/O ASSIGNMENTS TO BE RESET TO DEFAULT ASSI
IOER: XRA A ;SET IOBYTE TO DEFAULT VALUE
STA IOBYTE
LXI H,IOMSG ;GET ADDRESS OF I/O ERROR MSG
JMP COMERR ;GO PROCESS IT
IOMSG: DB 'I/O ER','R'+80H
;
; BYTE ROUTINE READS TWO ASCII CHARACTERS FROM THE
; CURRENT PAPER TAPE READER AND ASSEMBLES THEM INTO TWO
; HEXADECIMAL BYTES OF DATA. IT UPDATES A CHECKSUM
; ACCUMULATED IN REGISTER D.
BYTE: CALL BYT ;GET NEXT BYTE
ORA B ;COMBINE THEM
MOV B,A
ADD D ;UPDATE CHECKSUM
MOV D,A
MOV A,B ;RESTORE BYTE
RET
;
PEOL: MVI C,CR
CALL PO
MVI C,LF
JMP PO ;GO PUNCH THE OUTPUT
;
; RIX ROUTINE READS ONE CHARACTER FROM THE CURRENT
; PAPER TAPE READER AND STRIPS OFF THE PARITY BIT.
RIX: CALL RI
ANI 7FH
RET
QMSG: DB '???','?'+80H
LOGMSG: DB 'MOSS VERS 2.2'
DB CR,LF+80H
;
; INITIALIZATION CODE FOR THE 8250 ASYNCHRONOUS COMMUNICATION
; ELEMENT. THIS CODE WILL INITIALIZE THE BAUD RATE OF THE
; 8250, AS WELL AS THE WORD FORMAT. 8 DATA BTTS I STOP BIT
; AND NO PARITY ARE SELECTED. EITHER 2 OR 3 CARIAGE RETURNS
; MUST BE ENTERED TO ESTABLISH THE CORRECT BAUD RATE.
I8250: MVI A,0FH ;SET UP THE 8250
OUT SMDMCT
LXI D,40H ;SET UP TO TIME THE START BIT
MOV H,D
MOV L,D ;ZEROES TO (H,L)
I8250A: IN SMDMST ;WAIT FOR START BIT
ANA E
JRZ I8250A
;
I8250B: IN SMDMST ;NOW, TIME THE START BIT DURATION
INX H
ANA E
ANA E
JNZ I8250B
PUSH H ;SAVE COUNT IN CASE OF 4 MHZ
DAD H ;PREPARE THE 2 MHZ DIVISOR
MOV E,H ;SET UP THE FUDGE FACTOR
DAD D ;APPLY THE FUDGE FACTOR
DAD D
PUSH H ;SAVE FOR LATER USE
DAD H ;WAIT FOR 8 BIT TIMES
DAD H
I8250C: IN SDATA ;WASTE SOME TIME
DCX H
MOV A,L
ORA H
JNZ I8250C
POP H ;REGET 2 MHZ DIVISOR
I8250D: MVI A,83H ;SET DIVISOR REGISTER ACCESS
OUT SLCTRL
MOV A,L ;SET THE DIVISOR
OUT SDATA
MOV A,H
OUT SINTEN
MVI A,3 ;SET DATA REGISTER ACCESS
OUT SLCTRL
XRA A ;DISABLE INTERRUPTS
OUT SINTEN
OUT SLSTAT ;AND RESET ERROR FLAGS
CALL TTYIN ;GET A CHARACTER
ANI 7FH ;STRIP OFF ANY PARITY BIT
CPI 0DH ;SEE IF IT IS A CARRIAGE RETURN
POP H ;SET THE STACK STRAIGHT
RZ ;DONE IF CARRIAGE RETURN RECEIVED
MOV E,L ;ELSE, MUST BE 4 MHZ SYSTEM
MOV D,H ; SO, COUNT=COUNT*5/4
CALL DIV2
CALL DIV2
DAD D
PUSH H
JMPR I8250D ;GO SET THE NEW DIVISOR
;
;
;
DIV2: ORA A ;CLEAR THE CARRY BIT
MOV A,H ;DO A 16 BIT RIGHT SHIFT
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
RET
;
; EOF ROUTINE PUNCHES AN END OF FILE RECORD (INTEL HEX
; FORMAT) ONTO THE CURRENTLY ASSIGNED PAPER TAPE PUNCH
; DEVICE. AN ENTRY POINT ADDRESS FOR THE FILE WILL ALSO
; BE PUNCHED, IF SPECIFIED.
;
EOF: CALL EXLF ;GET JUMP ADDRESS
PUSH D ;SAVE THE # OF TRAILER NULLS
EOFA: CALL PSOR ;PUNCH START OF RECORD
XRA A ;ZERO OUT THE CHECKSUM
MOV D,A
CALL PBADR ;OUTPUT THE RECORD LENGTH AND EP
MVI A,1 ;PUNCH RECORD TYPE = 1
CALL PBYTE
XRA A
SUB D ;OUTPUT THE CHECKSUM
CALL PBYTE
JMPR LEO ;GO DO THE TRAILER
;
;
; LEADER ROUTINE 'PUNCHES' SIX INCHES (OR AS SPECIFIED)
; OF LEADER ON THE PAPER TAPE PUNCH. NULLS ARE PUNCHED
; TO FORM THE LEADER (OR TRAILER).
;
LEADER: CALL EXPR1 ;SEE IF SOME OTHER LENGTH WANTED
LEO: POP B ;GET THE VALUE
MOV A,B
ORA C ;TEST FOR DEFAULT SELECT
MOV B,C ;MOVE NEW VALUE IN JUST IN CASE
MVI C,0 ;GET A NULL CHARACTER
JRNZ LE1 ;JUMP IF NEW VALUE WANTED
;
MVI B,60 ;DEFAULT SET 60 NULLS
LE1: CALL PUNCH ;PUNCH ONE NULL
DJNZ LE1 ;KEEP GOING TIL DONE
;
RET
;
; QUERY ROUTINE WILL TELL THE OPERATOR WHAT HIS CURRENT LOGICAL
; PHYSICAL PERIPHERAL DEVICE ASSIGNMENTS ARE. NO PARAME
; (OTHER THAN A CARRIAGE RETURN) ARE REQUIRED ON ENTRY.
QUERY: LDA IOBYTE ;GET THE ASSIGNMENT CONTROL BYTE
MVI B,4 ;SET UP FOR FOUR LOGICAL DEVICES
LXI H,ACT ;ADDRESS OF CONVERSION TABLE
LXI D,ALT-APT ;NEGATIVE OFFSET FOR LOGICAL TABLE
QUE1: PUSH PSW
CALL BLK ;FORMAT THE PRINT OUT
MOV C,M ;GET THE CURRENT LOGICAL DEVICE CODE
CALL CONOUT ;OUTPUT IT
CALL DASH ;OUTPUT A DASH
POP PSW ;REGET THE CONTROL BYTE
PUSH PSW ;RESAVE IT
PUSH H ;SAVE THE TABLE POINTER
QUE2: INX H ;ADJUST POINTER TO CURRENT PHYSICAL DE
INR A
ANI 3 ;BITS 0 AND 1 ARE 0 WHEN ON CURRENT AS
JRNZ QUE2 ;NOT THERE YET, TRY AGAIN
;
MOV C,M ;FOUND IT, NOW PRINT IT
CALL CONOUT
POP H
POP PSW ;GO TO NEXT LOGICAL DEVICE
RAR ;ADJUST THE IOBYTE
RAR
DAD D ;ADJUST THE TABLE POINTER
DJNZ QUE1 ;GO DO NEXT LOGICAL DEVICE
;
RET ;RETURN TO MONITOR
;
; READ ROUTINE READS AN INTEL HEX FORMAT PAPER TAPE FROM
; THE CURRENT PAPER TAPE READER. IF A NON ZERO ADDRESS
; IS SPECIFIED IN THE END OF FILE RECORD CONTROL WILL
; BE TRANSFERRED TO THAT ADDRESS. OTHERWISE, CONTROL
; WILL REVERT TO THE EXECUTIVE.
;
READ: CALL EXPR1 ;GET OFFSET BIAS
REDO: POP H ; INTO (H,L)
PUSH H ;SAVE THE BIAS
RED1: CALL RIX ;READ A BYTE
SBI ':' ;LOOK FOR START OF RECORD
JRNZ RED1 ;JUMP TO KEEP LOOKING
;
MOV D,A ;INITIALIZE CHECKSUM
CALL BYTE ;GET RECORD LENGTH
JRZ RED3 ;JUMP IF EOF RECORD
;
MOV E,A ;ELSE, ASSUME DATA RECORD
CALL BYTE ;GET LOAD ADDRESS HIGH BYTE
PUSH PSW ;SAVE IT
CALL BYTE ;GET LOAD ADDRESS LOW BYTE
POP B ;BUILD ADDRESS IN (B,C)
MOV C,A
DAD B ;ADD ON THE BIAS
CALL BYTE ;SKIP OVER RECORD TYPE
RED2: CALL BYTE ;GET A DATA BYTE
MOV M,A ;PUT IT INTO MEMORY
CMA ;D0 A QUICK CHECK
XRA M ; RESULT SHOULD BE ZERO
CNZ BITS ;IF ERROR PRINT ADDRESS AND DATA
INX H ;INCREMENT MEMORY POINTER
DCR E ;RECORD LENGTH FOR LOOP CONTROL
JRNZ RED2 ;DO REST OF THE RECORD
;
CALL BYTE ;GET THE CHECKSUM
JNZ QPRT ;ABORT IF ERROR
JMPR REDO ;GO DO NEXT RECORD
;
RED3: CALL BYTE ;EOF RECORD GET ENTRY POINT
MOV H,A ;HIGH BYTE TO (H)
CALL BYTE ;GET THE LOW BYTE
MOV L,A
ORA H ;SEE IF IT IS ZERO
POP D ;RESTORE THE STACK
RZ ;RETURN TO MONITOR IF EP=0
PCHL ;ELSE, GO TO THE ENTRY POINT
;
; WRITE ROUTINE IS USED TO PUNCH AN INTEL HEX FORMAT
; PAPER TAPE ON THE CURRENT ASSIGNED PUNCH UNIT.
;
WRITE: CALL EXPR3 ;GET 3 PARAMETERS, DO CRLF
XRA A ;SEE IF RECORD LENGTH CHANGE
MOV B,A ;SET HIGH BYTE TO ZERO
ORA C ;NOW SEE IF CHANGE WANTED
JRNZ WRI1 ;YES, JUMP AND SET IT UP
;
MVI C,16 ;NO, DEFAULT TO 16 BYTES/RECORD
WRI1: PUSH H ;SAVE MEMORY POINTER
DAD B ;ADD THE RECORD LENGTH
ORA A ;CLEAR THE CARRY BIT
DSBC D ;SEE IF FULL RECORD REMAINS
;
POP H ;RESTORE (H,L)
JRC WRI2 ;GO DO A FULL RECORD
PUSH D ;SAVE LAST BYTE ADDRESS
XCHG ;SWAP (D,E) AND(H,L)
ORA A ;RESET THE CARRY BIT
DSBC D ;FIND # OF BYTE REMAINING
;
INX H ;ADJUST TO INCLUDE LAST BYTE
XTHL ;SWAP TOP OF STACK
XCHG ;SET (D,E) (H,L) TO NORMAL
POP B ;NEW RECORD LENGTH TO (B,C)
RC ;DONE IF ZERO LENGTH RECORD
WRI2: PUSH B ;SAVE LOOP COUNT
PUSH D
MOV D,B ;ZERO THE CHECKSUM
MOV B,C ;MOVE LOOP CONTROL TO B
CALL PSOR ;PUNCH START OF RECORD
MOV A,B ;GET RECORD LENGTH
CALL PBADR ;PUNCH IT
XRA A ;PUNCH RECORD TYPE '0'
CALL PBYTE
WRI3: MOV A,M ;GET NEXT DATA BYTE
INX H ;BUMP THE POINTER
CALL PBYTE ;PUNCH THE DATA
DJNZ WRI3 ;DO REST OF RECORD
;
XRA A ;NOW, DO THE CHECKSUM
SUB D
CALL PBYTE ;PUNCH IT
POP D ;RESTORE THE REGISTERS
POP B
JMPR WRI1 ;GO DO NEXT RECORD
;
PSOR: CALL PEOL
MVI C,':'
JMP PO
;
; HEXN ROUTINE
;
;THIS ROUTINE ADDS AND SUBTRACTS TWO HEXADECIMAL 16 BIT
; UNSIGNED NUMBERS AND DISPLAYS THE RESULTS ON THE
; CONSOLE.
HEXN: CALL EXLF ;GET THE TWO NUMBERS
PUSH H ;SAVE IT FOR THE SUBTRACT
DAD D ;ADD THEM
CALL LADRB ;OUTPUT THEM
POP H ;REGET THE FIRST NUMBER
ORA A ;CLEAR THE CARRY BIT
DSBC D ;DO THE SUBTRACT
;
JMPR LADR ;GO OUTPUT THE RESULT
;
;
; ROUTINE LADR PRINTS THE CONTENTS OF (H,L) ON THE
; CURRENT CONSOLE EITHER AT THE SART OF A NEW
; LINE (EP = LADRA) OH AT THE CURRENT LOCATION (EP =
; LADR).
LADRA: CALL CRLF ;START A NEW LINE
LADR: MOV A,H ;GET HIGH TWO DIGITS
CALL HEX1 ;PRNT THEM
MOV A,L ;GET LOW TWO DIGITS
HEX1: PUSH PSW ;SAVE THE LOW DIGIT
RRC ;PUT HIGH NIBBLE INTO BITS 0-3
RRC
RRC
RRC
CALL HEX2 ;GO PRINT SINGLE DIGIT
POP PSW ;REGET THE LOW DIGIT
HEX2: CALL CONV ;GO INSERT ASCII ZONE
JMPR CO ;DO THE CHARACTER OUTPUT
;
;
; ROUTINE DASH TYPES A DASH ON THE CURRENT CONSOLE DEVICE.
;
DASH1: CALL HEX1 ;FIRST, PRINT ACCUM AS TWO HEX DIGITS
DASH: MVI C,'-' ;GET AN ASCII DASH
JMPR CO ;GO TYPE IT
;
;
; IOBYTE HANDLERS
;
ORG MOSS + 05FBH
LADRB: CALL LADRA ;OUTPUT (H,L) AS 4 ASCII DIGITS
BLK: MVI C,' ' ;OUTPUT A BLANK
CO: LDA IOBYTE
ANI 3 ;ISOLATE CONSOLE ASGT
JZ TTYOUT ;TTY DEVICE ACTIVE
CPI 2
JM CRTOUT ;CRT ACTIVE
JNZ CUSO1 ;USER CONSOLE 1 ACTIVE
LO: LDA IOBYTE
ANI 0C0H ;ISOLATE LIST ASGT
JZ TTYOUT ;TTY DEVICE ACTIVE
CPI 80H
JM CRTOUT ;CRT ACTIVE
JZ LPRT ;LINE PRINTER ACTIVE
JMP LUSE1 ;USER PRINTER 1 ACTIVE
;
CSTS: LDA IOBYTE
ANI 3 ;ISOLATE CONSOLE ASGT
JZ TTST ;TTY ACTIVE
CPI 2
JM CRTST ;CRT ACTIVE
JNZ CUST1 ;USER CONSOLE 1 ACTIVE
;
BATST: LDA IOBYTE
ANI 0CH ;ISOLATE BATCH ASGT
JZ TTST ;TTY ACTIVE
CPI 8
JM PTRST ;PAPER TAPE READER ACTIVE
JZ RUST1 ;USER READER 1 ACTIVE
JMP RUST2 ;USER READER 2 ACTIVE
;
CI: LDA IOBYTE
ANI 3 ;ISOLATE CONSOLE ASGT
JZ TTYIN ;TTY DEVICE ACTIVE
CPI 2
JM CRTIN ;CRT ACTIVE
JNZ CUSI1 ;USER CONSOLE 1 ACTIVE
;
RI: LDA IOBYTE
ANI 0CH ;ISOLATE BATCH ASGT
JZ TTYRDR ;TTY ACTIVE
CPI 8
JM PTRIN ;PAPER TAPE READER ACTIVE
JZ RUSI1 ;USER READER I ACTIVE
JMP RUSI2 ;USER READER 2 ACTIVE
;
LSTAT: LDA IOBYTE
ANI 0C0H ;ISOLATE THE LIST DEVICE ASSIGNMENT
JZ TTOST
CPI 80H
JM CRTOST
JZ LPRST
JMP LUST1
;
PO: LDA IOBYTE
ANI 30H ;ISOLATE PUNCH ASGT
JZ TTPNCH ;TTY ACTIVE
CPI 20H
JM HSP ;HIGH SPEED PUNCH ACTIVE
JZ PUSO1 ;USER PUNCH 1 ACTIVE
JMP PUSO2 ;USER PUNCH 2 ACTIVE
;
; ROUTINE CONI READS THE CONSOLE AND STRIPS OFF THE ASCII
; PARITY BIT.
;
CONI: CALL CI ;GET THE NEXT CHARACTER
ANI 7FH ;STRIP OFF THE PARITY BIT
RTS: RET
;
; ROUTINE PRTWD PRINTS AN ASCII STRING ONTO THE CONSOLE.
; THE STRING MUST BE TERMINATED BY BIT 7 SET IN THE
; LAST CHARACTER OF THE STRING. THE STRING WILL START
; A NEW LINE (EP = PRTWD) OR CONTINUE ON THE SAME
; LINE (EP = PRTWA)
PRTWD: CALL CRLF ;START A NEW LINE
PRTWA: PUSH B ;SAVE (B,C)
PRTA: MOV C,M ;GET NEXT CHARACTER FROM MEMORY
CALL CO ;OUTPUT IT
INX H ;INCREMENT MEMORY POINTER
MOV A,C
RLC ;TEST FOR BIT 7 DELIMITER
JRNC PRTA ;NO DELIMITER, GO DO NEXT CHARACTER
;
PRTB: POP B ;RESTORE (B,C)
RET
;
; ROUTINE EXLF READS TWO PARAMETERS, PUTS THEM INTO THE
; D,E AND H,L REGISTERS, THEN DOES A CARRIAGE RETURN,
; LINE FEED SEQUENCE.
;
EXLF: CALL EXPR ;GO GET TWO PARAMETERS
POP D
POP H
;
; ROUTINE CRLF GENERATES A CARRIAGE RETURN, LNE FEED
; SEQUENCE ON THE CURRENT CONSOLE TO START A NEW LINE
; IT INCLUDES TRHEE NULL CHARACTERS FOR TTY TYPE
; DEVICES FOR THE HEAD MOVEMENT TIME.
;
CRLF: PUSH H ;SAVE THE CONTENTS OF (H,L)
CRLFA: LXI H,CRMSG ;ADDRESS OF CR,LF MESSAGE
CALL PRTWA ; OUTPUT IT
POP H ;RESTORE (H,L)
RET
;
RSTER: LXI H,RSTMSG ;GET ADDRESS OF RESTART ERROR MSG
COMERR: CALL PRTWD ;PRINT IT ON NEW LINE
JMP WSVEC ;GO TO WARM BOOT
RSTMSG: DB 'RST ER','R'+80H
CRMSG: DB CR,LF,0,80H
;
; I/O DRIVERS FOR THE 8250 ASYNC COMM ELEMENT
;
TTST: IN SLSTAT ;GET 8250 LINE STATUS
ANI 1 ;SEE IF RECEIVE DATA AVAILABLE
RZ ;RETURN IF NOT
ADI 0FEH ;FLAG THAT DATA IS AVAILABLE
RET
;
TTYIN: IN SLSTAT ;GET 8250 LINE STATUS
RAR ;MOVE RX DATA READY BIT INTO CARRY
JRNC TTYIN ;LOOP UNTIL DATA IS IN
;
IN SDATA ;READ THE DATA
RET
;
TTOST: IN SLSTAT ;GET 8250 LINE STATUS
ANI 20H ;ISOLATE TX BUFFER EMPTY BIT
RZ ;RETURN IF NOT EMPTY
ADI 0BFH ;FLAG THE EMPTY STATE
RET
;
TTYOUT: IN SLSTAT ;GET 8250 LINE STATUS
ANI 20H ;ISOLATE THRE BIT
JRZ TTYOUT ;WAIT UNTIL ONE OF THE REGISTERS EMPTI
;
MOV A,C ;MOVE THE DATA OVER
OUT SDATA ;OUTPUT THE DATA
RET
;
; EQUATES FOR ADDITIONAL CONSOLE DEVICES
CRTIN EQU IOER
CRTOUT EQU IOER
CRTST EQU IOER
CRTOST EQU IOER ;UNASSIGNED CRT OUTPUT STATUS
CUSI1 EQU IOER ;UNASSIGNED USER CONSOLE (INPUT)
CUSO1 EQU IOER ;UNASSIGNED USER CONSOLE (OUTPUT)
CUST1 EQU IOER
;
; EQUATES FOR ADDITIONAL PAPER TAPE PUNCH DEVICES
TTPNCH EQU TTYOUT ;UNASSIGNED TELETYPE PUNCH
HSP EQU IOER ;UNASSIGNED HIGH SPEED PUNCH
HSPST EQU IOER ;UNASSIGNED HJGH SPEED PUNCH STATUS
PUSO1 EQU IOER ;UNASSIGNED USER PUNCH 1
PUSO2 EQU IOER ;UNASSIGNED USER PUNCH 2
;
; EQUATES FOR ADDITIONAL LIST DEVICES
LPRT EQU IOER ;UNASSIGNED LINE PRINTER
LPRST EQU IOER ;UNASSIGNED PRINTER STATUS
LUSE1 EQU IOER ;LIST DEVICE 1
LUST1 EQU IOER ;LIST DEVICE 1 STATUS
;
; EQUATES FOR ADDITIONAL PAPER TAPE READER DEVICES
TTYRDR EQU TTYIN ;UNASSIGNED TELETYPE PAPER TAPE READER
PTRIN EQU IOER ;UNASSIGNED HIGH SPEED PAPER TAPE READ
PTRST EQU IOER ;UNASSIGNED HS PTR STATUS
RUSI1 EQU IOER ;UNASSIGNED PAPER TAPE READER 1
RUST1 EQU IOER ;UNASSIGNED PAPER TAPE READER 1 (STATUS)
RUSI2 EQU IOER ;UNASSIGNED PAPER TAPE READER 2
RUST2 EQU IOER ;UNASSIGNED PAPER TAPE READER 2 (STATUS)
;
BYT: CALL RIBBLE ;READ AND CONVERT ONE CHARACTER
RLC ;SHIFT INTO HIGH NIBBLE
RLC
RLC
RLC
MOV B,A ;SAVE IN B TEMPORARILY
RIBBLE: CALL RIX ;READ A CHARACTER
JMP NIBBLE ;GO CONVERT TO HEX DIGIT
;
; PADR ROUTINE PUNCHES (H,L) AS FOUR ASCII CHARACTERS.
; IT IS USED TO PUT THE ADDRESS INTO AN INTEL HEX
; FORMAT RECORD.
;
PBADR: CALL PBYTE
PADR: MOV A,H
CALL PBYTE
MOV A,L
;
; PBYTE ROUTINE PUNCHES (A) AS TWO ASCII CHARACTERS ON
; THE CURRENT PUNCH DEVICE.
;
PBYTE: PUSH PSW ;SAVE THE BYTE
RRC ;DO HIGH NIBBLE FIRST
RRC
RRC
RRC
CALL CONV ;CONVERT TO ASCII
CALL PUNCH ;PUNCH IT
POP PSW ;GET LOW NIBBLE
PUSH PSW ;RESAVE F0R CHECKSUM
CALL CONV ;CONVERT TO ASCII
CALL PUNCH ;PUNCH IT
POP PSW
ADD D ;UPDATE CHECKSUM
MOV D,A
RET
;
END