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
/
CPMUG015.ARK
/
SOLOS.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
47KB
|
2,059 lines
; ******** SOLOS OPERATING SYSTEM ********
;
; PROCESSOR TECHNOLOGY CORP.
; EMERYVILLE, CALIFORNIA
;
;
; VERSION 1.3
; RELEASE 3/27/77
;
;
;
;
;
; THIS 2048 BYTE PROGRAM IS THE STANDARD SOL STAND
; ALONE OPERATING SYSTEM. IT IS CONFIGURED TO OPTIMIZE
; THE CONVENIENCE AND POWER OF THE SOL-20 AND ONE OR TWO
; CASSETTE RECORDERS IN STAND ALONE COMPUTER APPLICATIONS.
;
;
;COMMANDS:
; TE TERMINAL MODE
; DU SSSS EEEE DUMP (START ADDR END ADDR)
; EN SSSS ENTER HEX TO MEMORY
; EX SSSS EXECUTE
; GE FILENAME/U GET (U=TAPE UNIT 0 OR 1, DFLT=1)
; SA FNAME/U SSSS EEEE SAVE ON TAPE (UNIT 0 OR 1)
; XE FILENAME/U AUTO LOAD/EXECUTE
; CA CATALOG OF TAPE FILES
; CU LL SSSS CUSTOM COMMAND (LL=LABLE)
; SET TA N SET TAPE SPEED (N:0=FAST,1=SLOW)
; SET S=NN SET DISPLAY SPEED (O-->FF)
; SET I=N SET IN PSEUDO PORT (N=0 - 3)
; SET O=N SET OUT PSEUDO PORT (N=0 - 3)
; SET N=NN SET NULLS (N=0 - FF)
; SET CI SSSS SET CUSTOM INPUT DRIVER ADDR
; SET CO SSSS SET CUSTOM OUTPUT DRIVER ADDR
; SET XE SSSS SET AUTO-EXECUTE ADDRESS FOR TAPE SAVE
; SET TY NN SET FILE TYPE FOR TAPE HEADER
; SET CR NN OVERRIDE CRC ERRORS (FF=IGNORE ERRORS)
;
;
; PSEUDO PORTS: 0 = KEYBOARD/VIDEO
; 1 = SERIAL PORT
; 2 = PARALLEL PORT
; 3 = USER DEFINED (SET CI, SET CO)
;
;
;
ORG 0C000H
;
;
;
; AUTO-STARTUP CODE
;
START: DB 0
INIT: JMP STRTA ;SYSTEM RESTART ENTRY POINT
;
;
; ENTRY POINTS
;
; THESE JUMP POINTS ARE PROVIDED TO ALLOW COMMON ENTRY
; LOCATIONS FOR ALL VERSIONS OF SOLOS. THEY ARE USED
; EXTENSIVLY BY SOL SYSTEM PROGRAMS AND IT IS RECOMMENDED
; THAT USER ROUTINES ACCESS SOLOS THROUGH THESE POINTS.
;
RETRN: JMP COMND ;RETURN TO SYSTEM ENTRY POINT
FOPEN: JMP BOPEN ;FILE OPEN ENTRY
FCLOS: JMP PCLOS ;FILE CLOSE ENTRY
RDBYT: JMP RTBYT ;CASSETTE READ BYTE ENTRY
WRBYT: JMP WTBYT ;CASSETTE WRITE BYTE ENTRY
RDBLK: JMP RTAPE ;CASSETTE READ BLOCK ENTRY
WRBLK: JMP WTAPE ;CASSETTE WRITE BLOCK ENTRY
;
;
; SYSTEM I/O ENTRY POINTS
;
; THESE ROUTINES PERFORM SYSTEM I/O
; THERE ARE TWO ENTRY TYPES:
; SINP/SOUT REG "A" WILL BE SET TO THE STANDARD
; SYSTEM PSEUDO PORT.
; AINP/AOUT REG "A" MUST BE SET BY THE USER AND
; WILL SPECIFY THE DESIRED PSEUDO PORT.
;
; THE FOLLOWING ARE THE PSEUDO PORTS:
; PORT DESCRIPTION
; ---- --------------------------------
; 0 KEYBOARD WHEN INPUT, AND VDM WHEN OUTPUT
; 1 SERIAL I/O PORT
; 2 PARALLEL I/O PORT
; 3 USER DEFINED I/O PORT
;
SOUT: LDA OPORT ;SOUT ENTRY POINT
AOUT: JMP OUTPR ;AOUT ENTRY POINT
SINP: LDA IPORT ;SINP ENTRY POINT
AINP: EQU $ ;AINP ENTRY POINT
;******** END OF SYSTEM ENTRY POINTS *********
PUSH H ;THIS IS ACTUALLY AINP
LXI H,ITAB
;
;
; THIS ROUTINE PROCESSES THE I/O REQUESTS BY DISPATCHING
; TO THE DRIVER REQUESTED IN REGISTER "A". ON ENTRY HL
; HAS THE PROPER DISPATCH TABLE.
;
IOPRC: ANI 3 ;KEEP REGISTER "A" TO FOUR VALUES
RLC ;COMPUTE ENTRY ADDRESS
ADD L
MOV L,A ;WE HAVE ADDRESS
JMP DISPT ;DISPATCH TO IT
;
;
; ***** SOL SYSTEM I/O ROUTINES *****
;
;
; THIS ROUTINE IS A MODEL OF ALL INPUT ROUTINES WITHIN
; SOLOS. EACH ROUTINE FIRST TESTS THE STATUS INPUT FOR
; DATA AVAILABLE. IF NO CHARACTERHAS BEEN RECEIVED THE
; ROUTINE RETURNS WITH THE ZERO FLAG SEG. OTHERWISE THE
; CHARACTER IS INPUT AND A RETURN MADE WITH THE CHARACTER
; IN THE ACCUMULATOR AND THE ZERO FLAG RESET.
;
;
; KEYBOARD INPUT DRIVER
;
KSTAT: IN STAPT ;GET STATUS WORK
CMA ;INVERT IT FOR PROPER RETURN
ANI KDR ;TEST KEYBOARD BIT
RZ ;ZERO IS NO CHARACTER RECEIVED
;
IN KDATA ;GET CHARACTER
RET ;GO BACK WITH IT
;
;
; THIS JUMP IS PART OF THE AUTO START UP CODE
;
DB 0 ;VERIFY ADDR=C037
JMP INIT ;THIS SHOULD BE C038
;
;
; JMP TABLE OUTPUT ROUTINES
;
; THIS ROUTINE SETS UP THE DISPATCH TABLE FOR OUTPUT
; ROUTINES. THE CHARACTER FOR OUTPUT IS IN REGISTER "B".
; OUTPUT IS MADE TO THE DRIVER POINTED TO BY THE REGISTER
; "A". THE DEVICE DRIVERS ARE DEFINED AS FOLLOWS:
;
; 0 - DISPLAY SCREEN
; 1 - SERIAL OUTPUT PORT
; 2 - PARALLEL OUTPUT PORT
; 3 - USER DEFINED OR ERROR FLAG
;
; ENTRY AT: SOUT SELECTS CURRENT OUTPUT DEVICE
; AOUT SELECTS DEVICE IN REGISTER "A"
;
OUTPR: PUSH H
LXI H,OTAB ;POINT TO OUTPUT TABLE
JMP IOPRC ;AND DISPATCH TO OUTPUT ROUTINE
;
;
;
; SERIAL INPUT DRIVER
;
SSTAT: IN SERST ;GET SERIAL STATUS WORD
ANI SDR ;TEST FOR SERIAL DATA READY
RZ ;FLAGS ARE SET
;
IN SDATA ;GET DATA BYTE
RET ;WE HAVE IT
;
;
; SERIAL DATA OUTPUT
;
SDROT: IN SERST ;GET PORT STATUS
RAL ;PUT HIGH BIT IN CARRY
JNC SDROT ;LOOP UNTIL TRANSMITTER BUFFER IS EMPTY
MOV A,B ;GET THE CHARACTER BACK
OUT SDATA ;SEND IT OUT
RET ;AND WE'RE DONE
;
;
;
;
; VIDEO DISPLAY ROUTINES
;
;
; THESE ROUTINES ALLOW FOR STANDARD VIDEO TERMINAL
; OPERATIONS. ON ENTRY, THE CHARACTER FOR OUTPUT IS IN
; REGISTER B AND ALL REGISTERS EXCEPT "A" AND FLAGS ARE
; UNALTERED ON RETURN.
;
;
VDMOT: PUSH H ;SAVE MOST REGISTERS
PUSH D
PUSH B
;
; TEST IS ESC SEPUENCE HAS BEEN STARTED
;
LDA ESCFL ;GET ESCAPE FLAG
ORA A
JNZ ESCS ;IF NON-ZERO GO PROCESS THE REST
;
;
CHPCK: MOV A,B ;SAVE IN B...STRIP PARITY BEFORE SCREEN!
ANI 7FH ;CLR PARITY TO LOCATE IN TBL
MOV B,A ;KEEP IT W/OUT PARITY IN B TOO
JZ GOBK ;DO A QUICK EXIT IF A NULL
LXI H,TBL ;POINT TO SPECIAL SHARACTER TABLE
CALL TSRCH ;GO PROCESS
;
GOBACK: CALL VDADD ;GET SCREEN ADDRESS
MOV A,M ;GET PRESENT CURSOR CHARACTER
ORI 80H
MOV M,A ;CURSOR IS BACK ON
LHLD SPEED-1 ;GET DELAY SPEED
INR L ;MAKE SURE IT IS NON-ZERO
XRA A ;DELAY WILL END WHEN H=0
TIMER: DCX H ;TIMER DELAYS HERE
CMP H ;DONE WITH DELAY YET
JNZ TIMER ;KEEP DELAYING
GOBK: POP B
POP D ;RESTORE REGISTERS
POP H
RET ;EXIT FROM VDMOT
;
NEXT: INX H
INX H
;
;
; THIS ROUTINE SEARCHES THROUGH A SINGLE CHARACTER
; TABLE FOR A MATCH TO THE CHARACTER IN "B". IF FOUND
; A DISPATCH IS MADE TO THE ADDRESS FOLLOWING THE MATCHED
; CHARACTER. IF NOT FOUND THE CHARACTER IS DISPLAYED ON
; THE MONITOR.
;
TSRCH: MOV A,M ;GET CHR FROM TABLE
ORA A
JZ CHAR ;ZERO IS THE LAST
CMP B ;TEST THE CHR
INX H ;POINT FORWARD
JNZ NEXT
PUSH H ;FOUND ONE...SAVE ADDRESS
CALL CREM ;REMOVE CURSOR
XTHL ;GET DISPATCH ADDRESS TO HL
JMP DISPT ;DISPATCH NOW
;
; PUT CHARACTER TO SCREEN
;
CHAR: MOV A,B ;GET CHARACTER
CPI 7FH ;IS IT A DEL?
RZ ;GO BACK IF SO
;
;
;
OCHAR: EQU $ ;ACTUALLY PUT CHAR TO SCREEN NOW
CALL VDADD ;GET SCREEN ADDRESS
MOV M,B ;PUT CHR ON SCREEN
;
LDA NCHAR ;GET CHARACTER POSITION
CPI 63 ;END OF LINE?
JC OK
LDA LINE
CPI 15 ;END OF SCREEN?
JNZ OK
;
; END OF SCREEN...ROLL UP ONE LINE
;
SCROLL: XRA A
STA NCHAR ;BACK TO FIRST CHAR POSITION
SROL: MOV C,A
CALL VDAD ;CALCULATE LINE TO BE BLANKED
XRA A
CALL CLIN1 ;CLEAR IT
LDA BOT
INR A
ANI 0FH
JMP ERAS3
;
; INCREMENT LINE COUNTER IF NECESSARY
;
OK: LDA NCHAR ;GET CHR POSITION
INR A
ANI 3FH ;MOD 64 AND WRAP
STA NCHAR
RNZ ;DIDN'T HIT END OF LINE, OK
PDOWN: EQU $ ;CURSOR DOWN ONE LINE HERE
LDA LINE ;GET THE LINE COUNT
INR A
CURSC: ANI 0FH ;STORE THE NEW
CUR: STA LINE ;STORE THE NEW
RET
;
; ERASE SCREEN
;
PERSE: LXI H,VDMEM ;POINT TO SCREEN
MVI M,80H+' ' ;THIS IS THE CURSOR
;
INX H ;BUMP 1ST
ERAS1: EQU $ ;LOOPS HERE TO ERASE SCREEN
MVI M,' ' ;BLANK IT OUT
INX H ;NEXT
MOV A,H ;SEE IF END OF SCREEN YET
CPI 0D0H
JC ERAS1 ;NO--KEEP BLANKING
STC ;CARRY WILL SAY COMPLETE ERASE
;
PHOME: MVI A,0 ;RESET CURSOR--CARRY=ERASE, ELSE HOME
STA LINE ;ZERO LINE
STA NCHAR ;LEFT SIDE OF SCREEN
RNC ;IF NO CARRY, WE ARE DONE WITH HOME
;
ERAS3: OUT DSTAT ;RESET SCROOL PARAMETERS
STA BOT ;BEGINNING OF TEXT OFFSET
RET
;
;
CLINE: CALL VDADD ;GET CURRENT SCREEN ADDRESS
LDA NCHAR ;CURRENT CURSOR POSITION
CLIN1: CPI 64 ;NO MORE THAN 63
RNC ;ALL DONE
MVI M,' ' ;ALL SPACED OUT
INX H
INR A
JMP CLIN1 ;LOOP TO END OF LINE
;
;
; ROUTINE TO MOVE THE CURSOR UP ONE LINE
;
PUP: LDA LINE ;GET LINE COUNT
DCR A
JMP CURSC ;MERGE TO HANDLE CURSOR
;
; MOVE CURSOR LEFT ONE POSITION
;
PLEFT: LDA NCHAR
DCR A
PCUR: EQU $ ;CURSOR ON SAME LINE
ANI 3FH ;LET CURSOR WRAP
STA NCHAR ;UPDATED CURSOR
RET
;
; CURSOR RIGHT ONE POSITION
;
PRIT: LDA NCHAR
INR A
JMP PCUR
;
; ROUTINE TO CALCULATE SCREEN ADDRESS
;
; ENTRY AT: RETURNS:
;
; VDADD CURRENT SCREEN ADDRESS
; VDAD2 ADDRESS OF CURRENT LINE, CHAR "C"
; VDAD LINE "A", CHARACTER POSITION 'C'
;
VDADD: LDA NCHAR ;GET CHARACTER POSITION
MOV C,A ;'C' KEEPS IT
VDAD2: LDA LINE ;LINE POSITION
VDAD: MOV L,A ;INTO 'L'
LDA BOT ;GET TEXT OFFSET
ADD L ;ADD IT TO THE LINE POSITION
RRC ;TIMES TWO
RRC ;MADES FOUR
MOV L,A ;L HAS IT
ANI 3 ;MOD THREE FOR LATER
ADI VDMEM SHR 8 ;LOW SCREEN OFFSET
MOV H,A ;NOW H IS DONE
MOV A,L ;TWIST L'S ARM
ANI 0C0H
ADD C
MOV L,A
RET ;H & L ARE NOW PERVERTED
;
; ROUTINE TO REMOVE CURSOR
;
CREM: CALL VDADD ;GET CURRENT SCREEN ADDRESS
MOV A,M
ANI 7FH ;STRIP OFF THE CURSOR
MOV M,A
RET
;
; ROUTINE TO BACKSPACE
;
PBACK: CALL PLEFT
CALL VDADD ;GET SCREEN ADDRESS
MVI M,' ' ;PUT A BLANK THERE
RET
;
; ROUTINE TO PROCESS A CARRIAGE RETURN
;
PCR: XRA A ;REWIND TO BEGINNING OF LINE
;
;ORIGINAL HAD 'CALL CLINE' INSTEAD OF 'XRA A' AS SHOWN
;ABOVE. THIS CAUSED DISK COMMANDS TO DISAPPEAR FROM THE
;SCREEN AS CP/M MUST OUTPUT TWO 'CR' CHARACTERS.
;
JMP PCUR ;AND STORE THE NEW VALUE
;
; ROUTINE TO PROCESS A LINEFEED
;
PLF: LDA LINE ;GET LINE COUNT
INR A
ANI 15 ;SEE IF IT WRAPPED AROUND
JNZ CUR ;NO--NO NEED TO SCROLL
JMP SROL ;YES--THEN SCROLL
;
; SET ESCAPE PROCESS FLAG
;
PESC: MVI A,(-1) AND 0FFH
STA ESCFL ;SET FLAG
RET
;
; PROCESS ESCAPE SEQUENCE
;
ESCS: CALL CREM ;REMOVE CURSOR
CALL ESCSP ;PROCESS THE NEXT PART OF SEQUENCE
JMP GOBACK
;
ESCSP: LDA ESCFL ;GET ESCAPE FLAG
CPI (-1) AND 0FFH ;TEST FLAG
JZ SECOND
;
; PROCESS THIRD CHR OF ESC SEQUENCE
;
LXI H,ESCFL
MVI M,0 ;NO MORE PARTS TO THE SEQUENCE
CPI 2
JC SETX ;SET X IF IS ONE
JZ SETY ;SET Y IF IS TWO
CPI 8
JZ STSPD ;SET NEW DISPLAY SPEED IF "8"
CPI 9
JC OCHAR ;PUT IT ON THE SCREEN
RNZ
;
; TAB ABSOLUTE TO VALUE IN REG B
;
SETX: MOV A,B ;GET CHARACTER
JMP PCUR
;
; SET CURSOR TO LINE "B"
;
SETY: MOV A,B
JMP CURSC
;
;
; PROCESS SECOND CHR OF ESC SEPUENCE
;
SECOND: MOV A,B ;GET WHICH
CPI 3
JZ CURET ;RETURN CURSOR PARAMETERS
CPI 4
JNZ ARET2
;
; ESC <4> RETURN ABSOLUTE SCREEN ADDRESS
;
ARET: MOV B,H
MOV C,L ;PRESENT SCREEN ADDRESS TO BC FOR RETURN
;
ARET1: POP H ;RETURN ADDRESS
POP D ;OLD B
PUSH B
PUSH H
XRA A
ARET2: STA ESCFL
RET
;
;
; RETURN PRESENT SCREEN PARAMETERS IN "BC"
;
CURET: LXI H,NCHAR
MOV B,M ;CHARACTER POSITION
INX H
MOV C,M ;LINE POSITION
JMP ARET1
;
;
; ***** START UP SYSTEM *****
;
; CLEAR SCREEN AND THE FIRST 256 BYTES OF GLOBAL RAM
; THEN ENTER THE COMMAND MODE
;
STRTA: XRA A
MOV C,A
LXI H,SYSRAM ;CLEAR THR FIRST PAGE
;
CLERA: MOV M,A
INX H
INR C
JNZ CLERA
;
LXI SP,SYSTP ;SET UP THE STACK FOR CALL
CALL PERSE
COMN1: XRA A
OUT STAPT ;BE SURE TAPES ARE OFF
STA OPORT
STA IPORT
;
;
;
; ***** COMMAND MODE *****
;
;
; THIS ROUTINE GETS AND PROCESSES COMMANDS
;
COMND: LXI SP,SYSTP ;SET STACK POINTER
LDA OPORT ;GET PORT
PUSH PSW
XRA A
STA OPORT ;FORCE SCREEN OPERATIONS
CALL PROMPT ;PUT PROMPT ON SCREEN
CALL GCLIN ;GET COMMAND LINE
POP PSW
STA OPORT ;RESTORE DEFAULT PORT
CALL COPRC ;PROCESS THE LINE
JMP COMND ;OVER AND OVER
;
;
;
; THIS ROUTINE READS A COMMAND LINE
; FROM THE SYSTEM KEYBOARD
;
; C/R TERMINATES THE SWQUENCE ERASING ALL
; CHARS TO THE RIGHT OF THE CURSOR
; L/F TERMINATES THE SEQUENCE
; MODE RESTARTS THE COMMAND LINE
;
GCLIN: CALL SINP ;READ INPUT DEVICE
JZ GCLIN
ANI 7FH ;CLEAR PARITY BIT
JZ COMN1 ;THIS WAS A MODE (OR EVEN CTRL-@)
MOV B,A
CPI CR ;CARRIAGE RETURN
JZ CLINE ;YES--DONE WITH LINE
CPI LF ;LINE FEED
RZ ;YES--DONE WITH LINE, LEAVE AS IS
CPI 7FH ;DELETE CHR?
JNZ CONT
MVI B,BACKS ;REPLACE IT
;
CONT: CALL SOUT
JMP GCLIN
;
;
; FIND AND PROCESS COMMAND
;
COPRC: CALL CREM ;REMOVE THE CURSOR
MVI C,1 ;SET FOR CHARACTER POSITION
CALL VDAD2 ;GET SCREEN ADDRESS
XCHG
LXI H,START ;MAKE SURE HL PT TO SOLOS START
PUSH H ;SAVE IT FOR LATER DISPT
CALL SCHR ;SCAN PAST BLANKS
JZ ERR1 ;NO COMMAND?
XCHG ;HL HAS FIRST CHR
;
LXI D,COMTAB ;POINT TO COMMAND TABLE
CALL FDCOM ;SEE IF IN PRIMARY COMMAND TABLE
CZ FDCOU ;IF NOT, TRY CUSTOM TABLE NEXT
DISPO: EQU $ ;HERE TO SEE IF ERROR OR DISP
JZ ERR2 ;NOT VALID, ERROR
INX D ;BUMP TO PTR OF RTN
XCHG ;HL PT TO RTN ADDR
;
;
; THIS IS THE DISPATCH ROUTINE
; HL PT TO RTN ADDRESS, HL WILL BE RESTORED FROM STACK
; SO THAT HL ARE RESTORED BEFORE DISPATCH.
;
DISPT: EQU $ ;OFF TO A ROUTINE
MOV A,M ;LO ADDR
INX H
MOV H,M ;HI ADDR
MOV L,A ;HL NOW COMPLETE
DISP1: EQU $ ;HERE TO GO OFF TO HL
XTHL ;XCHG HL W/HL ON STACK
MOV A,L ;ALSO COPY HERE FOR SETS
RET ;AND GO OFF TO THE RTN
;
;
; THIS ROUTINE SEARCHES THROUGH A TABLE, POINTED TO
; BY 'DE', FOR A DOUBLE CHARACTER MATCH OF THE 'HL'
; MEMORY CONTENT. IF NO MATCH IS FOUND THE SCAN ENDS
; WITH HL POINTING TO ORIGINAL VALUE AND ZERO FLAG SET.
;
FDCOU: LXI D,CUTAB ;HERE TO SCAN CUSTOM TBL ONLY
;
FDCOM: LDAX D
ORA A ;TEST FOR TABLE END
RZ ;NOT FOUND..COMMAND ERROR
PUSH H ;SAVE START OF SCAN ADDRESS
CMP M ;TEST FIRST CHR
INX D
JNZ NCOM
;
INX H
LDAX D
CMP M ;NOW SECOND CHARACTER
JNZ NCOM ;GOODNESS
;
POP H ;RESTORE ORIGINAL SCAN ADDR
ORA A ;SET NON-ZERO FLAG SAYING FOUND
RET ;WITH NON-ZERO SET
;
;
NCOM: INX D ;GO TO NEXT ENTRY
INX D
INX D
POP H ;GET BACK ORIGINAL ADDRESS
JMP FDCOM ;CONTINUE SEARCH
;
;
; ***** COMMAND TABLE *****
;
; THIS TABLE DESCRIBES THE VALID COMMANDS FOR SOLOS
;
COMTAB: DW 'TE' ;TERMINAL MODE
DW TERM
DW 'DU' ;DUMP
DW DUMP
DW 'EN' ;ENTER
DW ENTER
DW 'EX' ;EXECUTE
DW EXEC
DW 'GE' ;GET A FILE
DW TLOAD
DW 'SA' ;SAVE A FILE
DW TSAVE
DW 'XE' ;AUTO-EXECUTE A FILE
DW TXEQ
DW 'CA' ;CATALOG OF TAPE FILES
DW TLIST
DW 'SE' ;SET COMMAND
DW CSET
DW 'CU' ;CUSTOM COMMAND
DW CUSET
DB 0 ;END OF TABLE MARK
;
;
; DISPLAY DRIVER COMMAND TABLE
;
; THIS TABLE DEFINES THE CHARACTERS FOR SPECIAL
; PROCESSING. IF THE CHARACTER IS NOT IN THE TABLE IT
; GOES TO THE SCREEN.
;
TBL: DB CLEAR-80H ;CLEAR SCREEN
DW PERSE
DB UP-80H ;UP CURSOR
DW PUP
DB DOWN-80H ;DOWN CURSOR
DW PDOWN
DB LEFT-80H ;LEFT CURSOR
DW PLEFT
DB RIGHT-80H ;RIGHT CURSOR
DW PRIT
DB HOME-80H ;HOME CURSOR
DW PHOME
DB CR ;CARRIAGE RETURN
DW PCR
DB LF ;LINE FEED
DW PLF
DB BACKS ;BACKSPACE
DW PBACK
DB ESC ;ESCAPE KEY
DW PESC
DB 0 ;END OF TABLE
;
;
; OUTPUT DEVICE TABLE
;
OTAB: DW VDMOT ;VDM DRIVER
DW SDROT ;SERIAL OUTPUT
DW PROUT ;PARALLAL OUTPUT
DW ERROT ;ERROR OR USER DRIVER HANDLER
;
;
; INPUT DEVICE TABLE
;
ITAB: DW KSTAT ;KEYBOARD INPUT
DW SSTAT ;SERIAL INPUT
DW PASTAT ;PARALLEL INPUT
DW ERRIT ;ERROR OR USER DRIVER HANDLER
;
;
; SECONDARY COMMAND TABLE FOR SET COMMAND
;
SETAB: DW 'TA' ;SET TAPE SPEED
DW TASPD
DW 'S=' ;SET DISPLAY SPEED
DW DISPD
DW 'I=' ;SET INPUT PORT
DW SETIN
DW 'O=' ;SET OUTPUT PORT
DW SETOT
DW 'N=' ;SET NULLS
DW SETNU
DW 'CI' ;SET CUSTOM DRIVER ADDRESS
DW SETCI
DW 'CO' ;SET CUSTOM OUTPUT DRIVER ADDRESS
DW SETCO
DW 'XE' ;SET HEADER XEQ ADDRESS
DW SETXQ
DW 'TY' ;SET HEADER TYPE
DW SETTY
DW 'CR' ;SET CRC TO ALLOW IGNORING OF CRC ERRORS
DW SETCR
DB 0 ;END OF TABLE MARK
;
;
; SOLOS PORT ERROR HANDLER
;
ERRIT: PUSH H ;SAVE HL ONCE AGAIN
LHLD UIPRT ;GET USER INPUT PORT ADDRESS
JMP ERRO1 ;AND GO PROCESS
;
ERROT: PUSH H
LHLD UOPRT ;GET USER OUTPUT PORT ADDRESS
ERRO1: MOV A,L ;TEST HL FOR ZERO
ORA H
JZ COMN1 ;IF ZERO RETURN TO COMMAND MODE
XTHL ;ADDRESS TO STACK...OLD HL TO HL
RET ;GO TO THE DRIVER
;
; THIS ROUTINE IS THE PARALLEL DEVICE HANGLER
; NO PROVISION IS MADE FOR CONTROLLING THE PORT
; CONTROL BIT.
;
;
; PARALLEL INPUT DRIVER
;
PASTAT: IN STAPT
CMA ;INVERT STATUS FLAGS
ANI PDR ;TEST BIT
RZ
IN PDATA ;GET DATA
RET
;
; PARALLEL OUTPUT HANDLER
;
PROUT: IN STAPT ;GET STATUS
ANI PXDR ;TEST IF DEVICE IS READY
JNZ PROUT ;LOOP UNTIL SO
MOV A,B
OUT PDATA
RET
;
;
; OUTPUT A CR/LF FOLLOWED BY A PROMPT
;
PROMPT: CALL CRLF
MVI B,'>' ;THE PROMPT
JMP SOUT ;PUT IT ON THE SCREEN
;
;
CRLF: MVI B,LF ;LINE FEED
CALL SOUT
MVI B,CR ;CARRIAGE RETURN
CALL SOUT
; NOW OUTPUT THE NULLS
LDA NUCNT ;GET DESIRED COUNT
MOV C,A ;STORE IN C
NULOT: DCR C
RM ;RETURN WHEN PAST ZERO
XRA A ;GET A NULL
CALL OUTH
JMP NULOT
;
;
; SCAN OFF OPTIONAL PARAMETER. IF PRESENT RETURN WITH
; VALUE IN HL AND COPY OF 'L' IN 'A'. IF NOT PRESENT
; RETURN WITH A "1" IN 'A' AND HL UNTOUCHED.
;
PSCAN: CALL SBLK
MVI A,1 ;DEFAULT VALUE
RZ ;IF NONE
CALL SHEX ;CONVERT VALUE
MOV A,L ;GET LOWER HALF
RET
;
;
; SCAN OVER UP TO 12 CHARACTERS LOOKING FOR A BLANK
;
SBLK: MVI C,12 ;MAXIMUM COMMAND STRING
SBLK1: LDAX D
CPI BLANK
JZ SCHR ;GOT A BLANK NOW SCAN PAST IT
INX D
CPI '=' ;ALSO ALLOW EQUAL TO STOP US
JZ SCHR ;IF SO, PTR AT CHAR FOLLOWING
DCR C ;NO MORE THAN TWELVE
JNZ SBLK1
RET ;GO BACK WITH ZERO FLAG SET
;
;
; SCAN PAST UP TO 10 BLANK POSITIONS LOOKING FOR
; A NON-BLANK CHARACTER
;
SCHR: MVI C,10 ;SCAN TO FIRST NONBLANK CHR IN 10
SCHR1: LDAX D ;GET NEXT CHARACTER
CPI SPACE
RNZ ;WE'RE PAST THEM
INX D ;NEXT SCAN ADDRESS
DCR C
RZ ;COMMAND ERROR
JMP SCHR1 ;KEEP LOOPING
;
;
; THIS ROUTINE SCANS OVER CHARACTERS, PAST BLANKS AND
; CONVERTS THE FOLLOWING VALUE TO HEX. ERRORS RETURN TO
; THE ERROR HANDLER.
;
SCONV: CALL SBLK ;FIND IF VALUE IS PRESENT
JZ ERR1 ;ABORT TO ERROR IF NONE
;
;
; THIS ROUTINE CONVERTS ASCII DIGITS INTO BINARY FOLLOWING
; A STANDARD HEX CONVERSION. THE SCAN STOPS WHEN AN ASCII
; SPACE IS ENCOUNTERED. PARAMETER ERRORS REPLACE THE ERROR
; CHARACTER ON THE SCREEN WITH A QUESTION MARK.
;
SHEX: LXI H,0 ;CLEAR H & L
SHE1: LDAX D ;GET CHARACTER
CPI 20H ;IS IT A SPACE
RZ ;IF SO
CPI '/' ;SLASH IS ALSO LEGAL
RZ
CPI ':' ;EVEN THE COLON IS ALLOWED
RZ
;
HCONV: DAD H ;MAKE ROOM FOR THE NEW ONE
DAD H
DAD H
DAD H
CALL HCOV1 ;DO THE CONVERSION
JNC ERR1 ;NOT VALID HEXIDECIMAL VALUE
ADD L
MOV L,A ;MOVE IT IN
INX D ;BUMP THE POINTER
JMP SHE1
;
HCOV1: SUI 48 ;REMOVE ASCII BIAS
CPI 10
RC ;IF LESS THAN 9
SUI 7 ;IT'S A LETTER
CPI 10H
RET ;WITH TEST IN HAND
;
;
; ***** TERMINAL COMMAND *****
;
; THIS ROUTINE GETS CHARACTERS FROM THE SYSTEM KEYBOARD
; AND OUTPUTS THEM TO THE SELECTED OUTPUT PORT. IT IS
; INTENDED TO CONFIGURE THE SOL AS A STANDARD VIDEO
; TERMINAL. COMMAND KEYS ARE NOT OUTPUT TO THE OUTPUT
; PORT BUT ARE INTERPRETED AS DIRECT SOL COMMANDS.
; THE MODE COMMAND, RECEIVED BY THE KEYBOARD, PUTS THE SOL
; IN THE COMMAND MODE.
;
;
;
TERM: CALL PSCAN ;FIND IF INPUT PARAMETER IS PRESENT
STA IPORT ;SINP WILL USE THIS DRIVER (DEFAULT IS 1)
CALL PSCAN ;NOW FOR THE OUTPUT DRIVER
STA OPORT
;
TERM1: CALL KSTAT ;IS THERE ONE WAITING?
JZ TIN ;IF NOT
MOV B,A ;SAVE IT IN B
CPI MODE ;IS IT MODE?
JZ COMN1 ;YES...RESET AND QUIT TERM
JC TOUT ;NON-CURSOR KEY...SEND TO TERM PORT
CALL VDMOT ;PROCESS IT
JMP TIN
;
TOUT: CALL SOUT ;OUTPUT IT TO THE SERIAL PORT
TIN: CALL SINP ;GET INPUT STATUS
JZ TERM1 ;LOOP IF NOT
ANI 7FH ;NO HIGH BITS FROM HERE
JZ TERM1 ;A NULL IS IGNORED
MOV B,A ;IT'S OUTPUT FROM 'B'
CPI 1BH ;IS IT A CONTROL CHAR TO BE IGNORED
JNC TERM2 ;NO...TO VDM AS IS THEN
CPI CR ;CR OR LF ARE SPECIAL CASES THOUGH
JZ TERM2 ;AND MUST BE PASSED STD MODE TO VDM
CPI LF
JZ TERM2
LDA ESCFL ;A CTRL CHAR...ARE WE W/IN ESC SEQUENCE?
ORA A ;IF YES, THEN OUTPUT CTRL CHAR DIRECTLY TO VDM
JNZ TERM2 ;WE SURE ARE, LET VDM DRIVER HANDLE IT
PUSH B ;SAVE THE CHARACTER
MVI B,ESC ;CTRL CHAR TO VDM VIA ESC SEQUENCE
CALL VDMOT
MVI B,7 ;SAY TO PUT OUT NEXT CHAR AS IS
CALL VDMOT ;ALMOST READY
POP B ;RESTORE CHAR
TERM2: EQU $ ;ALL READY TO OUTPUT THE CHAR
CALL VDMOT ;PUT IT ON THE SCREEN
JMP TERM1 ;LOOP OVER AND OVER
;
;
;
; ***** DUMP COMMAND *****
;
; THIS ROUTINE DUMPS CHARACTERS FROM MEMORY TO THE
; CURRENT OUTPUT DEVICE. ALL VALUES ARE DISPLATED AS
; ASCII HEX.
;
; THE COMMAND FORM IS A FOLLOWS:
;
; DU ADDR1 ADDR2
;
; THE VALUES FROM ADDR1 TO ADDR2 ARE THEN OUTPUT TO THE
; OUTPUT DEVICE. IF ONLY ADDR1 IS SPECIFIED THEN THE
; VALUE AT THAT ADDRESS IS OUTPUT.
;
DUMP: CALL SCONV ;SCAN TO FIRST ADDRESS AND CONVERT IT
PUSH H ;SAVE THE VALUE
CALL PSCAN ;SEE IF SECOND WAS GIVIN
POP D
XCHG ;HL HAS START, DE HAS END
;
DLOOP: CALL CRLF
CALL ADOUT ;OUTPUT ADDRESS
CALL BOUT ;ANOTHER SPACE TO KEEP IT PRETTY
MVI C,16 ;VALUES PER LINE
;
DLP1: MOV A,M ;GET THE CHAR
PUSH B ;SAVE VALUE COUNT
CALL HBOUT ;SEND IT OUT WITH A BLANK
MOV A,L ;COMPARE DE AND HL
SUB E
MOV A,H
SBB D
JNC COMND ;ALL DONE
POP B ;VALUES PER LINE
INX H
DCR C ;BUMP THE LINE COUNT
JNZ DLP1 ;NOT ZERO IF MORE FOR THIS LINE
JMP DLOOP ;DO A LFCR BEFORE THE NEXT
;
;
; OUTPUT HL AS HEX 16 BIT VALUE
;
ADOUT: MOV A,H ;H FIRST
CALL HEOUT
MOV A,L ;THEN L FOLLOWED BY A SPACE
;
HBOUT: CALL HEOUT
CALL SINP ;SEE IF A CHAR WAITING
JZ BOUT ;NO
ANI 7FH ;CLR PARITY FIRST THO
JZ COMND ;EITHER MODE OR CTRL-@
CPI ' ' ;IS IT A SPACE
JNZ BOUT ;NO...IGNORE THE CHAR
WTLP1: CALL SINP ;IF SPACE, WAIT UNTIL ANY OTHER KEY HIT
JZ WTLP1 ;THIS ALLOWS LOOKING AT THE DISPLAY
BOUT: MVI B,' '
JMP SOUT ;PUT IT OUT
;
HEOUT: MOV C,A ;GET THE CHARACTER
RRC ;MOVE THE HIGH FOUR DOWN
RRC
RRC
RRC
CALL HEOU1 ;PUT THEM OUT
MOV A,C ;THIS TIME THE LOW FOUR
;
HEOU1: ANI 0FH ;FOUR ON THE FLOOR
ADI 48 ;WE WORK WITH ASCII HERE
CPI 58 ;0-9?
JC OUTH ;YUP
ADI 7 ;MAKE IT A LETTER
OUTH: MOV B,A ;OUTPUT IT FROM REGISTER 'B'
JMP SOUT
;
;
; ***** ENTER COMMAND *****
;
; THIS ROUTINE GETS VALUES FROM THE KEYBOARD AND ENTERS
; THEM INTO MEMORY. THE INPUT VALUES ARE SCANNED FOLLOWING
; A STANDARD 'GCLIN' INPUT SO ON SCREEN EDITING MAY TAKE
; PLACE PRIOR TO THE LINE TERMINATOR. A BACK SLASH '/'
; ENDS THE ROUTINE AND RETURNS CONTROL TO THE COMMAND MODE.
; A COLON ':' SETS THE PREVIOUS VALUE AS A NEW ADDRESS FOR
; ENTRY.
;
ENTER: CALL SCONV ;SCAN OVER CHARS AND GET ADDRESS
PUSH H ;SAVE ADDRESS
XRA A
STA OPORT ;ENTER VALUES TO SCREEN BUFFER
;
ENLOP: CALL CRLF
MVI B,':'
CALL CONT ;GET LINE OF INPUT
CALL CREM ;REMOVE THE CURSOR
MVI C,1 ;START SCAN
CALL VDAD2 ;GET ADDRESS
XCHG ;....TO DE
;
;
ENLO1: MVI C,3 ;NO MORE THAN THREE SPACES BETWEEN VALUES
CALL SCHR1 ;SCAN TO NEXT VALUE
JZ ENLOP ;LAST ENTRY FOUND, START NEW LINE
;
CPI '/' ;COMMAND TERMINATOR
JZ COMN1 ;IF SO, RETURN TO STANDARD INPUT
CALL SHEX ;CONVERT VALUE
CPI ':' ;ADDRESS TERMINATOR
JZ ENLO3 ;GO PROCESS IF SO
MOV A,L ;GET LOW PART AS CONVERTED
POP H ;GET MEMORY ADDRESS
MOV M,A ;PUT IN THE VALUE
INX H
PUSH H ;BACK GOES THE ADDRESS
JMP ENLO1 ;CONTINUE THE SCAN
;
ENLO3: XTHL ;PUT NEW ADDRESS ON STACK
INX D ;MOVE SCAN PAST TERMINATOR
JMP ENLO1
;
;
; ***** EXECUTE COMMAND *****
;
; THIS ROUTINE GETS THE FOLLOWING PARAMETER AND DOES A
; PROGRAM JUMP TO THE LOCATION GIVEN BY IT. IF PROPER
; STACK OPERATIONS ARE USED WITHIN THE EXTERNAL PROGRAM
; IT CAN DO A STANDARD 'RET'URN TO THE SOLOS COMMAND MODE.
; THE STARTING ADDRESS OF SOLOS IS PASSED TO THE PROGRAM
; IN REGISTER PAIR HL SO IT CAN ADJUST INTERNAL PARAMETERS
; FOR SOLOS OPERATION.
;
;
EXEC: CALL SCONV ;SCAN PAST BLANKS AND GET PARAMETER
EXEC1: PUSH H ;PUT GO ADDRESS ON STACK
LXI H,START ;TELL THE PROGRAM WHERE WE CAME FROM
RET ;AND DISPATCH IT
;
;
; THIS ROUTINE GETS A NAME OF UP TO 5 CHARACTERS
; FROM THE INPUT STRING. IF THE TERMINATOR IS A
; SLASH (/) THEN THE CHARACTER FOLLOWING IS TAKEN
; AS THE CASSETTE UNIT SPECIFICATION.
;
;
NAMES: LXI H,THEAD ;POINT TO INTERNAL HEADER
NAME: CALL SBLK ;SCAN OVER TO FIRST CHRS
MVI B,6 ;UP TO SIX ARE ACCEPTED
;
NAME1: LDAX D ;GET CHARACTER
CPI ' ' ;NO UNIT DELIMITER
JZ NFIL
CPI '/' ;UNIT DELIMITER
JZ NFIL
MOV M,A
INX D ;BUMP THE SCAN POINTER
INX H
DCR B
JNZ NAME1 ;FALL THROUGH TO ERR1 IF TOO MANY CHRS IN NAME
;
;
; ***** SOLOS ERROR HANDLER *****
;
ERR1: XCHG ;GET SCAN ADDRESS TO HL
ERR2: MVI M,'?' ;PUT QUESTION MARK ON SCREEN
JMP COMN1 ;AND RETURN TO COMMAND MODE
;
;
; HERE WE HAVE SCANNED OFF THE NAME. ZERO FILL FOR
; NAMES LESS THAN FIVE CHARACTERS.
;
NFIL: MVI M,0 ;PUT IN AT LEAST ONE ZERO
INX H
DCR B
JNZ NFIL ;LOOP UNTIL B IS ZERO
;
CPI '/' ;IS THERE A UNIT SPECIFICATION?
MVI A,1 ;PRETEND NOT
JNZ DEFLT
INX D ;MOVE PAST THE TERMINATOR
CALL SCHR ;GO GET UNIT SPEC
SUI '0' ;REMOVE ASCII BIAS
;
DEFLT: EQU $ ;MOVE OVER TO INTERNAL REPRESENTATION
ANI 1 ;JUST BIT ZERO
MVI A,TAPE1 ;ASSUME TAPE ONE
JNZ STUNT ;IF NON-ZERO, ITS ONE
RAR
STUNT: STA FNUMF ;SET IT IN
RET
;
;
;
; THIS ROUTINE PROCESSES THE XEQ AND GET COMMANDS
;
;
TXEQ: DB 3EH ;THIS BEGINS "MVI A,0AFH"
TLOAD: XRA A ;A=0 MEANS TLOAD, ELSE TXEQ
PUSH PSW ;SAVE FLAG FOR LATER
LXI H,DHEAD ;PLACE DUMMY HEADER HERE
CALL NAME ;SET IN NAME AND UNIT
LXI H,0 ;PRETEND NO SECOND VALUE
CALL PSCAN ;GO GET THE ADDRESS (IF PRESENT)
;
TLOA2: XCHG ;PUT ADDRESS IN DE
LXI H,DHEAD ;POINT TO DUMMY HEADER WITH NAME TO LOAD
MOV A,M ;SEE IF A NAME WAS ENTERED
ORA A ;IS THERE A NAME?
JNZ TLOA3 ;YES...SEARCH FOR IT
LXI H,THEAD ;NO NAME, LOAD 1ST FILE
TLOA3: PUSH H ;SAVE PTR TO NAME TO LOAD
CALL ALOAD ;GET UNIT AND SPEED
POP H ;RESTORE PTR TO HDR TO LOAD
CALL RTAPE ;READ IN THE TAPE
JC TAERR ;TAPE ERROR?
;
CALL NAOUT ;PUT OUT THE HEADER PARAMETERS
POP PSW ;RESTORE FLAG FROM ORIGINAL ENTRY
ORA A
RZ ;AUTO XEQ NOT WANTED
LDA HTYPE ;CHECK TYPE
ORA A ;SET FLAGS
JM TAERR ;TYPE IS NOW XEQ
LDA THEAD+5 ;GET CHARACTER PAST NAME
ORA A
JNZ TAERR ;THE BYTE MUST BE ZERO FOR AUTO XEQ
LHLD XEQAD ;GET THE TAPE ADDRESS
JMP EXEC1 ;AND GO TO IT
;
;
; ***** GET COMMAND *****
;
; THIS ROUTINE IS USED TO SAVE PROGRAMS AND DATA ON
; THE CASSETTE UNIT
;
;
TSAVE: CALL NAMES ;GET NAME AND UNIT
CALL SCONV ;GET START ADDRESS
PUSH H ;USE THE STACK AS A REGISTER
CALL SCONV ;GET END ADDRESS
XTHL ;PUT END ON STACK, GET BACK START
PUSH H ;SAVE START ON TOP OF STACK
CALL PSCAN ;SEE IF OPTIONAL HEADER ADDRESS WAS GIVEN
SHLD LOADR ;PUT HEADER ADDRESS IN PLACE
;
POP H ;"FROM" ADDRESS TO HL
POP D ;GET BACK END ADDRESS
PUSH H ;SAVE FROM AGAIN FOR LATER
MOV A,E ;NOW CALCULATE SIZE
SUB L ;SIZE=END-START+1
MOV L,A
MOV A,D
SBB H
MOV H,A
INX H
SHLD BLOCK ;STORE THE SIZE
PUSH H ;SAVE IT FOR THE READ ALSO
;
CALL ALOAD ;GET UNIT AND SPEED
LXI H,THEAD ;POINT TO HEADER
CALL WHEAD ;AND WRITE IT OUT
; NOW WRITE OUT THE DATA
POP D ;GET SIZE TO DE
POP H ;GET BACK "FROM" ADDRESS
JMP WRLO1 ;WRITE OUT THE DATA AND RETURN
;
;
; OUTPUT ERROR AND HEADER
;
TAERR: CALL CRLF
MVI D,6
LXI H,ERRM ;POINT TO ERROR MESSAGE
CALL NLOOP ;OUTPUT ERROR
CALL NAOUT ;THEN THE HEADER
JMP COMN1 ;AND BE SURE THE TAPE UNITS ARE OFF
;
ERRM: DB 'ERROR '
;
;
; THIS ROUTINE READS HEADERS FROM THE TAPE AND OUTPUTS
; THEM TO THE OUTPUT DEVICE. IT CONTINUES UNTIL THE
; MODE KEY IS DEPRESSED.
;
TLIST: CALL NAMES ;SET UP UNIT IF GIVEN
CALL CRLF
;
;
LLIST: CALL ALOAD
MVI B,1
CALL TON ;TURN ON THE TAPE
;
LIST1: CALL RHEAD
JC COMN1 ;TURN OFF THE TAPE UNIT
JNZ LIST1
CALL NAOUT ;OUTPUT THE HEADER
JMP LIST1 ;LOOP UNTIL MODE IS DEPRESSED
;
;
; THIS ROUTINE GETS THE CASSETTE UNIT NUMBER AND
; SPEED TO REGISTER "A" FOR THE TAPE CALLS
;
ALOAD: LXI H,FNUMF ;POINT TO THE UNIT SPECIFICATION
LDA TSPD ;GET THE TAPE SPEED
ORA M ;PUT THEM TOGETHER
RET ;AND GO BACK
;
;
; THIS ROUTINE OUTPUTS THE NAME AND PARAMETERS OF
; THEAD TO THE OUTPUT DEVICE.
;
;
NAOUT: MVI D,8
LXI H,THEAD-1 ;POINT TO THE HEADER
CALL NLOOP ;OUTPUT THE HEADER
CALL BOUT ;ANOTHER BLANK
LHLD LOADR ;NOW THE LOAD ADDRESS
CALL ADOUT ;PUT IT OUT
LHLD BLOCK ;AND THE BLOCK SIZE
CALL ADOUT
JMP CRLF ;DO THE CRLF AND RETURN
;
;
NLOOP: MOV A,M ;GET CHARACTER
ORA A
JNZ CHRLI ;IF IT ISN'T A ZERO
MVI A,' '
CHRLI: CALL OUTH ;OUTPUT CHAR NOW
INX H
DCR D
JNZ NLOOP
RET
;
;
;
;
; ***** SET COMMAND *****
;
; THIS ROUTINE GETS THE ASSOCIATED PARAMETER AND
; DISPATCHES TO THE PROPER ROUTINE FOR SETTING
; GLOBAL VALUES.
;
CSET: EQU $ ;THIS IS THE SET COMMAND
CALL SBLK ;LOOK FOR SET NAME
JZ ERR1 ;MUST HAVE A LEAST SOMETHING!!
PUSH D ;SAVE SCAN ADDRESS
CALL SCONV ;CONVERT FOLLOWING VALUE
XTHL ;GET SCAN ADDR BACK...SAVE VALUE ON STACK
LXI D,SETAB ;SECONDARY COMMAND TABLE
CALL FDCOM ;SEE IF IN TABLE
JMP DISPO ;AND EITHER ERR OR OFF TO IT
;
;
; THIS ROUTINE SETS THE TAPE SPEED
;
TASPD: ORA A ;IS IT ZERO?
JZ SETSP ;YES...THAT'S A VALID SPEED
MVI A,32 ;SET TO SLOW IF NON-ZERO
SETSP: STA TSPD ;SPEED IS STORED HERE
RET
;
;
STSPD: MOV A,B ;ESCAPE COMES HERE TO SET SPEED
DISPD: STA SPEED ;SET DISPLAY SPEED
RET
;
; SET INPUT DRIVER
;
SETIN: EQU $
STA IPORT
RET
;
; SET OUTPUT DRIVER
;
SETOT: EQU $
STA OPORT
RET
;
; SET USERS CUSTOM INPUT DRIVER ADDRESS
;
SETCI: SHLD UIPRT
RET
;
; SET USERS CUSTOM OUTPUT DRIVER ADDRESS
;
SETCO: SHLD UOPRT
RET
;
; SET TYPE BYTE INTO HEADER
;
SETTY: STA HTYPE
RET
;
; SET EXECUTE ADDRESS INTO HEADER
;
SETXQ: SHLD XEQAD
RET
;
;
SETNU: STA NUCNT ;SET THE NULL COUNT
RET ;THAT'S DONE
;
;
SETCR: EQU $ ;SET TO IGNORE CRC ERRORS
STA IGNCR ;FF=IGNORE ERRORS, ELSE=NORMAL
RET
;
;
;
; CUSTOM COMMAND NAME AND ADDRESS INTO CUSTOM COMMAND
;
CUSET: CALL NAMES ;CUSTOM COMMAND ENTRY/REMOVAL
LXI H,COMND ;DEFAULT ADDR IF NONE GIVEN
CALL PSCAN ;GET RTN ADDRESS
PUSH H ;SAVE RTN ADDRESS
LXI H,THEAD ;POINT AT NAME TO SEARCH
CALL FDCOU ;SEARCH IT IN CUSTOM TABLE
JZ CUSE2 ;NOT IN TABLE...ENTER IT
DCX D ;IN TABLE, REMOVE IT
MVI M,0 ;CHANGE NEW NAME TO BE ZERO
CUSE2: MOV A,M ;GET 1ST CHAR OF NAME
STAX D ;ENTER IT INTO TABLE
INX D ;AND THE 2ND NAME
INX H
MOV A,M
STAX D ;NAME NOW ENTERED
INX D ;GET SET TO ENTER ADDRESS
POP H ;RESTORE RTN ADDR
XCHG
MOV M,E ;SET ADDR IN NOW
INX H ;AND HI BYTE OF ADDR
MOV M,D
RET ;NAME IS NOW ENTERED OR CLEARED
;
;
;
; THE FOLLOWING ROUTINES PROVIDE "BYTE BY BYTE" ACCESS
; TO THE CASSETTE TAPES ON EITHER A READ ORWRITE BASIS.
;
; THE TAPE IS READ ONE BLOCK AT A TIME AND INDIVIDUAL
; TRANSFERS OF DATA HANDLED BY MANAGING A BUFFER AREA.
;
; THE BUFFER AREA IS CONTROLLED BY A FILE CONTROL BLOCK
; (FCB) WHOSE STRUCTURE IS:
;
; 7 BYTES FOR EACH OF THE TWO FILES STRUCTURED AS
; FOLLOWS:
;
; 1 BYTE - ACCESS CONTROL 00 IF CLOSED
; FF IF READING
; FEIF WRITING
; 1 BYTE - READ COUNTER
; 1 BYTE - BUFFER POSITION POINTER
; 2 BYTE - CONTROL HEADER ADDRESS
; 2 BYTE - BUFFER LOCATION ADDRESS
;
;
;
; THIS ROUTINE "OPENS" THE CASSETTE UNIT FOR ACCESS
;
; ON ENTRY: A - HAS THE TAPE UNIT NUMBER (1 OR 2)
; HL - HAS USER SUPPLIED HEADER FOR TAPE FILE
;
;
; NORMAL RETURN: ALL REGISTERS ARE ALTERED
; BLOCK IS READY FOR ACCESS
;
; ERROR RETURN: CARRY BIT IS SET
;
; ERRORS: BLOCK ALREADY OPEN
;
;
BOPEN: PUSH H ;SAVE HEADER ADDRESS
CALL LFCB ;GET ADDRESS OF FILE CONTROL
JNZ TERE2 ;FILE WAS ALREADY OPEN
MVI M,1 ;NOW IT IS
INX H ;POINT TO READ COUNT
MOV M,A ;ZERO
INX H ;POINT TO BUFFER CURSOR
MOV M,A ;PUT IN THE ZERO COUNT
;
; ALLOCATE THE BUFFER
;
LXI D,FBUF1 ;POINT TO BUFFER AREA
LDA FNUMF ;GET WHICH ONE WE ARE GOING TO USE
ADD D
MOV D,A ;256 BIT ADD
;
UBUF: POP B ;HEADER ADDRESS
ORA A ;CLEAR CARRY AND RET AFTER STORING PARAMS
JMP PSTOR ;STORE THE VALUES
;
; GENERAL ERROR RETURN POINTS FOR STACK CONTROL
;
TERE2: POP H
TERE1: POP D
TERE0: XRA A ;CLEAR ALL FLAGS
STC ;SET ERROR
RET
;
;
EOFER: DCR A ;SET MINUS FLAGS
STC ;AND CARRY
POP D ;CLEAR THE STACK
RET ;THE FLAGS TELL ALL
;
;
;
;
; THIS ROUTINE CLOSES THE FILE BUFFER TO ALLOW ACCESS
; FOR A DIFFERENT CASSETTE OF PROGRAM. IF THE TILE
; OPERATIONS WERE "WRITE" THEN THE LAST BLOCK IS WRITTEN
; OUT AND AN "END OF FILE" WRITTEN TO THE TAPE. IF
; THE OPERATIONS WERE "READS" THEN THE FILE IS JUST
; MADE READY FOR NEW USE.
;
; ON ENTRY: A - HAS WHICH UNIT (1 OR 2)
;
; ERROR RETURNS: FILE WASN'T OPEN
;
;
PCLOS: CALL LFCB ;GET CONTROL BLOCK ADDRESS
RZ ;WASN'T OPEN, CARRY IS SET FROM LFCR
ORA A ;CLEAR CARRY
INR A ;SET CONDITION FLAGS
MVI M,0 ;CLOSE THE CONTROL BYTE
RZ ;WE WERE READING...NOTHING MORE TO DO
;
; THE FILE OPERATIONS WERE "WRITES"
;
; PUT THE CURRENT BLOCK ON THE TAPE
; (EVEN IF ONLY ONE BYTE)
; THEN WRITE AN END OF FILE TO THE TAPE
;
;
INX H
INX H
MOV A,M ;GET CURSOR POSITION
CALL PLOAD ;BC GET HEADER ADDRESS, DE BUFFER ADDRESS
PUSH B ;HEADER TO STACK
LXI H,BLKOF ;OFFSET TO BLOCK SIZE
DAD B
ORA A ;TEST COUNT
JZ EOFW ;NO BYTES...JUST WRITE EOF
;
; WRITE LAST BLOCK
;
PUSH H ;SAVE BLOCK SIZE POINTER FOR EOF
MOV M,A ;PUT IN COUNT
INX H
MVI M,0 ;ZERO THE HIGHER BYTE
INX H
MOV M,E ;BUFFER ADDRESS
INX H
MOV M,D
MOV H,B
MOV L,C ;PUT HEADER ADDRESS IN HL
CALL WFBLK ;GO WRITE IT OUT
POP H ;BLOCK SIZE POINTER
;
; NOW WRITE END OF FILE TO CASSETTE
;
EOFW: XRA A ;PUT IN ZEROS FOR SIZE
;EOF MARK IS ZERO BYTES!
MOV M,A
INX H
MOV M,A
POP H ;HEADER ADDRESS
JMP WFBLK ;WRITE IT OUT AND RETURN
;
;
;
;
; THIS ROUTINE LOCATES THE FILE CONTROL BLOCK POINTED TO
; BY REGISTER "A". ON RETURN HL POINTS TO THE CONTROL BYTE
; AND REGISTER "A" HAS THE CONTROL WORD WITH THE FLAGS
; SET FOR IMMEDIATE CONDITION DECISIONS.
;
;
LFCB: LXI H,FCBAS ;POINT TO THE BASE OF IT
RAR ;MOVE THE 1 & 2 TO 0 & 1
ANI 1 ;SMALL NUMBERS ARE THE RULE
STA FNUMF ;CURRENT ACCESS FILE NUMBER
JZ LFCB1 ;UNIT ONE (VALUE OF ZERO)
LXI H,FCBA2 ;UNIT TWO--POINT TO ITS FCB
LFCB1: EQU $ ;HL POINT TO PROPER FCB
MOV A,M ;PICK UP FLAGS FROM FCB
ORA A ;SET FLAGS BASED ON CONTROL WORD
STC ;SET CARRY IN CASE OF IMMEDIATE ERROR RET
RET
;
;
;
;
; READ TAPE BYTE ROUTINE
;
; ENTRY: - A - HAS FILE NUMBER
; EXIT: NORMAL - A - HAS BYTE
; ERROR
; CARRY SET - IF FILE NOT OPEN OR
; PREVIOUS OPERATIONS WERE WRITE
; CARRY & MINUS - END OF FILE ENCOUNTERED
;
;
;
;
RTBYT: CALL LFCB ;LOCATE THE FILE CONTROL BLOCK
RZ ;FILE NOT OPEN
INR A ;TEST IF FF
JM TERE0 ;ERROR WAS WRITING
MVI M,(-1) AND 0FFH ;SET IT AS READ (IN CASE IT WAS JUST OPENED)
INX H
MOV A,M ;GET READ COUNT
PUSH H ;SAVE COUNT ADDRESS
INX H
CALL PLOAD ;GET THE OTHER PARAMETERS
POP H
ORA A
JNZ GTBYT ;IF NOT EMPTY GO GET BYTE
;
; CURSOR POSITION WAS ZERO...READ A NEW BLOCK
; INTO THE BUFFER.
;
RDNBLK: PUSH D ;BUFFER POINTER
PUSH H ;TABLE ADDRESS
INX H
CALL PHEAD ;PREPARE THE HEADER FOR READ
CALL RFBLK ;READ IN THE BLOCK
JC TERE2 ;ERROR POP OFF STACK BEFORE RETURN
POP H
MOV A,E ;LOW BYTE OF COUNT (WILL BE ZERO IF 256)
ORA D ;SEE IF BOTH ARE ZERO
JZ EOFER ;BYTE COUNT WAS ZERO...END OF FILE
MOV M,E ;NEW COUNT (ZERO IS 256 AT THIS POINT)
INX H ;BUFFER LOCATION POINTER
MVI M,0
DCX H
MOV A,E ;GET BACK BUFFER ADDRESS
POP D
;
;
;
; THIS ROUTINE GETS ONE BYTE FROM THE BUFFER
; AND RETURNS IT IN REGISTER "A". IF THE END
; OF THE BUFFER IS REACHED IT MOVES THE POINTER
; TO THE BEGINNING OF THE BUFFER FOR THE NEXT
; LOAD.
;
GTBYT: DCR A ;BUMP THE COUNT
MOV M,A ;RESTORE IT
INX H
MOV M,A ;GET BUFFER POSITION
INR M ;BUMP IT
;
ADD E
MOV E,A ;DE NOW POINT TO CORRECT BUFFER POSITION
JNC RT1
INR D
RT1: LDAX D ;GET CHARACTER FROM BUFFER
ORA A ;CLEAR CARRY
RET ;ALL DONE
;
;
;
; THIS ROUTINE IS USED TO WRITE A BYTE TO THE FILE
;
; ON ENTRY: A - HAS FILE NUMBER
; B - HAS DATA BYTE
;
;
WTBYT: CALL LFCB ;GET CONTROL BLOCK
RZ ;FILE WASN'T OPEN
INR A
RZ ;FILE WAS READ
MVI M,0FEH ;SET IT TO WRITE
INX H
INX H
MOV A,B ;GET CHARACTER
PUSH PSW
PUSH H ;SAVE CONTROL ADDRESS+2
;
; NOW DO THE WRITE
;
CALL PLOAD ;BC GETS HEADER ADDR
;DE BUFFER ADDRESS
POP H
MOV A,M ;COUNT BYTE
ADD E
MOV E,A
JNC WT1
INR D
WT1: POP PSW ;CHARACTER
STAX D ;PUT CHR IN BUFFER
ORA A ;CLEAR FLAGS
INR M ;INCREMENT THE COUNT
RNZ ;RETURN IF COUNT DIDN'T ROLL OVER
;
; THE BUFFER IS FULL. WRITE IT TO TAPE
; AND RESET CONTROL BLOCK.
;
CALL PHEAD ;PREPARE THE HEADER
JMP WFBLK ;WRITE IT OUT AND RETURN
;
;
;
;
; THIS ROUTINE PUTS THE BLOCK SIZE (256) AND BUFFER
; ADDRESS IN THE FILE HEADER.
;
PHEAD: CALL PLOAD ;GET HEADER AND BUFFER ADDRESSES
PUSH B ;HEADER ADDRESS
LXI H,BLKOF-1 ;PSTOR DOES AN INCREMENT
DAD B ;HL POINTS TO BLOCKSIZE ENTRY
LXI B,256
CALL PSTOR
POP H ;HL RETURN WITH HEADER ADDRESS
RET
;
;
PSTOR: INX H
MOV M,C
INX H
MOV M,B
INX H
MOV M,E
INX H
MOV M,D
RET
;
;
PLOAD: INX H
MOV C,M
INX H
MOV B,M
INX H
MOV E,M
INX H
MOV D,M
RET
;
;
;
;
;THIS ROUTINE SETS THE CORRECT UNIT FOR SYSTEM READS
;
RFBLK: CALL GTUNT ;SET UP A=UNIT WITH SPEED
;
;
; ***** TAPE READ ROUTINES *****
;
; ON ENTRY: A - HAS UNIT AND SPEED
; HL - POINTS TO HEADER BLOCK
; DE - HAS OPTIONAL PUT ADDRESS
;
; ON EXIT: CARRY IS SET IF ERROR OCCURED
; TAPE UNITS ARE OFF
;
;
RTAPE: PUSH D ;SAVE OPTIONAL ADDRESS
MVI B,3 ;SHORT DELAY
CALL TON
IN TDATA ;CLEAR THE UART FLAGS
;
PTAP1: PUSH H ;HEADER ADDRESS
CALL RHEAD ;GO READ HEADER
POP H
JC TERR ;IF AN ERROR OR ESC WAS RECEIVED
JNZ PTAP1 ;IF VALID HEADER NOT FOUND
;
; FOUND A VALID HEADER NOW DO COMPARE
;
PUSH H ;GET BACK AND RESAVE ADDRESS
LXI D,THEAD
CALL DHCMP ;COMPARE DE/HL HEADERS
POP H
JNZ PTAP1
;
;
POP D ;OPTIONAL "PUT" ADDRESS
MOV A,D
ORA E ;SEE IF DE IS ZERO
LHLD BLOCK ;GET BLOCK SIZE
XCHG ;....TO DE
; DE HAS HBLOCK...HL HAS USER OPTION
JNZ RTAP ;IF DE WAS 0 GET TAPE LOAD ADDR
LHLD LOADR ;GET TAPE LOAD ADDRESS
;
;
; THIS ROUTINE READS "DE" BYTES FROM THE TAPE
; TO ADDRESS HL. THE BYTES MUST BY FROM ONE
; CONTIGUOUS PHYSICAL BLOCK ON THE TAPE.
;
; HL HAS "PUT" ADDRESS
; DE HAS SIZE OF TAPE BLOCK
;
RTAP: PUSH D ;SAVE SIZE FOR RETURN TO CALLING PROGRAM
;
RTAP2: EQU $ ;HERE TO LOOP RDING BLKS
CALL DCRCT ;DROP COUNT, B=LEN THIS BLOCK
JZ RTOFF ;ZERO=ALL DONE
;
CALL RHED1 ;READ THAT MANY BYTES
JC TERR ;IF ERROR OR ESC
JZ RTAP2 ;RD OK...READ SOME MORE
;
; ERROR RETURN
;
TERR: XRA A
STC ;SET ERROR FLAGS
JMP RTOF1
;
;
TOFF: MVI B,1
CALL DELAY
RTOFF: XRA A
RTOF1: OUT TAPPT
POP D ;RETURN BYTE COUNT
RET
;
;
DCRCT: EQU $ ;COMMON RTN TO COUNT DOWN BLK LENGTHS
XRA A ;CLR FOR LATER TESTS
MOV B,A ;SET THIS BLK LEN = 256
ORA D ;IS ANMT LEFT < 256
JNZ DCRC2 ;NO...REDUCE AMNT BY 256
ORA E ;IS ENTIRE COUNT ZERO
RZ ;ALL DONE..ZERO=THIS CONDITION
MOV B,E ;SET THIS BLK LEN TO AMNT REMAINING
MOV E,D ;MAKE ENTIRE COUNT ZERO NOW
RET ;ALL DONE (NON-ZERO FLAG)
DCRC2: EQU $ ;REDUCE COUNT BY 256
DCR D ;DROP BY 256
ORA A ;FORCE NON-ZERO FLAG
RET ;NON-ZERO=NOT DONE YET (BLK LEN=256)
;
;
; READ THE HEADER
;
RHEAD: MVI B,10 ;FIND 10 NULLS
RHEA1: CALL STAT
RC ;IF ESCAPE
IN TDATA ;IGNORE ERROR CONDITIONS
ORA A ;ZERO?
JNZ RHEAD
DCR B
JNZ RHEA1 ;LOOP UNTIL 10 IN A ROW
;
; WAIT FOR THE START CHARACTER
;
SOHL: CALL TAPIN
RC ;ERROR OR ESCAPE
CPI 1 ;AT LEAST 10 NULLS FOLLOWED BY A 01
JC SOHL ;STILL A NULL, KEEP WAITING
JNZ RHEAD ;NON-ZERO, START SEQUENCE OVER AGAIN
;
; NOW GET THE HEADER
;
LXI H,THEAD ;POINT TO BUFFER
MVI B,HLEN ;LENGTH TO READ
;
RHED1: EQU $ ;RD A BLOCK INTO HL FOR B BYTES
MVI C,0 ;INITALIZE THE CRC
RHED2: EQU $ ;LOOP HERE
CALL TAPIN ;GET A BYTE
RC
MOV M,A ;STORE IT
INX H ;INCREMENT ADDRESS
CALL DOCRC ;GO COMPUTE THE CRC
DCR B ;WHOLE HEADER YET?
JNZ RHED2 ;DO ALL THE BYTES
;
; THIS ROUTINE GETS THE NEXT BYTE AND COMPARES IT
; TO THE VALUE IN REGISTER C. THE FLAGS ARE SET ON
; RETURN.
;
CALL TAPIN ;GET CRC BYTE
XRA C ;CLR CARRY AND SET ZERO IF MATCH
; ELSE NON-ZERO
RZ ;CRC WAS FINE
LDA IGNCR ;GET POSSIBLE OVERRIDE CRC ERROR FLAG
INR A ;FF=IGNORE CRC ERRORS
RET ;ELSE PROCESS CRC ERROR
;
;
; THIS ROUTINE GETS THE NEXT AVAILABLE BYTE FROM THE
; TAPE. WHILE WAITING FOR THE BYTE THE KEYBOARD IS TESTED
; FOR AN ESC COMMAND. IF RECEIVED THE TAPE LOAD IS
; TERMINATED AND A RETURN TO THE COMMAND MODE IS MADE.
;
STAT: IN TAPPT ;TAPE STATUS PORT
ANI TDR
RNZ
CALL SINP ;CHECK INPUT
JZ STAT ;NOTHING THERE YET
ANI 7FH ;CLR PARITY FIRST
JNZ STAT ;NOT A MODE (OR EVEN CTRL-@)
STC ;SET ERROR FLAG
RET ;AND RETURN
;
;
;
TAPIN: CALL STAT ;WAIT UNTIL A CHARACTER IS AVAILABLE
RC
;
TREDY: IN TAPPT ;TAPE STATUS
ANI TFE+TOE ;DATA ERROR?
IN TDATA ;GET THE DATA
RZ ;IF NO ERRORS
STC ;SET ERROR FLAG
RET
;
;
; THIS ROUTINE GETS THE CORRECT UNIT FOR SYSTEM WRITES
;
WFBLK: CALL GTUNT ;SET UP A WITH UNIT AND SPEED
;
;
; ***** WRITE TAPE BLOCK ROUTINE *****
;
; ON ENTRY: A - HAS UNIT AND SPEED
; HL - HAS POINTER TO HEADER
;
;
WTAPE: EQU $ ;HERE TO WRITE TAPE
PUSH H ;SAVE HEADER ADDRESS
CALL WHEAD ;TURN ON, THEN WRITE HEADER
POP H
LXI D,BLKOF ;OFFSET TO BLOCK SIZE IN HEADER
DAD D ;HL POINT TO BLOCK SIZE
MOV E,M
INX H
MOV D,M ;DE HAS SIZE
INX H
MOV A,M
INX H
MOV H,M
MOV L,A ;HL HAS STARTING ADDRESS
;
; THIS ROUTINE WRITES ONE PHYSICAL BLOCK ON THE
; TAPE "DE" BYTES LONG FROM ADDRESS "HL".
;
;
WRLO1: EQU $ ;HERE FOR THE EXTRA PUSH
PUSH H ;A DUMMY PUSH FOR LATER EXIT
WTAP2: EQU $ ;LOOP HERE UNTIL ENTIRE AMOUNT READ
CALL DCRCT ;DROP COUNT IN DE AND SET UP B
;WITH LENGTH THIS BLOCK
JZ TOFF ;RETURNS ZERO IF ALL DONE
CALL WTBL ;WRITE BLOCK FOR BYTES IN B (256)
JMP WTAP2 ;LOOP UNTIL ALL DONE
;
;
WRTAP: PUSH PSW
WRWAT: IN TAPPT ;TAPE STATUS
ANI TTBE ;IS TAPE READY FOR A CHAR YET
JZ WRWAT ;NO...WAIT
POP PSW ;YES...RESTORE CHAR TO OUTPUT
OUT TDATA ;SEND CHAR TO TAPE
;
DOCRC: EQU $ ;A COMMON CRC COMPUTATION ROUTINE
SUB C
MOV C,A
XRA C
CMA
SUB C
MOV C,A
RET ;ONE BYTE NOW WRITTEN
;
;
; THIS ROUTINE WRITES THE HEADER POINTED TO BY
; HL TO THE TAPE.
;
WHEAD: EQU $ ;HERE TO FIRST TURN ON THE TAPE
CALL WTON ;TURN IT ON, THEN WRITE HEADER
MVI D,50 ;WRITE 50 ZEROS
NULOP: XRA A
CALL WRTAP
DCR D
JNZ NULOP
;
MVI A,1
CALL WRTAP
MVI B,HLEN ;LENGTH TO WRITE OUT
;
WTBL: MVI C,0 ;RESET CRC BYTE
WLOOP: MOV A,M ;GET CHARACTER
CALL WRTAP ;WRITE IT TO THE TAPE
DCR B
INX H
JNZ WLOOP
MOV A,C ;GET CRC
JMP WRTAP ;PUT IT ON THE TAPE AND RETURN
;
;
; THIS ROUTINE COMPARES THE HEADER IN THEAD TO
; THE USER SUPPLIED HEADER IN ADDRESS HL.
; ON RETURN IF ZERO IS SET THE TWO NAMES COMPARED
;
DHCMP: MVI B,5
DHLOP: LDAX D
CMP M
RNZ
DCR B
RZ ;IF ALL FIVE COMPARED
INX H
INX D
JMP DHLOP
;
GTUNT: EQU $ ;SET A=SPEED + UNIT
LDA FNUMF ;GET UNIT
ORA A ;SEE WHICH UNIT
LDA TSPD ;BUT FIRST GET SPEED
JNZ GTUN2 ;MAKE IT UNIT TWO
ADI TAPE2 ;THIS ONCE=UNIT 2, TWICE=UNIT 1
GTUN2: ADI TAPE2 ;UNIT AND SPEED NOW SET IN A
RET ;ALL DONE
;
WTON: MVI B,4 ;SET LOOP DELAY, (BIT LONGER ON WRITE)
TON: EQU $ ;HERE TO TURN A TAPE ON THEN DELAY
OUT TAPPT ;GET TAPE MOVING, THEN DELAY
;
DELAY: LXI D,0
DLOP1: DCX D
MOV A,D
ORA E
JNZ DLOP1
DCR B
JNZ DELAY
RET
;
;
;********* END OF PROGRAM ************
;
;
;
;
;
; SOL SYSTEM EQUATES
;
;
; VDM PARAMETERS
;
VDMEM EQU 0CC00H ;VDM SCREEN MEMORY
HIBYTE EQU 0CCH ;MEMORY HIGH BYTE
;
;
; KEYBOARD SPECIAL KEY ASSIGNMENTS
;
DOWN EQU 9AH
UP EQU 97H
LEFT EQU 81H
RIGHT EQU 93H
MODE EQU 80H
CLEAR EQU 8BH
HOME EQU 08EH
BACKS EQU 5FH ;BACKSPACE
LF EQU 10
CR EQU 13
BLANK EQU ' '
SPACE EQU BLANK
CX EQU 'X'-40H
ESC EQU 1BH
;
; PORT ASSIGNMENTS
;
STAPT EQU 0FAH ;STATUS PORT GENERAL
SERST EQU 0F8H ;SERIAL STATUS PORT
SDATA EQU 0F9H ;SERIAL DATA
TAPPT EQU 0FAH ;TAPE STATUS PORT
TDATA EQU 0FBH ;TAPE DATA
KDATA EQU 0FCH ;KEYBOARD DATA
PDATA EQU 0FDH ;PARALLEL DATA
DSTAT EQU 0FEH ;VDM DISPLAY PARAMETER PORT
SENSE EQU 0FFH ;SENSE SWITCHES
;
;
; BIT ASSIGNMENT MASKS
;
SCD EQU 1 ;SERIAL CARRIER DETECT
SDSR EQU 2 ;SERIAL DATA SET READY
SPE EQU 4 ;SERIAL PARITY ERROR
SFE EQU 8 ;SERIAL FRAMING ERROR
SOE EQU 16 ;SERIAL OVERRUN ERROR
SCTS EQU 32 ;SERIAL CLEAR TO SEND
SDR EQU 64 ;SERIAL DATA READY
STBE EQU 128 ;SERIAL TRANSMITTER BUFFER EMPTY
;
KDR EQU 1 ;KEYBOARD DAYA READY
PDR EQU 2 ;PARALLEL DATA READY
PXDR EQU 4 ;PARALLEL DEVICE READY
TFE EQU 8 ;TAPE FRAMING ERROR
TOE EQU 16 ;TAPE OVERRUN ERROR
TDR EQU 64 ;TAPE DATA READY
TTBE EQU 128 ;TAPE TRANSMITTER BUFFER EMPTY
;
SOK EQU 1 ;SCROLL OK FLAG
;
TAPE1 EQU 80H ;1=TURN TAPE ONE ON
TAPE2 EQU 40H ;1=TURN TAPE TWO ON
;
;
;
; SOL SYSTEM GLOBAL AREA
;
ORG 0C800H ;START OF 1K RAM AREA
;
SYSRAM EQU $ ;START OF SYSTEM RAM
SYSTP EQU $+1024 ;STACK IS AT THE TOP
;
;
; ***** PARAMETERS STORED IN RAM *****
;
UIPRT DS 2 ;USER DEFINED INPUT RTN IF NON-ZERO
UOPRT DS 2 ;USER DEFINED OUTPUT RTN IF NON-ZERO
DFLTS DS 2 ;DEFAULT PSUEDO I/O PORTS
; (ALWAYS ZERO IN SOLOS)
IPORT DS 1 ;CRNT INPUT PSEUDO PORT
OPORT DS 1 ;CRNT OUTPUT PSEUDO PORT
NCHAR DS 1 ;CURRENT CHARACTER POSITION
LINE DS 1 ;CURRENT LINE POSITION
BOT DS 1 ;BEGINNING OF TEXT DISPLACEMENT
SPEED DS 1 ;SPEED CONTROL BYTE
ESCFL DS 1 ;ESCAPE FLAG CONTROL BYTE
TSPD DS 1 ;CURRENT TAPE SPEED
INPTR DS 2 ;FOR COMPATABILITY W/CUTER
NUCNT DS 1 ;NUMBER OF NULLS AFTER CRLF
IGNCR DS 1 ;FF=IGNORE CRC ERRORE, ELSE NORMAL
;
DS 10 ;ROOM FOR FUTURE EXPANSION
;
;
; THIS IS THE HEADER LAYOUT
;
THEAD DS 5 ;NAME
DS 1 ;THIS BYTE MUST BE ZERO
HTYPE DS 1 ;TYPE
BLOCK DS 2 ;BLOCK SIZE
LOADR DS 2 ;LOAD ADDRESS
XEQAD DS 2 ;AUTO-EXECUTE ADDRESS
HSPR DS 3 ;SPARES
;
HLEN EQU $-THEAD ;LENGTH OF HEADER
BLKOF EQU BLOCK-THEAD ;OFFSET TO BLOCK SIZE
DHEAD DS HLEN ;A DUMMY HDR FOR COMPARES WHILE RDING
;
;
CUTAB DS 6*4 ;ROOM FOR UP TO 6 CUSTOM USER COMMANDS
;
;
FNUMF DS 1 ;FOR CURRENT FILE OPERATIONS
FCBAS DS 7 ;1ST FILE CONTROL BLOCK
FCBA2 DS 7 ;2ND FILE CONTROL BLOCK
FBUF1 DS 2*256 ;SYSTEM FILE BUFFER BASE
DS 81 ;THIS IS AN AREA USED BY CUTER
USARE EQU $ ;START OF USER AREA *****************
; REMEMBER THAT THE STACK WORKS ITS WAY DOWN FROM
; THE END OF THIS 1K RAM AREA.
;
;
;
END