home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG019.ARK
/
RM80.ASM
< prev
next >
Wrap
Assembly Source File
|
1985-02-10
|
61KB
|
1,833 lines
;;; RM80 V2.0 - RESIDENT MONITOR FOR AN 8080 / Z80 SYSTEM
;
; LAWRENCE E. HUGHES III
; 8080 SOFTWARE DEVELOPMENT CENTER
; 1506 MYRICK ROAD
; TALLAHASSEE, FLORIDA 32303
ORG 5800H
TBUF: DS 1024 ;TAPE BUFFER
NBUF: DS 11 ;FILENAME BUFFER
TUNIT: DS 1 ;TAPE UNIT BUFFER
PRN: DS 1 ;PHYSICAL RECORD NUMBER
CTPC: DS 1 ;CASSETTE TAPE PAGE COUNT
IBUF: DS 128 ;INPUT BUFFER
STACK: DS 64 ;SYSTEM STACK AREA
PFLAG1: DS 1 ;PARAMETER FLAGS
PFLAG2: DS 1
PARAM1: DS 2 ;PARAMETERS
PARAM2: DS 2
CBUF: DS 6 ;COMMAND BUFFER
INCH: DS 1 ;CHARACTER BUFFERS FOR LINK
OUTCH: DS 1
DMPAD: DS 2 ;DUMP ADDRESS
CRC: DS 2 ;TEMP STORAGE FOR TAPE CRC
LDERR: DS 1 ;LOADER ERROR COUNT
OFLST: DS 1 ;OBJECT FILE LOADER STATE
OFLCE: DS 1 ;OBJECT FILE LOADER CHECKSUM ERROR FLAG
OFLLA: DS 2 ;OBJECT FILE LOADER LOAD ADDRESS
OFLOS: DS 2 ;OBJECT FILE LOADER OFFSET
OFLBC: DS 1 ;OBJECT FILE LOADER BYTE COUNT
OFLCS: DS 1 ;OBJECT FILE LOADER CHECKSUM
OFLBB: DS 1 ;OBJECT FILE LOADER BYTE BUFFER
OFLSW: DS 1 ;OBJECT FILE LOADER SWITCH (NON-ZERO = ON)
TFLSW: DS 1 ;TEXT FILE LOADER SWITCH (NON-ZERO = ON)
TFLFWA: DS 2 ;TEXT FILE LOADER FIRST WORD ADDRESS
TFLLWA: DS 2 ;TEXT FILE LOADER LAST WORD ADDRESS
TEMP: DS 3 ;TEMPORARY AREA FOR IN AND OUT COMMANDS
NULL EQU 00H
SOH EQU 01H
STX EQU 02H
ETX EQU 03H
BS EQU 08H
LF EQU 0AH
CR EQU 0DH
DEL EQU 7FH
;;; MAIN PROGRAM - GET COMMAND, SCAN IT AND BRANCH
ORG 0C000H
JMP RM80
JMP RACC ;READ ASCII CHAR FROM CONSOLE
JMP CRDAC ;CHECK FOR RDA FROM CONSOLE
JMP WACC ;WRITE ASCII CHAR TO CONSOLE
JMP CTBEC ;CHECK FOR TBE FROM CONSOLE
JMP RACM ;READ ASCII CHARACTER FROM MODEM
JMP CRDAM ;CHECK FOR RDA FROM MODEM
JMP WACM ;WRITE ASCII CHARACTER TO MODEM
JMP CTBEM ;CHECK FOR TBE FROM MODEM
JMP CTRR ;READ PHYSICAL RECORD FROM TAPE
JMP CTWR ;WRITE PHYSICAL RECORD TO TAPE
JMP MOVEUP ;MOVE BLOCK OF MEMORY TOWARDS 0000
JMP MOVEDN ;MOVE BLOCK OF MEMORY TOWARDS FFFF
JMP DMP ;DUMP BLOCK OF MEMORY IN HEX/ASCII
JMP RASC ;READ ASCII STRING FROM CONSOLE
JMP DHS ;DECODE HEX STRING
RM80: LXI SP,STACK+64
CALL INITC ;INITIALIZE CONSOLE
CALL INITM ;INITIALIZE MODEM
CALL INITT ;INITIALIZE TAPE
LXI H,0 ;CLEAR OBJECT FILE LOADER OFFSET
SHLD OFLOS
CALL WEOLC
LXI H,RM80S1 ;PRINT 'RM80 V2.0'
CALL WASC
RM801: MVI A,')' ;ISSUE PROMPT CHAR
CALL WACC
LXI H,IBUF ;READ COMMAND INTO IBUF
CALL RASC
MVI M,' ' ;INSURE AT LEAST ONE BLANK AT END
INX H
MVI M,CR
LXI D,IBUF ;PARSE COMMAND
LXI H,CBUF ;SCAN OFF KEYWORD INTO CBUF
MVI C,6 ;MAX KEYWORD SIZE
RM802: LDAX D ;FETCH NEXT CHAR FROM IBUF
INX D
CPI 61H ;IF LC, CONVERT TO UC
JC $+5
SUI 20H
CPI ' ' ;EXIT AT END-OF-KEYWORD
JZ RM803
MOV M,A ;STORE IN CBUF
INX H
DCR C ;LOOP IF 5 OR LESS CHARS SO FAR
JNZ RM802
JMP RM80X ;ELSE TAKE ERROR EXIT
RM803: INR C ;BLANK FILL REST OF CBUF
DCR C
JZ RM804
MVI M,' '
INX H
JMP RM803+1
RM804: XRA A ;CLEAR PARAMETER FLAGS
STA PFLAG1
STA PFLAG2
CALL DHS ;DECODE FIRST PARAMETER INTO HL
JC RM80X ;BRANCH ON ERROR
STA PFLAG1
SHLD PARAM1 ;SAVE FIRST PARAMETER
CALL DHS ;DECODE SECOND PARAMETER
JC RM80X ;BRANCH ON ERROR
STA PFLAG2
SHLD PARAM2 ;SAVE SECOND PARAMETER
LDA PFLAG1 ;IF NO FIRST PARAM, DEFAULT TO 100H
ORA A
JNZ $+9
LXI H,100H
SHLD PARAM1
LDA PFLAG2 ;IF NO SECOND PARAM, DEFAULT TO PARAM1
ORA A
JNZ $+9
LHLD PARAM1
SHLD PARAM2
RM805: LXI H,CTAB ;LOOKUP KEYWORD IN COMMAND TABLE
RM806: LXI D,CBUF
MVI C,5 ;NUMBER OF BYTES TO COMPARE
MVI B,1 ;SET MATCH FLAG
RM807: LDAX D ;FETCH NEXT BYTE OF KEYWORD
CMP M ;COMPARE WITH NEXT BYTE OF TABLE
JZ $+5 ;JUMP IF GOOD COMPARE
MVI B,0 ;CLEAR MATCH FLAG
INX D ;INCREMENT POINTERS
INX H
DCR C ;LOOP THRU ENTIRE KEYWORD
JNZ RM807
DCR B ;TEST MATCH FLAG
JZ RM808 ;JUMP IF GOOD MATCH
INX H ;ELSE SKIP ADDR FIELD
INX H
MOV A,M ;LOOP IF NOT END OF TABLE
ORA A
JNZ RM806
LXI H,RM80S2 ;PRINT 'ILLEGAL COMMAND'
CALL WASC
JMP RM801 ;AND LOOP
RM808: MOV E,M ;FETCH ADDR FIELD INTO DE
INX H
MOV D,M
LXI B,RM801 ;CREATE A RETURN ADDRESS
PUSH B
PUSH D ;FORCE JUMP ADDR ONTO STACK
LHLD PARAM2 ;DE = SECOND PARAMETER
XCHG
LHLD PARAM1 ;HL = FIRST PARAMETER
RET ;WOULD YOU PREFER 'POP PC'?
RM80X: LXI H,RM80S3 ;PRINT 'SYNTAX ERROR'
CALL WASC
JMP RM801 ;AND LOOP
RM80S1: DB 'RM80 V2.0',CR,LF,0
RM80S2: DB 'ILLEGAL COMMAND',CR,LF,0
RM80S3: DB 'SYNTAX ERROR',CR,LF,0
; COMMAND TABLE
CTAB: DB 'DUMP '
DW DUMP
DB 'TYPE '
DW TYPE
DB 'ENTER'
DW ENTER
DB 'TEXT '
DW TEXT
DB 'MOVE '
DW MOVE
DB 'FILL '
DW FILL
DB 'GO '
DW GO
DB 'STORE'
DW STORE
DB 'FETCH'
DW FETCH
DB 'CHECK'
DW CHECK
DB 'UNIT '
DW UNIT
DB 'WRITE'
DW WRITE
DB 'READ '
DW READ
DB 'LOAD '
DW LOAD
DB 'SCAN '
DW SCAN
DB 'LINK '
DW LINK
DB 'SOLO '
DW SOLO
DB 'IN '
DW RIP
DB 'OUT '
DW WOP
DB 0 ;END OF COMMAND TABLE
;; RIP - READ INPUT PORT (AND DISPLAY)
RIP: MVI A,0DBH ;JAM INPUT INSTRUCTION
STA TEMP+0
MOV A,L ;PORT ADDRESS
STA TEMP+1
MVI A,0C9H ;JAM RETURN INSTRUCTION
STA TEMP+2
CALL TEMP ;EXECUTE INPUT COMMAND
CALL WHBC ;WRITE BYTE IN HEX
JMP WEOLC ;EXIT VIA WEOLC
;; WOP - WRITE OUTPUT PORT
WOP: MVI A,0D3H ;JAM OUTPUT INSTRUCTION
STA TEMP+0
MOV A,L ;PORT NUMBER
STA TEMP+1
MVI A,0C9H ;JAM RETURN INSTRUCTION
STA TEMP+2
MOV A,E ;BYTE TO OUTPUT
CALL TEMP ;EXECUTE OUTPUT COMMAND
JMP WEOLC ;EXIT VIA WEOLC
;; DUMP - RM80 DUMP COMMAND
DUMP: LDA PFLAG1 ;JUMP IF NO PARAMETERS
ORA A
JZ DUMP1
CALL DIFF ;DE=DE-HL+1
INX D
SHLD DMPAD ;SET DUMP ADDRESS TO REAL FWA
JMP DMP ;PERFORM DUMP AND RETURN
DUMP1: LXI H,0 ;SET DUMP ADDRESS TO ZERO
SHLD DMPAD
DUMP2: LXI H,TBUF ;READ NEXT RECORD FROM TAPE
LXI B,NBUF
CALL CTRR
CALL WEOLC
CALL CTPH ;PRINT HEADER INFO (NAME, TYPE, ETC)
MOV A,D ;SAVE PAGE COUNT
STA CTPC
LXI H,TBUF ;DUMP RECORD
CALL DMP
LDA CTPC ;FETCH PAGE COUNT
CPI 4 ;LOOP UNLESS SHORT RECORD
JNC DUMP2
RET
;; TYPE - RM80 TYPE COMMAND
TYPE: LDA PFLAG1 ;JUMP IF NO PARAMETERS
ORA A
JZ TYPE2
CALL DIFF ;DE = DE-HL+1
INX D
TYPE1: MOV A,D ;EXIT WHEN DE=0
ORA E
JZ WEOLC
MOV A,M ;FETCH NEXT BYTE
CPI 'Z'-40H ;EXIT IF END-OF-FILE CHAR
JZ WEOLC
INX H
CALL WACC ;WRITE IT - USER ASKED FOR IT
DCX D ;DECREMENT COUNT AND LOOP
JMP TYPE1
TYPE2: LXI H,TBUF ;READ NEXT RECORD FROM TAPE
LXI B,NBUF
CALL CTRR
MOV A,D ;SAVE PAGE COUNT
STA CTPC
LXI H,TBUF ;TYPE CONTENTS OF RECORD
TYPE3: MOV A,D ;EXIT WHEN COUNT=0
ORA E
JZ TYPE4
MOV A,M ;WRITE NEXT BYTE
CPI 'Z'-40H ;EXIT IF END-OF-FILE CHAR
JZ WEOLC
INX H
CALL WACC
DCX D ;DECREMENT COUNT
JMP TYPE3
TYPE4: LDA CTPC ;FETCH PAGE COUNT
CPI 4 ;LOOP IF NOT SHORT RECORD
JNC TYPE2
JMP WEOLC ;WRITE END-OF-LINE AND RETURN
;; ENTER - RM80 ENTER COMMAND
ENTER: MOV A,H ;PROMPT WITH CURRENT LOAD ADDRESS
CALL WHBC
MOV A,L
CALL WHBC
MVI A,'?'
CALL WACC
MVI A,' '
CALL WACC
PUSH H ;SAVE LOAD ADDRESS
LXI H,IBUF ;READ INPUT LINE
CALL RASC
DCR B ;EXIT ON EMPTY LINE
JZ ENTER3
LXI D,IBUF ;DECODE AND LOAD BYTES ON THIS LINE
ENTER1: CALL DHS ;DECODE NEXT BYTE
JC ENTERX
ORA A ;EXIT AT END OF LINE
JZ ENTER2
MOV A,L
POP H ;RESTORE LOAD ADDRESS
MOV M,A ;LOAD BYTE INTO MEMORY
INX H ;INCREMENT LOAD ADDRESS
PUSH H ;SAVE LOAD ADDRESS AWAY AGAIN
JMP ENTER1 ;LOOP
ENTER2: POP H ;RESTORE LOAD ADDRESS
JMP ENTER ;AND GO ON WITH NEXT LINE
ENTER3: POP H ;CLEAR STACK AND EXIT
JMP WEOLC
ENTERX: POP H
LXI H,ENTERS1
JMP WASC
ENTERS1: DB 'ERROR',CR,LF,0
;; TEXT - RM80 TEXT COMMAND
TEXT: PUSH H ;SAVE LOAD ADDRESS
MOV A,H ;PROMPT WITH CURRENT LOAD ADDRESS
CALL WHBC
MOV A,L
CALL WHBC
MVI A,'?'
CALL WACC
MVI A,' '
CALL WACC
LXI H,IBUF
CALL RASC ;READ NEXT LINE FROM CONSOLE
DCR B ;EXIT ON EMPTY LINE (JUST CR)
JZ TEXT2
INR B
POP H ;RESTORE LOAD ADDRESS
LXI D,IBUF ;STORE LINE IN MEMORY
TEXT1: LDAX D ;FETCH NEXT CHAR FROM IBUF
INX D
MOV M,A ;STORE IN MEMORY
INX H
DCR B ;DECREMENT COUNT
JNZ TEXT1 ;LOOP UNTIL END-OF-LINE
MVI M,LF ;STORE A LINE FEED AFTER CR
INX H
JMP TEXT ;LOOP
TEXT2: POP H ;CLEAR STACK AND RETURN
RET
;; MOVE - RM80 MOVE COMMAND
MOVE: CALL DIFF ;DE = DE-HL+1
INX D
PUSH D
PUSH H
LXI H,MOVES1 ;PRINT 'TO?'
CALL WASC
LXI H,IBUF ;READ RESPONSE
CALL RASC
LXI D,IBUF ;DECODE VALUE
CALL DHS
JNC MOVE0 ;JUMP IF NO ERRORS
POP H
POP D
JMP PERR
MOVE0: XCHG ;DE = BC = FWA DEST.
MOV B,D
MOV C,E
POP H ;HL = FWA SOURCE
CALL DIFF ;DE = FWA DEST - FWA SOURCE
POP D ;DE = SOURCE SIZE
JNC MOVEDN ;FWA DEST > FWA SOURCE
JMP MOVEUP ;FWA DEST < FWA SOURCE
MOVES1: DB 'TO? ',0
;; FILL - RM80 FILL COMMAND
FILL: CALL DIFF
INX D
PUSH H
PUSH D
LXI H,FILLS1 ;PRINT 'WITH? '
CALL WASC
LXI H,IBUF ;READ ANSWER
CALL RASC
LXI D,IBUF ;DECODE IT
CALL DHS
JNC FILL0 ;JUMP IF OK
POP D ;ELSE CLEAR STACK AND TAKE ERROR EXIT
POP H
JMP PERR
FILL0: MOV B,L ;B = FILL BYTE
POP D
POP H
FILL1: MOV A,D ;RETURN WHEN COUNT=0
ORA E
RZ
MOV M,B ;STORE FILL BYTE
INX H
DCX D ;DECREMENT COUNT AND LOOP
JMP FILL1
FILLS1: DB 'WITH? ',0
;; GO - RM80 GO COMMAND
GO: PCHL ;SHUFFLE OFF TO PARAM1
;; STORE - RM80 STORE COMMAND
STORE: CALL DIFF ;DE = DE-HL+1
INX D
LDA TUNIT ;TURN ON MOTOR
OUT CASSTA
MVI B,15 ;WAIT 1.5 SECONDS
CALL WTS
MVI A,3CH ;WRITE START BYTE
CALL CTWBX
MVI A,0E6H ;WRITE SYNC BYTE
CALL CTWBX
MVI B,0 ;CLEAR CHECKSUM
STORE1: MOV A,M ;FETCH NEXT BYTE
INX H
CALL CTWBX ;WRITE IT
DCX D ;DECREMENT COUNT
MOV A,D ;LOOP UNTIL COUNT=0
ORA E
JNZ STORE1
MOV A,B ;WRITE CHECKSUM
CALL CTWBX
MVI B,5 ;WAIT 0.5 SECONDS
CALL WTS
XRA A ;TURN OFF MOTOR
OUT CASSTA
RET
CTWBX: PUSH PSW ;AWAIT TBE (INVERTED)
IN CASSTA
ANI CASTBE
JNZ $-4
POP PSW
OUT CASDAT ;WRITE BYTE
CMA ;DISPLAY ON LIGHTS
OUT 0FFH
CMA
PUSH PSW ;ADD BYTE INTO CHECKSUM
ADD B
MOV B,A
POP PSW
RET
;; FETCH - RM80 FETCH COMMAND
FETCH: CALL DIFF ;DE = DE-HL+1
INX D
LDA TUNIT ;TURN ON MOTOR AND ENTER HUNT MODE
ORI CASEHM
OUT CASSTA
MVI B,0 ;CLEAR CHECKSUM
FETCH1: CALL CTRBX ;READ NEXT BYTE
MOV M,A ;STORE IT
INX H
DCX D ;DECREMENT COUNT
MOV A,D ;LOOP UNTIL COUNT=0
ORA E
JNZ FETCH1
FETCH2: MOV C,B ;SAVE NEW CHECKSUM
CALL CTRBX ;READ OLD ONE
MOV B,A
XRA A ;TURN OFF MOTOR
OUT CASSTA
MOV A,B ;RETURN IF CHECKSUMS COMPARE GOOD
CMP C
RZ
LXI H,FETCHS1 ;ELSE PRINT 'CHECKSUM ERROR'
JMP WASC
FETCHS1: DB 'CHECKSUM ERROR',CR,LF,0
CTRBX: IN CASSTA ;AWAIT RDA (INVERTED)
ANI CASRDA
JNZ $-4
IN CASDAT ;READ BYTE
CMA ;DISPLAY ON LIGHTS
OUT 0FFH
CMA
PUSH PSW ;ADD BYTE INTO CHECKSUM
ADD B
MOV B,A
POP PSW
RET
;; CHECK - RM80 CHECK COMMAND
CHECK: CALL DIFF ;DE = DE-HL+1
INX D
LDA TUNIT ;TURN ON MOTOR AND ENTER HUNT MODE
ORI CASEHM
OUT CASSTA
MVI B,0 ;CLEAR CHECKSUM
CHECK1: CALL CTRBX ;READ NEXT BYTE
DCX D ;DECREMENT COUNT
MOV A,D ;LOOP UNTIL COUNT=0
ORA E
JNZ CHECK1
JMP FETCH2 ;REST IS SAME AS FETCH
;; UNIT - RM80 UNIT COMMAND
UNIT: MOV A,L
STA TUNIT
RET
;; SCAN - RM80 SCAN COMMAND
SCAN: LXI H,TBUF ;READ NEXT RECORD
LXI B,NBUF
CALL CTRR
CALL CTPH ;PRINT HEADER INFO
MOV A,D ;IF END-OF-FILE, SKIP ONE LINE
CPI 4
CC WEOLC
JMP SCAN ;LOOP (EXIT VIA CONSOLE BREAKIN)
;; WRITE - RM80 WRITE COMMAND
WRITE: LDA PFLAG1 ;JUMP IF 1ST PARAM ABSENT
ORA A
RZ
LDA PFLAG2 ;JUMP IF 2ND PARAM PRESNT
ORA A
JNZ WRITE1
MOV D,L ;DE = (PARAM1+1)*256-1 = LWA
INR D
MVI E,0
DCX D
LXI H,100H ;SET DEFAULT FWA
WRITE1: CALL DIFF ;DE = DE-HL+1 = FILE SIZE
INX D
PUSH D
XRA A ;PRN = 0
STA PRN
CALL GFNC ;GET CP/M FILE NAME FROM CONSOLE
WRITE2: MOV A,D ;JUMP IF LESS THAN ONE PRU LEFT
CPI 4
JC WRITE3
PUSH D ;SAVE FILE SIZE
LXI D,400H ;SET PHYS REC SIZE
LXI B,NBUF ;POINT TO NAME BUFFER
CALL CTWR ;WRITE FULL PRU
POP D ;RESTORE FILE SIZE
MOV A,D ;DE = DE - 400H
SUI 4
MOV D,A
JMP WRITE2
WRITE3: LXI B,NBUF ;POINT TO NAME BUFFER
CALL CTWR ;WRITE LAST PRU (SHORT)
POP D ;RESTORE FILE SIZE
MOV A,D ;PRINT FILE SIZE IN HEX
CALL WHBC
MOV A,E
CALL WHBC
LXI H,WRITES1 ;PRINT 'BYTES WRITTEN' AND EXIT
JMP WASC
WRITES1: DB ' BYTES WRITTEN',CR,LF,0
;; READ - RM80 READ COMMAND
READ: PUSH H
READ1: LXI H,TBUF ;READ NEXT RECORD
LXI B,NBUF
CALL CTRR
CALL CTPH
MOV A,D ;SAVE PAGE COUNT
STA CTPC
LXI H,TBUF
READ2: MOV A,D ;EXIT WHEN COUNT = 0
ORA E
JZ READ4
MOV A,M ;FETCH NEXT BYTE FROM TBUF
INX H
XTHL
MOV M,A ;STORE AT LOAD ADDRESS
INX H ;INCREMENT LOAD ADDRESS
XTHL
DCX D ;DECREMENT COUNT
JMP READ2
READ4: LDA CTPC ;FETCH PAGE COUNT
CPI 4 ;LOOP IF NOT SHORT RECORD
JNC READ1
POP H ;CLEAR STACK
RET
;; LOAD - RM80 LOAD COMMAND
LOAD: XRA A ;INIT OBJECT FILE LOADER
STA OFLST
STA OFLCE
STA LDERR ;CLEAR LOADER ERROR COUNT
LOAD1: LXI H,TBUF
LXI B,NBUF
CALL CTRR ;READ NEXT RECORD
CALL CTPH
MOV A,D ;SAVE PAGE COUNT
STA CTPC
LXI H,TBUF
LOAD2: MOV A,D ;EXIT WHEN COUNT=0
ORA E
JZ LOAD4
MOV A,M ;FETCH NEXT BYTE
INX H
CALL OFL ;INVOKE OBJECT FILE LOADER ON BYTE
LDA OFLCE ;JUMP IF NO CHECKSUM ERROR
ORA A
JZ LOAD3
LDA LDERR ;INCREMENT LOADER ERROR COUNT
INR A
STA LDERR
XRA A ;RESET CHECKSUM ERROR FLAG
STA OFLCE
LOAD3: DCX D ;DECREMENT COUNT AND LOOP
JMP LOAD2
LOAD4: LDA CTPC ;FETCH PAGE COUNT
CPI 4 ;LOOP IF NOT SHORT RECORD
JNC LOAD1
LXI H,LOADS1 ;PRINT 'ERROR COUNT = '
CALL WASC
LDA LDERR ;PRINT ERROR COUNT
CALL WHBC
JMP WEOLC ;EXIT VIA WEOLC
LOADS1: DB 'ERROR COUNT = ',0
;; LINK - RM80 LINK COMMAND
LINK: XRA A ;CLEAR CHAR BUFFERS
STA INCH
STA OUTCH
STA OFLSW ;START WITH OBJECT FILE LOADER OFF
STA TFLSW ;START WITH TEXT FILE LOADER OFF
SHLD TFLFWA ;SET FWA FOR TEXT FILE LOADER
SHLD TFLLWA ;SET LWA FOR TEXT FILE LOADER
LINK1: CALL CRDAC ;ANYTHING FROM CONSOLE?
JNC LINK2 ;JUMP IF NOT
CALL RACC ;ELSE READ CHAR FROM CONSOLE
CPI 20H ;IF CONTROL CODE TYPED, CALL PCC
CC PCC
JC LINK2 ;JUMP IF CODE PROCESSED
ORI 80H ;SAVE IT AWAY FOR LATER
STA OUTCH
LINK2: CALL CTBEC ;CONSOLE READY FOR DATA?
JNC LINK3 ;JUMP IF NOT
LDA INCH ;DO WE GOT ANY GOODIES FOR IT?
ORA A
JP LINK3 ;JUMP IF NOT
ANI 7FH ;ELSE WRITE CHAR TO CONSOLE
CALL WACC
XRA A ;CLEAR INPUT CHAR BUFFER
STA INCH
LINK3: CALL CRDAM ;ANYTHING FROM MODEM?
JNC LINK4 ;JUMP IF NOT
CALL RACM ;ELSE READ CHAR FROM MODEM
MOV B,A ;IF OFL ENABLED, CALL OFL
LDA OFLSW
ORA A
MOV A,B
JZ $+12
PUSH PSW
CALL OFL
POP PSW
CMA
OUT 0FFH
CMA
MOV B,A ;IF TFL ENABLED, CALL TFL
LDA TFLSW
ORA A
MOV A,B
JZ $+10
CALL TFL
CMA
OUT 0FFH
CMA
ORI 80H ;SAVE IT AWAY FOR LATER
STA INCH
LINK4: CALL CTBEM ;MODEM READY FOR MORE DATA?
JNC LINK5 ;JUMP IF NOT
LDA OUTCH ;DO WE GOT ANY GOODIES FOR IT
ORA A
JP LINK5 ;JUMP IF NOT
ANI 7FH ;ELSE WRITE CHAR TO MODEM
CALL WACM
XRA A ;CLEAR OUTPUT CHAR BUFFER
STA OUTCH
LINK5: JMP LINK1 ;LOOP
PCC: CPI 'X'-40H ;JUMP IF NOT CONTROL-X
JNZ PCC1
POP H ;CLEAR STACK AND EXIT
JMP WEOLC
PCC1: CPI 'O'-40H ;JUMP IF NOT CTRL-O
JNZ PCC2
MVI A,1 ;ENABLE OBJECT FILE LOADER
STA OFLSW
STC
RET
PCC2: CPI 'N'-40H ;JUMP IF NOT CTRL-N
JNZ PCC3
XRA A ;DISABLE OBJECT FILE LOADER
STA OFLSW
STC
RET
PCC3: CPI 'R'-40H ;JUMP IF NOT CTRL-R
JNZ PCC4
MVI A,1 ;ENABLE TEXT FILE LOADER
STA TFLSW
STC
RET
PCC4: CPI 'Q'-40H ;JUMP IF NOT CTRL-Q
JNZ PCC5
XRA A ;DISABLE TEXT FILE LOADER
STA TFLSW
LHLD TFLLWA ;WRITE MEMORY BUFFER TO TAPE
DCX H
XCHG
LHLD TFLFWA
CALL WRITE1
STC
RET
PCC5: CPI 'S'-40H ;JUMP IF NOT CTRL-S
JNZ PCC6
JMP TFS ;SEND TEXT FILE (FROM TAPE)
PCC6: STC ;FESS UP THAT WE DON'T KNOW BOUT THIS ONE
CMC
RET
TFL: ORA A ;IGNORE NULLS
RZ
PUSH H
LHLD TFLLWA
MOV M,A
INX H
SHLD TFLLWA
POP H
RET
TFS: LXI H,TBUF ;READ NEXT RECORD
LXI B,NBUF
CALL CTRR
MOV A,D
STA CTPC
LXI H,TBUF
TFS1: MOV A,D ;EXIT WHEN COUNT=0
ORA E
JZ TFS3
MOV A,M ;FETCH NEXT CHARACTER
INX H
CPI 'Z'-40H ;EXIT IF CNTRL-Z
JZ TFS4
ORA A
JZ TFS2
CPI LF ;DO NOT SEND LINE FEEDS
JZ TFS2
CALL WACM ;WRITE CHAR TO MODEM
CALL WACC ;WRITE CHAR TO CONSOLE
CPI CR ;JUMP IF NOT CR
JNZ TFS2
CALL RACM ;AWAIT LINE FEED
CPI LF
JNZ $-5
CALL WACC ;ECHO LINE FEED TO CONSOLE
TFS2: CALL CRDAC ;CHECK FOR CONSOLE BREAKIN
JNC $+11 ;JUMP IF NOT PRESENT
CALL RACC ;READ CHARACTER
CPI 'T'-40H ;EXIT IF CTRL-T
JZ TFS4
DCX D ;DECREMENT COUNT AND LOOP
JMP TFS1
TFS3: LDA CTPC ;FETCH PAGE COUNT
CPI 4 ;LOOP IF NOT SHORT RECORD
JNC TFS
TFS4: CALL WEOLC
STC
RET
;; SOLO - RM80 SOLO COMMAND
SOLO: SHLD OFLOS
RET
;;; GENERAL PURPOSE UTILITIES
;
; LAWRENCE E. HUGHES III
; 8080 SOFTWARE DEVELOPMENT CENTER
; 1506 MYRICK ROAD
; TALLAHASSEE, FLORIDA 32303
;; MOVEUP - MOVE BLOCK OF MEMORY TOWARDS ZERO
;
; ENTRY CONDITIONS
; HL........FWA OF SOURCE
; BC........FWA OF DEST
; DE........NUMBER OF BYTES TO MOVE
MOVEUP: MOV A,D
ORA E
RZ
MOV A,M
INX H
STAX B
INX B
DCX D
JMP MOVEUP
;; MOVEDN - MOVE BLOCK OF MEMORY TOWARDS FFFF
;
; ENTRY CONDITIONS
; HL........FWA OF SOURCE
; BC........FWA OF DEST
; DE........NUMBER OF BYTES TO MOVE
MOVEDN: DAD D
MOV A,C
ADD E
MOV C,A
MOV A,B
ADC D
MOV B,A
MOVEDN1: MOV A,D
ORA E
RZ
DCX H
MOV A,M
DCX B
STAX B
DCX D
JMP MOVEDN1
;; PERR - PRINT 'ERROR'
PERR: LXI H,PERRS1
JMP WASC
PERRS1: DB 'ERROR',CR,LF,0
;; DIFF - DE = DE - HL
DIFF: MOV A,E
SUB L
MOV E,A
MOV A,D
SBB H
MOV D,A
RET
;; GFNC - GET FILE NAME FROM CONSOLE
GFNC: PUSH H
PUSH D
CALL WEOLC
LXI H,GFNS1 ;PRINT 'FILENAME?'
CALL WASC
LXI H,IBUF ;READ RESPONSE INTO IBUF
CALL RASC
LXI D,IBUF ;DECODE FILE NAME INTO NBUF
LXI H,NBUF
CALL DFN
POP D
POP H
RET
GFNS1: DB 'FILENAME? ',0
;; DFN - DECODE FILE NAME (CP/M FORMAT)
;
; ENTRY CONDITIONS
; DE........FWA OF STRING TO DECODE
; HL........FWA OF BUFFER TO ACCEPT DECODED FILENAME
;
; EXIT CONDITIONS
; C-FLAG....SET IFF ERRORS OCCURRED (FIELD TOO LONG)
DFN: MVI C,9 ;DECODE NAME FIELD
DFN1: LDAX D ;FETCH NEXT BYTE FROM STRING
INX D
CPI 61H ;IF LC, CONVERT TO UC
JC $+5
SUI 20H
CPI CR ;JUMP IF END OF STRING
JZ DFN2
CPI ' ' ;JUMP IF END OF FIELD
JZ DFN2
CPI '.' ;JUMP IF END OF NAME
JZ DFN2
DCR C ;EXIT IF NAME TOO LONG
JZ DFNX
MOV M,A ;STORE BYTE IN NAME FIELD OF BUFFER
INX H
JMP DFN1 ;LOOP
DFN2: DCR C ;BLANK FILL REST OF NAME FIELD OF BUFFER
JZ DFN3
MVI M,' '
INX H
JMP DFN2
DFN3: MVI C,4
CPI '.' ;JUMP IF NO TYPE FIELD IN STRING
JNZ DFN5
DFN4: LDAX D ;FETCH NEXT BYTE FROM STRING
INX D
CPI 61H ;IF LC, CONVERT TO UC
JC $+5
SUI 20H
CPI CR ;JUMP IF END OF STRING
JZ DFN5
CPI ' ' ;JUMP IF END OF FIELD
JZ DFN5
DCR C ;EXIT IF TYPE TOO LONG
JZ DFNX
MOV M,A ;STORE BYTE IN TYPE FIELD OF BUFFER
INX H
JMP DFN4 ;LOOP
DFN5: DCR C ;BLANK FILL REST OF TYPE FIELD OF BUFFER
JZ DFN6
MVI M,' '
INX H
JMP DFN5
DFN6: STC ;NORMAL EXIT
CMC
RET
DFNX: STC ;ERROR EXIT
RET
;; OFL - INTEL HEX OBJECT FILE LOADER (FINITE STATE MACHINE)
;
; ENTRY CONDITIONS
; A.........OBJECT FILE BYTE
; OFLST.....STATE COUNTER (INIT BY USER TO ZERO)
; OFLLA.....LOAD ADDRESS
; OFLBC.....BYTE COUNT
; OFLCS.....CHECKSUM
; OFLCE.....CHECKSUM ERROR - INIT BY USER TO ZERO
; SET NON-ZERO IF ERROR OCCURS, MUST BE
; RE-CLEARED TO ZERO BY USER
OFL: PUSH PSW
LDA OFLST ;JUMP IF STATE >= 1
CPI 1
JNC OFL1
POP PSW
CPI ':' ;IGNORE ALL CHARS UNTIL COLON FOUND
RNZ
MVI A,1 ;ADVANCE TO STATE 1
STA OFLST
XRA A ;CLEAR CHECKSUM
STA OFLCS
RET
OFL1: CPI 2 ;JUMP IF STATE >= 2
JNC OFL2
INR A
STA OFLST
CALL OFLCB ;CLEAR BYTE BUFFER
POP PSW
JMP OFLAD ;ACCUM. 1ST DIGIT OF BYTE COUNT
OFL2: CPI 3 ;JUMP IF STATE >= 3
JNC OFL3
INR A
STA OFLST
POP PSW
CALL OFLAD ;ACCUM. 2ND DIGIT OF BYTE COUNT
STA OFLBC ;SAVE RESULT AS BYTE COUNT
JMP OFLUC ;ADD RESULT INTO CHECKSUM
OFL3: CPI 4 ;JUMP IF STATE >= 4
JNC OFL4
INR A
STA OFLST
CALL OFLCB ;CLEAR BYTE BUFFER
POP PSW
JMP OFLAD ;ACCUM. 1ST DIGIT OF HI ADDR
OFL4: CPI 5 ;JUMP IF STATE >= 5
JNC OFL5
INR A
STA OFLST
POP PSW
CALL OFLAD ;ACCUM 2ND DIGIT OF HI ADDR
STA OFLLA+1 ;SAVE HI BYTE OF LOAD ADDRESS
JMP OFLUC ;ADD RESULT INTO CHECKSUM
OFL5: CPI 6 ;JUMP IF STATE >= 6
JNC OFL6
INR A
STA OFLST
CALL OFLCB ;CLEAR BYTE BUFFER
POP PSW ;ACCUM. 1ST DIGIT OF LO ADDR
JMP OFLAD
OFL6: CPI 7 ;JUMP IF STATE >= 7
JNC OFL7
INR A
STA OFLST
POP PSW
CALL OFLAD ;ACCUM. 2ND DIGIT OF LO ADDR
STA OFLLA ;SAVE LO BYTE OF LOAD ADDRESS
PUSH H
PUSH D
LHLD OFLLA ;ADD IN OFFSET
XCHG
LHLD OFLOS
DAD D
SHLD OFLLA
POP D
POP H
JMP OFLUC ;ADD RESULT INTO CHECKSUM
OFL7: CPI 9 ;JUMP IF STATE >= 9
JNC OFL8
INR A
STA OFLST
POP PSW ;IGNORE NEXT DIGIT OF REC TYPE
RET
OFL8: CPI 10 ;JUMP IF STATE >= 10
JNC OFL10
INR A
STA OFLST
LDA OFLBC ;EXIT IF BYTE COUNT = 0
ORA A
JZ OFL9
CALL OFLCB ;CLEAR BYTE BUFFER
POP PSW
JMP OFLAD ;ACCUM. 1ST DIGIT OF NEXT DATA BYTE
OFL9: MVI A,11 ;SET STATE TO 12 (ALL DATA BYTES READ)
STA OFLST
JMP OFL11
OFL10: CPI 11 ;JUMP IF STATE >= 11
JNC OFL11
DCR A
STA OFLST
POP PSW
CALL OFLAD ;ACCUM. 2ND DIGIT OF NEXT DATA BYTE
PUSH H ;LOAD BYTE AT LOAD ADDRESS
LHLD OFLLA
MOV M,A
INX H ;INCREMENT LOAD ADDRESS
SHLD OFLLA
POP H
CALL OFLUC ;ADD BYTE INTO CHECKSUM
LDA OFLBC ;DECREMENT BYTE COUNT
DCR A
STA OFLBC
RET
OFL11: CPI 12 ;JUMP IF STATE >= 12
JNC OFL12
INR A
STA OFLST
CALL OFLCB ;CLEAR BYTE BUFFER
POP PSW
JMP OFLAD ;ACCUM. 1ST DIGIT OF CHECKSUM
OFL12: POP PSW
CALL OFLAD ;ACCUM. 2ND DIGIT OF CHECKSUM
CALL OFLUC ;ADD INTO NEW CHECKSUM (SHOULD YIELD ZERO)
STA OFLCE ;STORE RESULT AS CHECKSUM ERROR FLAG
XRA A ;RETURN TO STATE ZERO
STA OFLST
RET
;; OFLCB - CLEAR BYTE BUFFER
OFLCB: XRA A
STA OFLBB
RET
;; OFLAD - ACCUMULATE (HEX) DIGIT
OFLAD: SUI '0' ;SUBTRACT ASCII BIAS
CPI 10 ;JUMP IF 0-9
JC $+5
SUI 7 ;ADJUST A-F
PUSH B
MOV B,A
LDA OFLBB ;FETCH BYTE BUFFER
ADD A ;MULTIPLY BY 16
ADD A
ADD A
ADD A
ADD B ;ADD IN NEW DIGIT
STA OFLBB ;REPLACE RESULT
POP B
RET
; OFLUC - UPDATE CHECKSUM
OFLUC: PUSH H
LXI H,OFLCS ;POINT TO CHECKSUM
ADD M ;ADD IN NEW BYTE
MOV M,A
POP H
RET
;; DMP - DUMP MEMORY IN HEX AND ASCII TO CONSOLE
;
; ENTRY CONDITIONS
; HL........FWA OF BLOCK TO DUMP
; DE........NUMBER OF BYTES TO DUMP
; DMPAD.....ADDR PRINTED AT START OF EACH LINE,
; INIT BY USER, INCREMENTED BY DMP
DMP: MOV A,D ;EXIT VIA WEOLC IF DE=0
ORA E
JZ WEOLC
CALL CRDAC ;CHECK FOR CONSOLE RDA
JNC DMP0 ;IF NO RDA, JUMP
CALL RACC ;ELSE DISCARD CHAR TYPED
JMP WEOLC ;AND EXIT VIA WEOLC
DMP0: CALL WEOLC ;START NEW LINE
LDA DMPAD+1 ;WRITE DUMP ADDR IN HEX
CALL WHBC
LDA DMPAD
CALL WHBC
PUSH H ;SAVE FWA
PUSH D ;SAVE BYTE COUNT
MVI C,16 ;NUMBER OF BYTES PER LINE
DMP1: MOV A,D ;JUMP IF DONE
ORA E
JZ DMP2
MVI A,' ' ;PRINT 1 BLANK
CALL WACC
MOV A,M ;FETCH NEXT BYTE
INX H
CALL WHBC ;WRITE TO CONSOLE IN HEX
PUSH H ;DMPAD = DMPAD + 1
LHLD DMPAD
INX H
SHLD DMPAD
POP H
DCX D ;DECREMENT COUNT
DCR C ;CONTINUE UNTIL 16 BYTES DUMPED
JNZ DMP1
JMP DMP3 ;GO DUMP BYTES IN ASCII
DMP2: INR C ;EXIT WHEN C=0
DCR C
JZ DMP3
MVI A,' ' ;PRINT 3 SPACES
CALL WACC
CALL WACC
CALL WACC
JMP DMP2+1 ;CONTINUE
DMP3: POP D ;RESTORE BYTE COUNT
POP H ;RESTORE POINTER
MVI A,' ' ;PRINT 2 SPACES
CALL WACC
CALL WACC
MVI C,16 ;NUMBER OF BYTES PER LINE
DMP4: MOV A,D ;EXIT VIA WEOLC IF DONE
ORA E
JZ WEOLC
MOV A,M ;FETCH NEXT BYTE
INX H
ANI 7FH ;DISCARD PARITY BIT
CPI 20H ;SUBSTITUTE PERIOD FOR CTRL CHARS
JNC $+5
MVI A,'.'
CPI 7FH
JC $+5
MVI A,'.'
CALL WACC ;PRINT BYTE IN ASCII
DCX D ;DECREMENT COUNT
DCR C ;CONTINUE UNTIL C = 0
JNZ DMP4
JMP DMP ;PROCEED TO NEXT LINE
;; WHBC - WRITE HEX BYTE TO CONSOLE
;
; ENTRY CONDITIONS
; A.........BYTE TO WRITE IN HEX
WHBC: PUSH PSW ;PRINT FIRST DIGIT
RRC
RRC
RRC
RRC
CALL WHDC
POP PSW ;PRINT SECOND DIGIT
PUSH PSW
CALL WHDC
POP PSW
RET
;; WHDC - WRITE HEX DIGIT TO CONSOLE
;
; ENTRY CONDITIONS
; A.........BITS 3-0 CONTAIN BINARY VALUE OF DIGIT
WHDC: ANI 0FH ;DISCARD TOP 4 BITS
CPI 10 ;ADJUST 10-15
JC $+5
ADI 7
ADI '0' ;CONVERT TO ASCII
JMP WACC ;GO PRINT DIGIT AND RETURN
;; WEOLC - WRITE END OF LINE TO CONSOLE
WEOLC: PUSH PSW
MVI A,CR
CALL WACC
MVI A,LF
CALL WACC
POP PSW
RET
;; WASC - WRITE ASCII STRING TO CONSOLE
;
; ENTRY CONDITIONS
; HL........FWA OF STRING, TERMINATED BY ZERO BYTE
WASC: MOV A,M ;FETCH NEXT BYTE IN STRING
INX H
ORA A ;RETURN IF END-OF-STRING
RZ
CALL WACC ;PRINT CHAR
JMP WASC
;; WASCX - WRITE ASCII STRING TO CONSOLE
;
; ENTRY CONDITIONS
; HL........FWA OF STRING
; B.........NUMBER OF CHARS TO WRITE
WASCX: INR B
DCR B
RZ
MOV A,M
INX H
CALL WACC
JMP WASCX+1
;; RASC - READ ASCII STRING FROM CONSOLE
;
; ENTRY CONDITIONS
; HL........FWA OF 128 BYTE BUFFER TO READ INTO
;
; EXIT CONDITIONS
; HL........POINTS TO LAST CHAR STORED (CR)
; B.........NUMBER OF BYTES STORED
RASC: PUSH H ;SAVE BUFFER POINTER
MVI B,0 ;COUNT = 0
RASC1: CALL RACC ;READ NEXT CHAR FROM CONSOLE
CPI 'U'-40H ;JUMP IF NOT CTRL-U
JNZ RASC2
CALL WEOLC ;ABORT OLD LINE
POP H ;RESTORE BUFFER POINTER
JMP RASC ;START OVER
RASC2: CPI BS
JZ RASC25
CPI DEL
JNZ RASC3
RASC25: INR B
DCR B
JZ RASC1
DCX H ;DELETE CHAR
DCR B
MVI A,BS
CALL WACC
JMP RASC1
RASC3: MOV M,A ;STORE CHAR IN BUFFER
INR B ;INCREMENT COUNT
MOV A,B ;JUMP IF STILL ROOM IN BUFFER
ORA A
JP RASC4
MVI M,CR ;FORCE A CR INTO LAST BYTE OF BUFFER
POP H ;RESTORE BUFFER POINTER
RET
RASC4: MOV A,M ;FETCH CHAR BACK INTO A
CPI CR ;EXIT IF CHAR = CR
JZ RASC5
INX H ;NOW INCREMENT BUFFER POINTER
CALL WACC ;ECHO CHAR TO CONSOLE AND LOOP
JMP RASC1
RASC5: INX SP ;CLEAR TOP OF STACK
INX SP
JMP WEOLC
;; DHS - DECODE HEX STRING (TERM. BY BLANK OR CR)
;
; ENTRY CONDITIONS
; DE........FWA OF STRING TO DECODE
;
; EXIT CONDITIONS
; HL........VALUE OF HEX STRING
; A.........NUMBER OF LEGAL DIGITS FOUND
; DE........POINTS TO LAST CHAR SCANNED
; C-FLAG....SET IFF ERRORS
DHS: LXI H,0 ;HL = 0
PUSH B
MVI B,0 ;CLEAR 'DIGITS FOUND' COUNT
DHS1: LDAX D ;SKIP LEADING BLANKS, IF ANY
CPI CR ;CHECK FOR END-OF-LINE
JZ DHS5
INX D
CPI ' '
JZ DHS1
DHS2: DAD H ;HL = HL * 16
DAD H
DAD H
DAD H
CPI 61H ;IF LC, CONVERT TO UC
JC $+5
SUI 20H
SUI '0' ;CONVERT TO BINARY
JC DHSX
CPI 10 ;JUMP IF DIGIT < 10
JC $+5
SUI 7 ;ADJUST FOR A-F
CPI 16
JNC DHSX
ADD L ;HL = HL + NEW DIGIT
MOV L,A
JNC $+4
INR H
INR B ;INCREMENT 'DIGITS FOUND' COUNT
LDAX D
CPI CR
JZ DHS5
CPI ' '
JZ DHS5
INX D
JMP DHS2
DHS5: LDAX D ;NORMAL EXIT
MOV A,B
POP B
STC
CMC
RET
DHSX: DCX D ;ERROR EXIT
LDAX D
POP B
STC
RET
;;; CONSOLE DRIVER (IMSAI SIO-2 PORT A)
;
; LAWRENCE E. HUGHES III
; 8080 SOFTWARE DEVELOPMENT CENTER
; 1506 MYRICK ROAD
; TALLAHASSEE, FLORIDA 32303
CONDAT EQU 12H ;DATA PORT
CONSTA EQU 13H ;STATUS PORT
CONRDA EQU 02H ;READ-DATA-AVAILABLE MASK
CONTBE EQU 01H ;TRANSMIT-BUFFER-EMPTY MASK
;; RACC - READ ASCII CHAR FROM CONSOLE
;
; EXIT CONDITIONS
; A.........7-BIT ASCII CHARACTER (D7=0)
RACC: CALL CRDAC ;LOOP UNTIL CONSOLE RDA OCCURS
JNC $-3
IN CONDAT ;READ DATA BYTE
ANI 7FH ;CLEAR TOP BIT
RET
;; CRDAC - CHECK FOR RDA ON CONSOLE
;
; EXIT CONDITIONS
; C-FLAG....SET IFF RDA OCCURED
CRDAC: IN CONSTA ;READ STATUS PORT
ANI CONRDA ;MASK OFF RDA FLAG
JZ $+5 ;JUMP IF NOT PRESENT
STC ;ELSE SET CARRY AND RETURN
RET
STC ;CLEAR CARRY AND RETURN
CMC
RET
;; WACC - WRITE ASCII CHARACTER TO CONSOLE
;
; ENTRY CONDITIONS
; A.........ASCII CHARACTER TO WRITE
WACC: PUSH PSW ;SAVE CHAR
CALL CTBEC ;LOOP UNTIL CONSOLE TBE OCCURS
JNC $-3
POP PSW ;RESTORE CHAR
OUT CONDAT ;WRITE CHAR AND RETURN
RET
;; CTBEC - CHECK FOR TBE ON CONSOLE
;
; EXIT CONDITIONS
; C-FLAG...SET IF TBE OCCURRED
CTBEC: IN CONSTA ;READ STATUS PORT
ANI CONTBE ;MASK OFF TBE FLAG
JZ $+5 ;JUMP IF NOT PRESENT
STC ;ELSE SET CARRY AND RETURN
RET
STC ;CLEAR CARRY AND RETURN
CMC
RET
;; INITC - INITIALIZE CONSOLE PORT
INITC: XRA A ;CLEAR USART
OUT CONSTA
OUT CONSTA
OUT CONSTA
MVI A,40H ;DO AN INTERNAL RESET
OUT CONSTA
MVI A,6EH ;SELECT ASYNC, ETC
OUT CONSTA
MVI A,27H ;ISSUE CTS, DSR, ENABLE RX AND TX
OUT CONSTA
IN CONDAT ;CLEAR READ BUFFERS IN CHIP
IN CONDAT
RET
;;; MODEM DRIVER (IMSAI SIO-2 PORT B)
;
; LAWRENCE E. HUGHES III
; 8080 SOFTWARE DEVELOPMENT CENTER
; 1506 MYRICK ROAD
; TALLAHASSEE, FLORIDA 32303
MODDAT EQU 14H ;DATA PORT
MODSTA EQU 15H ;STATUS PORT
MODRDA EQU 02H ;READ-DATA AVAILABLE MASK
MODTBE EQU 01H ;TRANSMIT-BUFFER-EMPTY MASK
;; RACM - READ ASCII CHAR FROM MODEM
;
; EXIT CONDITIONS
; A.........7-BIT ASCII CHARACTER (D7 = 0)
RACM: CALL CRDAM ;LOOP UNTIL MODEM RDA OCCURS
JNC $-3
IN MODDAT ;READ DATA BYTE
ANI 7FH ;CLEAR TOP BIT
RET
;; CRDAM - CHECK FOR RDA ON MODEM
;
; EXIT CONDITIONS
; C-FLAG....SET IFF RDA OCCURRED
CRDAM: IN MODSTA ;READ STATUS PORT
ANI MODRDA ;MASK IFF RDA FLAG
JZ $+5 ;JUMP IF NOT PRESENT
STC ;ELSE SET CARRY FLAG AND RETURN
RET
STC ;CLEAR CARRY AND RETURN
CMC
RET
;; WACM - WRITE ASCII CHARACTER TO MODEM
;
; ENTRY CONDITIONS
; A.........ASCII CHAR TO WRITE
WACM: PUSH PSW ;SAVE CHAR
CALL CTBEM ;LOOP UNTIL MODEM TBE OCCURS
JNC $-3
POP PSW ;RESTORE CHAR
OUT MODDAT ;WRITE CHAR AND RETURN
RET
;; CTBEM - CHECK FOR TBE ON MODEM
;
; EXIT CONDITIONS
; C-FLAG....SET IFF TBE OCCURRED
CTBEM: IN MODSTA ;READ STATUS PORT
ANI MODTBE ;MASK OFF TBE FLAG
JZ $+5 ;JUMP IF NOT PRESENT
STC ;ELSE SET CARRY FLAG AND RETURN
RET
STC ;CLEAR CARRY FLAG AND RETURN
CMC
RET
;; INITM - INITIALIZE MODEM PORT
INITM: XRA A ;CLEAR USART
OUT MODSTA
OUT MODSTA
OUT MODSTA
MVI A,40H ;DO AN INTERNAL RESET
OUT MODSTA
MVI A,6EH ;SELECT ASYNC, ETC.
OUT MODSTA
MVI A,27H ;ISSUE RTS, DSR, ENABLE RX AND TX
OUT MODSTA
IN MODDAT ;CLEAR READ BUFFERS IN CHIP
IN MODDAT
RET
;;; CASSETTE TAPE DRIVER (MODIFIED TARBELL INTERFACE)
;
; LAWRENCE E. HUGHES III
; 8080 SOFTWARE DEVELOPMENT CENTER
; 1506 MYRICK ROAD
; TALLAHASSEE, FLORIDA 32303
CASDAT EQU 6FH ;DATA PORT
CASSTA EQU 6EH ;STATUS PORT
CASRDA EQU 10H ;READ-DATA-AVAILABLE MASK (INVERTED)
CASTBE EQU 20H ;TRANSMIT-BUFFER-EMPTY MASK (INVERTED)
CASEHM EQU 10H ;ENTER HUNT MODE COMMAND
CASCRC EQU 8005H ;CRC POLYNOMIAL (CRC-16)
;; INITT - INITIALIZE TAPE INTERFACE
INITT: XRA A
OUT CASSTA
MVI A,1 ;DEFAULT TO TAPE UNIT 1
STA TUNIT
RET
;; CTRR - READ PHYSICAL RECORD FROM CASSETTE TAPE
;
; ENTRY CONDITIONS
; HL........ADDR OF BUFFER TO ACCEPT DATA
; BC........ADDR OF 11 BYTE BUFFER TO ACCEPT FILENAME
; TUNIT.....UNIT NO. SPECIFIER (1 OR 2)
;
; EXIT CONDITIONS
; DE........PHYSICAL RECORD SIZE (BYTES)
; PRN.......PHYSICAL RECORD NUMBER
; C-FLAG....SET MEANS READ ERROR OCCURRED
CTRR: LDA TUNIT ;GET UNIT NUMBER
ORI CASEHM ;OR IN HUNT MODE BIT
OUT CASSTA ;TURN ON SELECTED UNIT'S MOTOR
CALL CTRB ;READ BYTE FROM TABLE
JC RM80 ;EXIT ON CONSOLE BREAKIN
CPI SOH ;LOOP IF NOT SOH (NOISE)
JNZ CTRR
CTRR1: PUSH H ;SAVE BUFFER ADDR
LXI H,0 ;CLEAR CRC
SHLD CRC
MOV H,B ;READ FILENAME INTO BUFFER
MOV L,C
LXI D,11
CALL CTRS
CALL CTRB ;READ PHYSICAL RECORD NUMBER INTO PRN
STA PRN
CALL CTRB ;READ PHYSICAL RECORD SIZE INTO DE
MOV D,A
CALL CTRB
MOV E,A
CALL CTRB ;ERROR EXIT IF NEXT BYTE NOT STX
CPI STX
JNZ CTRR2
POP H ;RESTORE DATA BUFFER ADDR
PUSH D ;SAVE PHYS REC SIZE
CALL CTRS ;READ DATA BYTES
CALL CTRB ;ERROR EXIT IF NEXT BYTE NOT ETX
CPI ETX
JNZ CTRR2
CALL CTRB ;READ TAPE CRC
CALL CTRB
LHLD CRC ;OUR CRC SHOULD NOW BE ZERO
MOV A,H
ORA L
JNZ CTRR2
POP D ;RESTORE PHYS REC SIZE
XRA A ;TURN OFF MOTOR
OUT CASSTA
STC ;CLEAR ERROR FLAG AND RETURN
CMC
RET
CTRR2: POP D ;RESTORE PHYS REC SIZE
XRA A ;TURN OFF MOTOR
OUT CASSTA
STC ;SET ERROR FLAG AND RETURN
RET
;; CTRS - READ STRING FROM CASSETTE TAPE
;
; ENTRY CONDITIONS
; HL........FWA TO READ INTO
; DE........NUMBER OF BYTES TO READ
CTRS: MOV A,D ;RETURN IF COUNT=0
ORA E
RZ
CALL CTRB ;READ NEXT BYTE
JC RM80 ;EXIT ON CONSOLE BREAKIN
MOV M,A ;STORE IN MEMORY
INX H
DCX D ;DECREMENT COUNT AND LOOP
JMP CTRS
;; CTRB - READ BYTE FROM CASSETTE TAPE
;
; EXIT CONDITIONS
; C-FLAG....SET IFF CONSOLE BREAKIN
CTRB: CALL CRDAC ;EXIT ON CONSOLE BREAKIN
RC
IN CASSTA ;CHECK FOR RDA (INVERTED)
ANI CASRDA
JNZ CTRB
IN CASDAT ;READ BYTE
CMA ;DISPLAY ON LIGHTS
OUT 0FFH
CMA
JMP UCRC ;UPDATE CRC AND RETURN
;; CTWR - WRITE PHYSICAL RECORD TO CASSETTE TAPE
;
; ENTRY CONDITIONS
; TUNIT.....UNIT NUMBER TO WRITE TO
; HL........ADDR OF BUFFER TO BE WRITTEN
; DE........NUMBER OF BYTES TO WRITE (PHYS REC SIZE)
; PRN.......PHYSICAL RECORD NUMBER (INIT TO ZERO BY USER,
; INCREMENTED BY CTWR AUTOMATICALLY)
; BC........ADDR OF BUFFER CONTAINING FILENAME
CTWR: PUSH H ;SAVE DATA BUFFER ADDR
PUSH D ;SAVE PHYS REC SIZE
PUSH B ;SAVE FILENAME BUFFER ADDR
LDA TUNIT ;TURN ON MOTOR
OUT CASSTA
MVI B,15 ;WAIT 1.5 SECONDS
CALL WTS
MVI A,3CH ;WRITE START BYTE
CALL CTWB
MVI A,0E6H ;WRITE SYNC BYTE
CALL CTWB
MVI A,SOH ;WRITE SOH
CALL CTWB
LXI H,0 ;CLEAR CRC
SHLD CRC
POP H ;RESTORE FILENAME BUFFER ADDR
LXI D,11 ;WRITE FILENAME TO TAPE
CALL CTWS
LDA PRN ;WRITE PHYSICAL RECORD NUMBER
CALL CTWB
INR A ;INCREMENT PRN
STA PRN
POP D ;RESTORE PHYS REC SIZE
MOV A,D ;WRITE PHYS REC SIZE
CALL CTWB
MOV A,E
CALL CTWB
MVI A,STX ;WRITE STX
CALL CTWB
POP H ;RESTORE BUFFER POINTER
PUSH D ;SAVE PHYS REC SIZE
CALL CTWS ;WRITE DATA BYTES
MVI A,ETX ;WRITE ETX
CALL CTWB
PUSH H ;SAVE THE UPDATED BUFFER POINTER
LHLD CRC ;WRITE CRC WE'VE BEEN CREATING
MOV A,H
CALL CTWB
MOV A,L
CALL CTWB
POP H ;RESTORE THE UPDATED BUFFER POINTER
XRA A ;SEND A NULL
CALL CTWB
POP D ;RESTORE PHYS REC SIZE
XRA A ;TURN OFF MOTOR
OUT CASSTA
MVI B,5 ;WAIT 0.5 SECONDS AND RETURN
JMP WTS
;; CTWS - WRITE STRING TO CASSETTE TAPE
;
; ENTRY CONDITIONS
; HL........FWA OF STRING TO WRITE
; DE........NUMBER OF BYTES TO WRITE
CTWS: MOV A,D ;RETURN IF COUNT = 0
ORA E
RZ
MOV A,M ;FETCH NEXT BYTE
INX H
CALL CTWB ;WRITE IT
DCX D ;DECREMENT COUNT AND LOOP
JMP CTWS
;; CTWB - WRITE BYTE TO CASSETTE TAPE
;
; ENTRY CONDITIONS
; A.........BYTE TO WRITE
CTWB: PUSH PSW
IN CASSTA ;AWAIT TBE (INVERTED)
ANI CASTBE
JNZ $-4
POP PSW
OUT CASDAT ;WRITE BYTE
CMA ;DISPLAY ON LIGHTS, FALL THRU TO UCRC
OUT 0FFH
CMA
JMP UCRC
;; CTPH - PRINT HEADER INFO
CTPH: PUSH H
PUSH B
PUSH PSW
LXI H,CTPHS1 ;PRINT 'NAME = '
CALL WASC
LXI H,NBUF ;PRINT NAME
MVI B,8
CALL WASCX
LXI H,CTPHS2 ;PRINT ' TYPE = '
CALL WASC
LXI H,NBUF+8 ;PRINT TYPE
MVI B,3
CALL WASCX
LXI H,CTPHS3 ;PRINT ' SIZE = '
CALL WASC
MOV A,D ;PRINT SIZE (IN HEX)
CALL WHBC
MOV A,E
CALL WHBC
LXI H,CTPHS4 ;PRINT ' PRN = '
CALL WASC
LDA PRN ;PRINT PRN (IN HEX)
CALL WHBC
LXI H,CTPHS5 ;PRINT ' CRC = '
CALL WASC
LXI H,CTPHS6 ;PRINT CRC STATUS
POP PSW
PUSH PSW
JNC $+6
LXI H,CTPHS7
CALL WASC
CALL WEOLC
POP PSW
POP B
POP H
RET
CTPHS1: DB 'NAME = ',0
CTPHS2: DB ' TYPE = ',0
CTPHS3: DB ' SIZE = ',0
CTPHS4: DB ' PRN = ',0
CTPHS5: DB ' CRC = ',0
CTPHS6: DB 'GOOD',0
CTPHS7: DB 'BAD',0
;; UCRC - UPDATE CRC
;
; ENTRY CONDITIONS
; A.........NEW DATA BYTE
; CRC.......2 BYTE BUFFER CONTAINING CRC
UCRC: PUSH PSW ;SAVE REGS
PUSH B
PUSH D
PUSH H
MOV B,A ;SAVE DATA BYTE
MVI C,8 ;LOOP COUNT
UCRC1: ANI 80H ;MASK OFF MSB OF DATA BYTE
LHLD CRC ;FETCH CRC INTO HL
XRA H ;XOR MSB OF DATA BYTE INTO CRC
MOV H,A
DAD H ;LEFT SHIFT CRC 1 BIT
JNC UCRC2 ;JUMP IF NO CARRY
MOV A,H ;HL = HL XOR CRC POLYNOMIAL
XRI CASCRC SHR 8
MOV H,A
MOV A,L
XRI CASCRC AND 0FFH
MOV L,A
UCRC2: SHLD CRC ;REPLACE CRC
DCR C ;DECREMENT LOOP COUNT
JZ UCRC3 ;EXIT WHEN ENTIRE BYTE PROCESSED
MOV A,B ;SHIFT DATA BYTE LEFT 1 BIT
ADD A
MOV B,A
JMP UCRC1 ;LOOP
UCRC3: POP H ;RESTORE REGS AND RETURN
POP D
POP B
POP PSW
STC
CMC
RET
;; WTS - WAIT TENTHS OF A SECOND
;
; ENTRY CONDITIONS
; B - NUMBER OF TENTHS TO WAIT
WTS: INR B ;EXIT WHEN B=0
DCR B
RZ
PUSH H ;WAIT ONE TENTH SECOND
LXI H,8330
WTS1: DCX H
MOV A,H
ORA L
JNZ WTS1
POP H
DCR B ;DECREMENT COUNT AND LOOP
JMP WTS
END
ERT TO BINARY
JC DHSX
CPI 10 ;JUMP IF DIGIT < 10
JC $+5
SUI