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
/
CPMUG023.ARK
/
KERNEL.ASM
< prev
next >
Wrap
Assembly Source File
|
1985-07-13
|
39KB
|
2,344 lines
;INTEL 8080 STOIC KERNEL
;J. SACHS 3/24/77
;
;***************************************************************************
;** COPYRIGHT (C) MASSACHUSETTS INSTITUTE OF TECHNOLOGY AND HARVARD **
;** UNIVERSITY, BIOMEDICAL ENGINEERING CENTER 1977. ALL RIGHTS RESERVED. **
;***************************************************************************
;
;ASSY TIME PARAMETERS
BCKSP EQU 0 ;TTY = -1 FOR A TERMINAL WITH BACKSPACE
;TTY = 0 FOR A TERMINAL WITHOUT BACKSPACE
TABS EQU 0 ;TABS = -1 FOR A TERMINAL WITH HARDWARE TABS
;TABS = 0 FOR A TERMINAL WITHOUT HARDWARE TABS
DISK EQU -1 ;DISK = 0 FOR TAPE
;DISK = -1 FOR DISK
DEBUG EQU -1 ;DEBUG = 0 FOR NO ERROR CHECKING
;DEBUG = -1 FOR ERROR CHECKING
CPM EQU -1 ;CPM = -1 FOR A CPM COMPATABLE KERNEL
;CPM = 0 FOR ORGINAL KERNEL
;LOCATIONS OF I/O ROUTINES IN BOOT ROM
;
IF (DISK) AND (NOT CPM)
Q$TTYI EQU 01F4H ;TTY INPUT ROUTINE
Q$TTYO EQU Q$TTYI+3 ;TTY OUTPUT ROUTINE
DSKIN EQU Q$TTYO+3 ;DISK INPUT ROUTINE
DSKOU EQU DSKIN+3 ;DISK OUTPUT ROUTINE
BSIZE EQU 1000Q ;DISK BLOCK SIZE (BYTES)
NBLKS EQU 1000Q ;NUMBER OF DISK BLOCKS
ENDIF
IF (NOT DISK) AND (NOT CPM)
DSKIN EQU 201DH
DSKOU EQU 2018H
BSIZE EQU 2000Q
NBLKS EQU 1000Q
ENDIF
;PARAMETER DEFINITIONS
;
IF NOT CPM
SSIZE EQU 256 ;MAIN STACK SIZE
RSIZE EQU 64 ;RETURN STACK SIZE
LSIZE EQU 64 ;LOOP STACK SIZE
VSIZE EQU 8 ;VOCABULARY STACK SIZE
KSIZE EQU 82 ;KEYBOARD BUFFER SIZE
CSIZE EQU 256 ;COMPILE BUFFER SIZE
;RESTART JUMPS
ORG 2000H
JMP ABORT ;RESTART 0
JMP 0 ;RESTART 1
JMP 0 ;RESTART 2
JMP 0 ;RESTART 3
JMP 0 ;RESTART 4
JMP 0 ;RESTART 5
JMP 0 ;RESTART 6
JMP 0 ;RESTART 7
ENDIF
;
IF (NOT DISK) AND (NOT CPM)
ORG 2400H
;DEFINE TTY ADDRESSES
TTYISR EQU 0E001H ;TTY INPUT STATUS REGISTER
TTYOSR EQU 0E002H ;TTY OUTPUT STATUS REGISTER
TTYIDR EQU 0E003H ;TTY INPUT DATA REGISTER
TTYODR EQU 0E004H ;TTY OUTPUT DATA REGISTER
;GET CHAR FROM TTY
Q$TTYI: LDA TTYISR
ORA A
JP Q$TTYI
LDA TTYIDR
ANI 177Q
RET
;TYPE A CHARACTER ON TTY
Q$TTYO: PUSH PSW
TTYO1: LDA TTYOSR
ORA A
JP TTYO1
POP PSW
STA TTYODR
RET
ENDIF
;
;/////////////////////////////////////////////////////////////////////
;
;DATE 2/21/78
;
;
;ROUTINE: CPMKER
;PURP: ALTERNATIONS TO STOIC KERNEL TO RUN UNDER CPM
;ENTRY: SET CPM ASSEMBLY TIME PARAMETER TO -1=TRUE
;EXIT: ADDITIONAL ROUTINES ARE INSERTED INTO THE KERNEL TO
; INTERFACE TO CPM
; 1) TTYIN
; 2) TTYOUT
; 3) DISKIN
; 4) DISKOUT IS NOT IMPLEMENTED AT THIS TIME
; 5) RD15 MODIFIED TO IGNORE LINE FEED CHARACTERS
; 6) CPMLD COMMAND IMPLEMENTED TO READ IN STOIC SOURCE
; FILES FROM A CPM DISK
; TO USE TYPE
; 'NAME CPMLD
; NOTE THE NAME IS ONLY THE FIRST NAME AND NOT THE EXTENSION
; WHICH IS ASSUMED TO BE "STC"
; 7) RETCPM COMMAND WHICH WILL REBOOT CPM
; 8) ALSO THE MEMORY WILL BE SET EACH TIME STOIC IS BROUGHT UP
; TO THE VALUE @ LOCATION 6 = ADDRESS OF THE BASE OF BDOS
; 9) SZSTOIC COMPUTES THE # OF 256 BYTE PAGES USED BY STOIC
; USED FOR SAVING STOIC
; 10)CHANGES TO THE ORGINAL KERNEL SO THE KERNEL WILL
; ASSEMBLE USING "ASM"
; A) ALL ? CHANGED TO Q$
; B) ALL MVI A,-1 CHANGED TO MVI A,0FFH
; C) ALL MVI M,-1 CHANGED TO MVI M,OFFH
;
;
;/////////////////////////////////////////////////////////////////
;
;
IF CPM
;
;BLOCK DEFINITIONS
;
BSIZE EQU 400H ;SIZE OF DISK BLOCK
NBLKS EQU 77*26*128/BSIZE ;77 TRACKS
;26 SECTORS PER TRACK
;128 BYTES PER SECTOR
;NUMBER OF BLOCKS
;
;
;PARAMETER DEFINITIONS
SSIZE EQU 256 ;MAIN STACK SIZE
RSIZE EQU 64 ;RETURN STACK SIZE
LSIZE EQU 64 ;LOOP STACK SIZE
VSIZE EQU 8 ;VOCABULARY STACK SIZE
KSIZE EQU 82 ;KEYBOARD BUFFER SIZE
CSIZE EQU 256 ;COMPILE BUFFER SIZE
ORG 100H
;
;ENTER STOIC
TPA: LXI SP,SSTACK ;SET NEW STACK POINTER
;
; PICK UP SIZE OF AVAIL MEMORY
LHLD BDOS+1 ;GET BEGINING OF BDOS
SHLD Q$MEMO ;STORE IN MEMORY LOCATION
JMP ABORT ;ENTER STOIC
;
;
; BDOS AND IO EQUATES
;
BDOS EQU 5 ;ADDRESS OF JMP TO BDOS
CONO EQU 9 ;DISPLACEMENT TO CONOUT ROUTINE
CONI EQU 6 ;INDEX INTO CONSOLE CBIOS ROUTINE
BASEIOS EQU 1 ;LOCATION 1 HAS BASE OF IOS
SELDSK EQU 14 ;SELECT THE DISK
OPENCPM EQU 15 ;OPEN A CPM FILE
RDNXTREC EQU 20 ;READ NEXT SECTOR
CPMFCB EQU 5CH ;DEFUALT FILE CONTROL BLOCK
SETDMA EQU 26 ;SET DMA ADDRESS
;
;
;
;TTYIN
Q$TTYI: LHLD BASEIOS ;GET ADDRESS OF IOS
LXI D,CONI
DAD D
PCHL ;JMP TO ROUTINE
;
;
;TTY OUT
Q$TTYO: ANI 7FH ;CLEAR MSB
MOV C,A ;PLACE IN REG C
LHLD BASEIOS ;GET BASE OF IOS TABLE
LXI D,CONO
DAD D ;HL=ADDRESS OF CONSOLE OUT ROUTINE
PCHL ;JMP TO CONO
;
;
;DISK OUTPUT ROUTINE PRESENTLY CAUSES A ERROR
DSKOU: MVI A,1
RET
;
;DISK INPUT ROUTINE
;PURP: INPUT A BLOCK OF DATA [8 SECTORS ] FROM A CPM FILE
;ENTRY: HL=BLOCK# IN LOWER 9 BITS [DISCARDED]
; THE 10,AND 11 BITS [BIT 1,2 OF HL] = THE UNIT
;EXIT: A=0 IF GOOD READ ELSE A=1
;
;PROCEDURE
;
;
;SET THE DMA ADDRESS TO POINT TO THE BUFFER
; AND READ 8 SECTORS
DSKIN: MVI B,BSIZE/128
NXTSEC: PUSH B ;SAVE COUNT
PUSH D ;SAVE DMA ADDRESS
MVI C,SETDMA
CALL BDOS ;SET THE DMA ADDRESS
LXI D,CPMFCB
MVI C,RDNXTREC ;READ THE NEXT RECORD
CALL BDOS ;READ THE SECTOR
POP D
POP B ;RETRIEVE POINTERS
ORA A ;SET FLAGS RETURNED FROM THE READ OPERATION
JZ NXTSECCONT
DCR A ;IF ERROR WAS END OF FILE IGNORE
RET ;IF ERROR WAS A 2 RET WITH ERROR 1
;
NXTSECCONT:
LXI H,128 ;
DAD D
XCHG ;DE=NEXT DMA LOCATION
DCR B
JNZ NXTSEC
RET
;
;
;/////////////////////////////////////////////////
;
;
;ROUTINE: RET TO CPM
;PRUP: RETURN TO CPM
;ENTRY: NONE
;EXIT: NONE
;PROCEDURE
;
DB 6,'RETCP'
DW 0
DW $+2
Q$RETCPM: LHLD BASEIOS
PCHL ;DO A WARM BOOT
;
;
;//////////////////////////////////////////////////
;
;
;
;ADDITIONAL WORDS TO IMPLEMENT FILE READING
;
;
;//////////////////////////////////////////////////
;
;ROUTINE: 0FCB
;PURP: FILL A CPM FCB WITH ZERO'S
;ENTRY: TOS=FCB ADDRESS
;EXIT: TOS=DELETED
;PROCEDURE
;
DB 4,'0FCB'
DW Q$RETCPM
DW $+2
Q$0FCB: POP H ;FETCH FCB ADDRESS
MVI B,33
Q$0FCB1:
MVI M,0
INX H
DCR B
JNZ Q$0FCB1 ;JIF NOT DONE
JMP Q$NEXT
;
;///////////////////////////////////////////////////////////
;
;
;
;OPFILE
;PURP: OPEN A CPM FILE
;ENTRY: TOS=FCB ADDRESS
;EXIT: TOS=0 IF OK
; TOS=-1 IF ERROR
;PROCEDURE
DB 6,'OPFIL'
DW Q$0FCB
DW $+2
Q$OPFILE: LDA Q$UNIT ;GET THE UNIT
MOV E,A
MVI C,SELDSK
CALL BDOS
POP D ;GET FCB ADDRESS
MVI C,OPENCPM
CALL BDOS ;OPEN FILE
INR A
JNZ Q$NEXT ;JIF NO ERRORS
LXI H,OPENERR
JMP ERROR
;
;OPEN ERROR MESSAGE
OPENERR: DB 15,'OPEN FILE ERROR',0
;
;
;
;////////////////////////////////////////
;
;ROUTINE DFTFCB
;PURP: PUSH THE ADDRESS OF THE DEFUALT ON TO THE TOS
;ENTRY: NONE
;EXIT: TOS=DEFUALT FCB
;PROCEDURE
;
DB 6,'DFTFC' ;DEFUALT FCB
DW Q$OPFILE
DW Q$CONS
Q$DFTFCB: DW CPMFCB
;
;//////////////////////////////////////////////
;
;ROUTINE: STORE A FILE NAME IN THE FCB
;PURP:
;ENTRY: TOS=FCB,NAME
;EXIT: TOS=DELETED
;PROCEDURE
;
DB 6,'STNAM' ;STORENAME
DW Q$DFTFCB
DW $+2
Q$STNAME: POP D ;GET DESTINATION
POP H ;GET SOURCE
MOV A,M ;GET LENGTH OF SOURCE
MOV B,A ;PLACE IN B
CPI 9 ;TEST FOR PROPER LENGTH
JC STN1 ;JIF OK
LXI H,BADNAME ;ELSE ERROR EXIT
JMP ERROR
;
;FIRST MOVE THE DEFUALT EXTENSION ".STC" AND CLEAR THE NAME
; THE MOVE IN THE NAME
STN1: PUSH H
PUSH D
MVI C,2 ;C=COUNTER TO DETERMINE WHEN THE NAME IS MOVED
LXI H,DFEXT ;HL=DEFUALT CLEARED NAME AND .EXT
STN2: MOV B,M ;FETCH COUNT
STN3: INX D ;NEXT FCB
INX H ;NEXT SOURCE
MOV A,M
STAX D
DCR B ;DEC COUNT
JNZ STN3 ;JIF NOT DONE
DCR C ;DEC C TO CHECK IF WE HAVE MOVED THE NAME
JZ Q$NEXT ;JIF WE HAVE
POP D
POP H
JMP STN2 ;ELSE MOVE THE NAME NOW
;SINCE THE EXTENION IS IN
;
;
;BADNAME MESSAGE
BADNAME: DB 19,'FILENAME LENGTH > 8',0
;DEFUALT EXTENSION WITH BLANK FILE NAME
DFEXT: DB 11,' STC',0
;
;
;/////////////////////////////////////////////////////
;
;ROUTINE: CPMLD
;PRUP: LOAD A CPM FILE
;ENTRY: TOS=NAME
;EXIT: TOS=DELETED
;PROCEDURE
;
DB 5,'CPMLD'
DW Q$STNAME
DW Q$COLN
Q$CPMLD: DW Q$DFTFCB
DW Q$0FCB ;0 THE FILE CONTROL BLOCK
DW Q$DFTFCB
DW Q$STNAME ;STORE NAME IN DFTFCB
DW Q$DFTFCB ;GET ADDRESS OF DEFUALT FCB
DW Q$OPFILE ;OPEN THE FILE
DW EBUF ;EMPTY THE BUFFERS
DW LIT
DW 1 ;DUMMY BLOCK 1
DW LOAD ;LOAD THE FILE
DW Q$SEMI ;RETURN
;
;
ENDIF
;
;
;/////////////////////////////////////////////////////////////
;
;
;INTERPRETER
;
DW $+2
PUSH0: LXI H,0 ;0PUSH
JMP Q$Q$PUSH
DW $+2
PUSH1: LXI H,-1 ;-1PUSH
JMP Q$Q$PUSH
Q$DPUSH: PUSH D ;DPUSH
Q$Q$PUSH: PUSH H ;PUSH
Q$NEXT:
IF DEBUG
LXI H,-(SSTACK+1)
DAD SP
JC STKE1
LXI H,-SSTKE
DAD SP
JNC STKE2
ENDIF
LHLD Q$I ;NEXT
INX H
INX H
SHLD Q$I
MOV E,M
INX H
MOV D,M
NEXT1: MOV H,D
MOV L,E
DCX H
MOV A,M
DCX H
MOV L,M
MOV H,A
PCHL
IF DEBUG
STKE1: LXI H,SERM1
JMP ERROR
STKE2: LXI H,SERM2
JMP ERROR
SERM1: DB 11,'STACK EMPTY'
SERM2: DB 10,'STACK FULL'
ENDIF
;
;
;TTY INPUT ROUTINE (JUMPS TO ADDRESS IN Q$TYI)
;
; CALL TTYIN
; CHARACTER RETURNED IN A
TTYIN: LHLD Q$TYI
PCHL
;TTY OUTPUT ROUTINE (JUMPS TO ADDRESS IN Q$TYO)
;
; CHARACTER IN A
; CALL TTYOU
TTYOU: LHLD Q$TYO
PCHL
DW $+2
Q$SEMI: LHLD Q$R ;RETURN STACK PTR
MOV E,M ;GET TOP OR STACK INTO DE
INX H
MOV D,M
DCX H
DCX H ;DECREMENT RETURN STACK PTR BY 2
DCX H
SHLD Q$R
XCHG ;MOVE RESULT TO HL
SHLD Q$I ;SET .I
JMP Q$NEXT
DW $+2
Q$SCOD: LHLD Q$CURR ;(;CODE<)
MOV E,M
INX H
MOV D,M
DCX D
DCX D
LHLD Q$I
INX H
INX H
XCHG
MOV M,E
INX H
MOV M,D
JMP Q$SEMI
DB 2,'()',0,0,0 ;()
;LINK TO CPM WORDS IF CPM=-1
IF CPM
DW Q$CPMLD
ENDIF
;
;ELSE THIS WILL BE THE END OF THE DICTIONARY
IF NOT CPM
DW 0
ENDIF
;
DW $+2
LIT: LHLD Q$I ;INCREMENT .I BY 2
INX H
INX H
SHLD Q$I
ATPUS: MOV E,M ;@PUSH
INX H
MOV D,M
PUSHD: PUSH D ;PUSHD
JMP Q$NEXT
DB 3,'S()',0,0 ;S()
DW LIT
DW $+2
SLIT: LHLD Q$I
INX H
INX H
MVI D,0
MOV E,M
PUSH H
DAD D
SHLD Q$I
JMP Q$NEXT
DB 5,'ABORT' ;ABORT
DW SLIT
DW $+2
ABORT: LXI SP,SSTACK ;RESET STACK PTR
LXI H,RSTACK ;RESET RETURN STACK PTR
SHLD Q$R
LXI H,LSTACK ;RESET LOOP STACK PTR
SHLD Q$Q$L
LXI H,-1 ;SET INBLK TO -1 (READ FROM KEYBOARD)
SHLD Q$INBLK
CALL Q$Q$AB ;CALL USER ABORT ROUTINE
LXI H,GO-2 ;SET .I TO GO-2
SHLD Q$I
JMP Q$NEXT ;START IT UP
Q$Q$AB: LHLD Q$ABORT ;JMP TO ABORT ROUTINE ADDRESS
PCHL
IF DEBUG
;TEST FOR DICTIONARY FULL
DICTF: LHLD Q$MEMO ;END OF MEMORY
LXI D,-100 ;-100 FOR SAFETY
DAD D
CALL Q$MHL
XCHG
LHLD Q$Q$D ;DICTIONARY POINTER
DAD D
RNC
LXI H,DER2 ;DICTIONARY FULL
JMP ERROR
DER2: DB 15,'DICTIONARY FULL'
;TEST FOR COMPILE BUFFER FULL
CBF: LHLD Q$C ;COMPILE BUFFER PTR
LXI D,-KBUF ;START OF LINE BUFFER
DAD D
RNC
LXI H,CER2 ;COMPILE BUFFER FULL
JMP ERROR
CER2: DB 19,'COMPILE BUFFER FULL'
ENDIF
;
;
;
Q$MHL: DCX H ;-HL
Q$NHL: MOV A,H ;NOTHL
CMA
MOV H,A
MOV A,L
CMA
MOV L,A
Q$AB: RET ;DEFAULT ABORT ROUTINE
;MULTIPLY ROUTINE
;MULTIPLIES (HL) BY (DE)
;RESULT RETURNED IN (HLDE)
Q$MUL: PUSH H ;MUL
MOV A,L
LXI H,0
LXI B,8
MULT1: DAD H
RAL
JNC MULT2
DAD D
ADC B
MULT2: DCR C
JNZ MULT1
XTHL
MOV L,A
MOV A,H
MOV H,B
MVI C,8
MULT3: DAD H
RAL
JNC MULT4
DAD D
ADC B
MULT4: DCR C
JNZ MULT3
MOV D,A
MOV E,H
MOV H,L
MOV L,B
POP B
DAD B
JNC MULT5
INX D
MULT5: XCHG
RET
;
;
DB 6,'(ELSE' ;(ELSE)
DW ABORT
DW $+2
Q$ELSE: LHLD Q$I
INX H
INX H
MOV E,M
INX H
MOV D,M
DCX H
DAD D
SHLD Q$I
JMP Q$NEXT
DB 4,'(IF)',0 ;(IF)
DW Q$ELSE
DW $+2
Q$IF: POP H
MOV A,H
ORA L
JZ Q$ELSE
LHLD Q$I
INX H
INX H
SHLD Q$I
JMP Q$NEXT
DB 1,'.',0,0,0,0 ;.
DW Q$IF
DW $+2
PERIO: LHLD Q$Q$D
JMP Q$Q$PUSH
DB 5,'STATE' ;STATE
DW PERIO
DW Q$CONS
STATE: DW Q$STATE
;
;
;OUTPUT A CHARACTER TO TTY
;
; A ASCII CHARACTER CODE
; CALL Q$TTO
;
;OUTPUT A CR TO TTY
;
; CALL Q$CR
;
;OUTPUT A CR IF COLUMN NON-ZERO
;
; CALL Q$IFCR
Q$IFCR: LDA Q$COLU
ORA A
RZ
Q$CR: MVI A,15Q
Q$TTO: LXI H,Q$COLU ;INCREMENT COLUMN
INR M
IF NOT TABS
CPI 11Q ;TAB Q$
JZ TTO2
ENDIF
TTO1: PUSH PSW ;SAVE CHARACTER
CALL TTYOU ;OUTPUT IT
POP PSW ;RESTORE CHARACTER
CPI 15Q ;RETURN Q$
RNZ ;NO, DONE
SUB A ;RESET COLUMN TO 0
STA Q$COLU
MVI A,12Q ;OUTPUT A LINE FEED
JMP TTO1
IF NOT TABS
TTO2: MVI A,40Q ;OUTPUT A SPACE
CALL TTYOU
LDA Q$COLU ;GET COLUMN #
ANI 7 ;0 MOD 8 Q$
RZ ;YES, DONE
MVI A,11Q ;NO, INCREMENT COLUMN AND DO ANOTHER SPACE
JMP Q$TTO
ENDIF
;TYPE A MESSAGE ON TTY
;
; H PTR TO STRING
; CALL Q$MSG
Q$MSG: MOV A,M ;GET BYTE COUNT IN A REGISTER
MSG1: ORA A ;LENGTH = 0 Q$
RZ ;YES, RETURN
DCR A ;DECREMENT COUNT
PUSH PSW ;SAVE IT
INX H ;INCREMENT PTR
PUSH H ;SAVE IT
MOV A,M ;GET NEXT BYTE
CALL Q$TTO ;TYPE IT
POP H ;RESTORE PTR AND COUNT
POP PSW
JMP MSG1 ;CONTINUE
;
;
;DICTIONARY LOOKUP
DB 6,'LOOKU' ;LOOKUP
DW STATE
DW $+2
LOOKU: POP H ;PTR TO STRING
SHLD Q$T1
LHLD Q$V ;VOCABULARY STACK PTR
LOOK0: SHLD Q$T3
LXI D,-(VSTACK)
DAD D
MOV A,H
ORA L
JZ Q$Q$PUSH ;YES, LOSE
LHLD Q$T3
MOV E,M
INX H
MOV D,M
XCHG
MOV E,M
INX H
MOV D,M
XCHG
MOV A,H
ORA L
JZ LOOK4 ;EMPTY BRANCH
LOOK1: LXI D,-10 ;BACK UP TO FIRST BYTE OF NAME
DAD D
SHLD Q$T2
XCHG
LHLD Q$T1 ;CHECK LENGTH BYTE
LDAX D
ANI 177Q ;AND OFF PRECEDENCE
CMP M
JNZ LOOK3 ;LENGTH BYTE DIFFERENT
MVI C,5 ;CHECK NEXT 5 CHARACTERS
LOOK5: INX D ;INCREMENT POINTERS
INX H
LDAX D ;COMPARE BYTES
CMP M
JNZ LOOK3 ;NO MATCH
ORA A
JZ LOOK2 ;BYTES EQUAL AND ZERO
DCR C
JNZ LOOK5
LOOK2: LHLD Q$T2 ;MATCH
LXI D,10
DAD D
PUSH H ;PUSH PTR TO ENTRY
JMP PUSH1 ;PUSH -1
LOOK3: LHLD Q$T2 ;LINK TO NEXT ENTRY
LXI D,6
DAD D
MOV E,M
INX H
MOV D,M
XCHG
MOV A,H
ORA L
JNZ LOOK1
LOOK4: LHLD Q$T3 ;LINK IS ZERO
DCX H ;GO TO NEXT BRANCH
DCX H
JMP LOOK0
;
;
DB 2,'B,',0,0,0 ;B,
DW LOOKU
DW $+2
BCOMA: POP H
MOV A,L
CALL Q$BCOM
JMP Q$NEXT
DB 1,',',0,0,0,0 ;,
DW BCOMA
DW $+2
COMMA: POP H
CALL Q$COMM
JMP Q$NEXT
DB 2,'C,',0,0,0 ;C,
DW COMMA
DW $+2
CCOMM: POP H
CALL Q$CCOM
JMP Q$NEXT
Q$COMM: PUSH H
MOV A,L
CALL Q$BCOM
POP H
MOV A,H
CALL Q$BCOM
RET
Q$BCOM: LHLD Q$Q$D
MOV M,A
INX H
SHLD Q$Q$D
IF DEBUG
CALL DICTF
ENDIF
RET
Q$CCOM: PUSH H
MOV A,L
CALL Q$CBCO
POP H
MOV A,H
CALL Q$CBCO
RET
Q$CBCO: LHLD Q$C
MOV M,A
INX H
SHLD Q$C
IF DEBUG
CALL CBF
ENDIF
RET
;
;
DB 6,'RDLIN' ;RDLINE
DW CCOMM
DW $+2
RDLIN: LXI H,KBUF+1 ;KEYBOARD BUFFER ADDRESS + 1
SHLD Q$T2 ;CURRENT OUTPUT PTR
SHLD Q$INP ;SET INP
SUB A ;ZERO EOL,BUFFER MODIFIED FLAG
STA Q$EOL
STA Q$T1
CMA ;SET EOC TO -1
STA Q$EOC
LHLD Q$INBLK ;READING FROM FILE Q$
INX H
MOV A,H
ORA L
JNZ RDL9 ;YES
;READING FROM TTY
RDL1: CALL TTYIN ;GET NEXT CHAR
CPI 12Q ;LINE FEED
JZ RDL8
CPI 177Q
JZ RDL2 ;RUBOUT
ORA A
JZ RDL3 ;NULL
CPI 15Q ;CR
JZ RDL10
CPI 14Q ;FF
JZ RDL10
RDL4: PUSH PSW ;ECHO CHARACTER
CALL Q$TTO
MVI A,0FFH ;SET BUFFER MODIFIED FLAG TO -1
STA Q$T1
POP PSW
CALL OCH ;STORE CHAR IN BUFFER
LXI D,-(KBUF+KSIZE)
DAD D
JNC RDL1
RDL5: LXI H,RDL6 ;BUFFER FULL
JMP ERROR
RDL6: DB 13,'LINE TOO LONG'
;PROCESS RUBOUT
RDL2: LHLD Q$T2 ;OUTPUT PTR
LXI D,-(KBUF+1) ;START OF BUFFER
DAD D
MOV A,H
ORA L
JZ RDL1 ;BUFFER EMPTY, IGNORE RUBOUT
LHLD Q$T2 ;BACK UP OUTPUT PTR
DCX H
SHLD Q$T2
IF BCKSP
MVI A,10Q ;ECHO BACKSPACE, SPACE, BACKSPACE
CALL Q$TTO
MVI A,40Q
CALL Q$TTO
MVI A,10Q
CALL Q$TTO
ENDIF
IF NOT BCKSP
MVI A,137Q ;ECHO _
CALL Q$TTO
ENDIF
JMP RDL1
;PROCESS NULL
RDL3: LXI H,KBUF+1 ;RESET OUTPUT PTR
SHLD Q$T2
;PROCESS CR OR FF
RDL10: CALL Q$CR ;ECHO A CR
RDL11: SUB A ;OUTPUT A NULL TO LINE BUFFER
LHLD Q$T2
MOV M,A
LXI D,-(KBUF+1) ;COMPUTE BYTE COUNT
DAD D
MOV A,L
STA KBUF ;STORE IN 1ST BYTE OF LINE BUFFER
JMP Q$NEXT
;PROCESS LINE FEED
RDL8: LDA Q$T1 ;BUFFER MODIFIED Q$
ORA A
JNZ RDL1 ;YES, IGNORE LINE FEED
CALL Q$CR ;ECHO A CR
JMP Q$NEXT ;AND RE-EXECUTE LINE
RDL9: LHLD Q$INBLK ;GET INBLK
XCHG
CALL RBLK ;GET ADDR OF BUFFER CONTAINING BLOCK
PUSH D ;SAVE IT
LHLD Q$INBYT ;GET INBYTE
PUSH H ;SAVE IT
INX H ;INCREMENT IT
SHLD Q$INBYT
LXI D,-BSIZE
DAD D
MOV A,H
ORA L
JNZ RDL15
LHLD Q$INBLK ;INCREMENT INBLK
INX H
SHLD Q$INBLK
LXI H,0 ;RESET INBYTE
SHLD Q$INBYT
RDL15: POP D
POP H
DAD D
MOV A,M ;GET CHAR FROM FILE
;
;**********************************
;
; THIS CHECK FOR LF IS ADDED BY WINK SAVILLE SO
; FILES MADE UNDER CPM WHICH WILL HAVE LF IN THEM WILL WORK
;
;
IF CPM
;
CPI 0AH ;CHECK FOR A LINE FEED
JZ RDL9 ;JIF LF
;IGNORE LINE FEED
ENDIF
;
;
;***********************************
;
CPI 15Q ;CR
JZ RDL11
CPI 14Q ;FF
JZ RDL11
CPI 4 ;EOF Q$
JZ RDL12 ;YES, ERROR
CALL OCH ;STORE CHAR IN BUFFER
LXI D,-(KBUF+KSIZE)
DAD D
JNC RDL9
JMP RDL5 ;LINE TOO LONG
RDL12: LXI H,RDL13 ;END OF FILE
JMP ERROR
RDL13: DB 3,'EOF'
;OUTPUT A CHARACTER TO LINE BUFFER
OCH: LHLD Q$T2
MOV M,A
INX H
SHLD Q$T2
RET
;
;
DW $+2
UNDEF: POP H ;WAS IF A LITERAL Q$
MOV A,H
ORA L
JNZ Q$NEXT ;YES, OK
LXI H,UND1
ERROR: LXI SP,SSTACK ;RESET PARAMETER STACK POINTER
PUSH H ;PUSH PTR TO STRING
LXI H,RSTACK ;RESET RETURN STACK POINTER
SHLD Q$R
LXI H,LSTACK ;RESET LOOP STACK POINTER
SHLD Q$Q$L
JMP ERR ;EXECUTE ERROR HANDLER
UND1: DB 9,'UNDEFINED'
DB 3,'ERR',0,0 ;ERR
DW RDLIN
DW $+2
ERR: LHLD Q$ERRM ;ERRMSG @ EXEC
EXEC: XCHG
JMP NEXT1
DB 7,'ERRMS' ;ERRMSG0
DW ERR
DW $+2
ERRM0: CALL Q$IFCR ;TYPE A CR IF COLUMN NON-ZERO
POP H ;TYPE THE MESSAGE
CALL Q$MSG
CALL Q$CR ;TYPE A CR
LHLD Q$Q$D ;TYPE THE LAST TOKEN
CALL Q$MSG
CALL Q$IFCR ;TYPE A CR IF COLUMN NON-ZERO
LHLD Q$INBLK ;INBLK = -1 Q$
INX H
MOV A,H
ORA L
JZ ABORT ;YES, EXECUTING FROM KEYBD
LXI H,KBUF ;NO, TYPE LINE BUFFER
CALL Q$MSG
CALL Q$CR ;TYPE A CR
JMP ABORT ;ABORT
;
;
DB 4,'UNIT',0 ;UNIT
DW ERRM0
DW Q$CONS
UNIT: DW Q$UNIT
IF DISK
SETUP:
; MOV A,L ;TEST FOR ILLEGAL BLOCK #
; SUI NBLKS AND 0FFH
; MOV A,H
; SBI NBLKS/100H
; JNC IBN ;ILLEGAL BLOCK #
LXI B,1 ;SET BLOCK COUNT TO 1
RET
;IBN: LXI H,IBNM
; JMP ERROR
WRERC: CALL SETUP
Q$WRERC: CALL DSKOU
RZ ;NO ERRORS
CPI 4 ;WRITE PROTECTED Q$
JNZ RDER1 ;NO, CHECK FOR OTHER ERRORS
LXI H,WRER1 ;WRITE PROTECTED
JMP ERROR
RDERC: CALL SETUP
Q$RDERC: CALL DSKIN
RZ ;NO ERRORS
RDER1: LXI H,RDER2 ;CRC ERROR
JMP ERROR
WRER1: DB 20,'DISK WRITE PROTECTED'
RDER2: DB 10,'DISK ERROR'
IBNM: DB 15,'ILLEGAL BLOCK #'
ENDIF
IF NOT DISK
WRERC: LXI B,1 ;WRITE 1 BLOCK
Q$WRERC: CALL DSKOU ;WRITE WITH ERROR CHECKING
RZ
JMP RDER1
RDERC: LXI B,1 ;READ 1 BLOCK
Q$RDERC: CALL DSKIN ;READ WITH ERROR CHECKING
RZ ;IF 0, NO ERROR
RDER1: DCR A
MOV E,A
MVI D,0
LXI H,TERRT
DAD D
DAD D
MOV E,M
INX H
MOV D,M
XCHG
JMP ERROR
TERRT: DW TERR1
DW TERR2
DW TERR3
DW TERR4
DW TERR5
DW TERR6
DW TERR7
DW TERR8
DW TERR9
DW TERRA
DW TERRB
TERR1: DB 14,'TAPE NOT READY'
TERR2: DB 20,'TAPE WRITE PROTECTED'
TERR3: DB 22,'READ AFTER WRITE ERROR'
TERR4: DB 13,'READ OVERFLOW'
TERR5: DB 15,'POSTAMBLE ERROR'
TERR6: DB 11,'SHORT BLOCK'
TERR7: DB 10,'LONG BLOCK'
TERR8: DB 3,'EOT'
TERR9: DB 3,'BOT'
TERRA: DB 14,'CHECKSUM ERROR'
TERRB: DB 12,'NO SUCH TAPE'
ENDIF
;
;
DB 6,'NEWES' ;NEWEST
DW UNIT
DW Q$CONS
NEWQ$: DW NEWEST
; (D,E) BLOCK #
; CALL RBLK (WBLK)
; (D,E) BUFFER ADDRESS
WBLK: MVI A,0FFH ;WBLK
JMP BLK
RBLK: SUB A ;RBLK
BLK: STA FLAG
LHLD NEWEST ;IS BLOCK THE MOST RECENTLY ACCESSED BLOCK Q$
MOV A,E
CMP M
JNZ BLK1 ;NO
INX H
MOV A,D
CMP M
JNZ BLK1 ;NO
INX H ;YES, RETURN BUFFER ADDR
MOV E,M
INX H
MOV D,M
RET
BLK1: LHLD NEWEST ;SEARCH BUFFER LIST
SHLD BUFP
XCHG
SHLD BLKN
BLK2: LHLD BUFP ;GET LINK TO NEXT BCT
LXI D,4
CALL LDX
MOV A,D
ORA E
JZ BLK3 ;END OF LIST, MUST READ IN BLOCK
LHLD BUFP
SHLD PREV
XCHG
SHLD BUFP
MOV E,M ;GET BLOCK #
INX H
MOV D,M
LHLD BLKN ;COMPARE WITH REQUESTED BLOCK #
MOV A,H
CMP D
JNZ BLK2 ;NO
MOV A,L
CMP E
JNZ BLK2 ;NO
BLK6: LHLD BUFP ;RELINK BCT'S
LXI D,4
CALL LDX
PUSH D ;SAVE LINK OF CURRENT BCT
LHLD NEWEST ;RESET LINK OF CURRENT BCT TO NEWEST
XCHG
LHLD BUFP
LXI B,4
CALL STX
LHLD BUFP ;SET NEWEST TO CURRENT BCT
SHLD NEWEST
LHLD PREV ;STORE SAVED LINK IN LINK OF PREVIOUS BCT
POP D
LXI B,4
CALL STX
LHLD BUFP ;RETURN BUFFER ADDRESS
LXI D,2
CALL LDX
RET
BLK3: CALL FBUF ;FREE A BUFFER
LDA FLAG ;RBLOCK Q$
ORA A
JNZ BLK7 ;NO
LHLD BUFP ;READ IN BLOCK
LXI D,2
CALL LDX
LHLD BLKN
CALL RDERC
BLK7: LHLD BLKN ;STORE BLOCK # IN BCT
XCHG
LHLD BUFP
MOV M,E
INX H
MOV M,D
JMP BLK6 ;RELINK BCT'S
FBUF: LHLD BUFP ;REEE A BUFFER
LXI D,6 ;GET MODIFIED FLAG
CALL LDX
MOV A,D
ORA E
RZ ;NOT MODIFIED, RETURN
LHLD BUFP ;GET BLOCK #
MOV E,M
INX H
MOV D,M
PUSH D
LHLD BUFP ;GET BUFFER ADDR
LXI D,2
CALL LDX
POP H
CALL WRERC ;WRITE IT BACK OUT
LHLD BUFP ;CLEAR THE MODIFIED FLAG
LXI D,0
LXI B,6
CALL STX
RET ;RETURN
DB 6,'RBLOC' ;RBLOCK
DW NEWQ$
DW $+2
RBLOC: POP D ;GET BLOCK #
LDA Q$UNIT ;ADD IN UNIT NUMBER
ORA A
RAL
ORA D
MOV D,A
CALL RBLK
JMP PUSHD
DB 6,'WBLOC' ;WBLOCK
DW RBLOC
DW $+2
WBLOC: POP D
LDA Q$UNIT ;ADD IN UNIT NUMBER
ORA A
RAL
ORA D
MOV D,A
CALL WBLK
PUSH D
JMP UPDAT
DB 6,'UPDAT' ;UPDATE
DW WBLOC
DW $+2
UPDAT: LHLD NEWEST ;SET MODIFIED FLAG ON CURRENT BCT
LXI D,-1
LXI B,6
CALL STX
JMP Q$NEXT
DB 5,'FLUSH' ;FLUSH
DW UPDAT
DW $+2
FLUSH: LHLD NEWEST ;FREE ALL BUFFERS
FLSH1: SHLD BUFP
CALL FBUF ;FREE A BUFFER
LHLD BUFP ;LINK TO NEXT BCT
LXI D,4
CALL LDX
MOV A,D
ORA E
JZ Q$NEXT ;DONE
XCHG ;DO ANOTHER ONE
JMP FLSH1
DB 4,'EBUF',0 ;EBUF
DW FLUSH
DW $+2
EBUF: LHLD NEWEST ;SET ALL BLOCK NUMBERS TO -1
EBUF1: SHLD BUFP
MVI M,0FFH
INX H
MVI M,0FFH
DCX H
LXI D,0
LXI B,6
CALL STX
LHLD BUFP ;LINK TO NEXT BCT
LXI D,4
CALL LDX
MOV A,D
ORA E
JZ Q$NEXT ;DONE
XCHG ;DO ANOTHER ONE
JMP EBUF1
;INDEXED LOAD
; (DE) OFFSET
; (HL) BASE ADDRESS
; CALL LDX
; (DE) DATA
LDX: DAD D
MOV E,M
INX H
MOV D,M
RET
;INDEXED STORE
; (BC) OFFSET
; (DE) DATA
; (HL) BASE ADDRESS
; CALL STX
STX: DAD B
MOV M,E
INX H
MOV M,D
RET
;
;
;GET NEXT WORD FROM INPUT STREAM
;
;ON ENTRY,
;Q$INP CONTAINS INPUT POINTER
;
;ON EXIT,
;Q$INP IS UPDATED
;TOKEN IS AT END OF DICTIONARY (NULL TERMINATED)
;END-OF-LINE FLAG IS ON STACK
;
;DELIMITER IS SPACE OR TAB UNLESS FIRST CHARACTER IS " OR \
;IN WHICH CASE SCANNING CONTINUES UNTIL NEXT " OR \
;
;IF END-OF-LINE FLAG IS SET ON ENTRY, WORD RETURNS IMMEDIATELY
;SCANNING STOPS UNCONDITIONALLY ON A NULL IN THE INPUT STREAM
;AND THE END-OF-LINE FLAG IS SET IF THE NULL OCCURED INBETWEEN WORDS;
;OTHERWISE IT IS SET ON THE NEXT CALL TO WORD.
DB 4,'WORD',0 ;WORD
DW EBUF
DW $+2
WORD: LDA Q$EOL ;ALREADY AT END OF LINE Q$
ORA A
JNZ PUSH1 ;YES, RETURN -1
LXI B,0920H ;SET TAB,SPACE AS DELIMITERS (IN (B,C))
LHLD Q$Q$D ;(D,E) IS OUTPUT PTR
INX H ;SKIP LENGTH BYTE
XCHG
LHLD Q$INP ;(H,L) IS INPUT PTR
WORD3: MOV A,M ;GET NEXT INPUT CHAR
INX H
ORA A
JZ WORD6 ;NULL, END OF LINE
CMP B ;DELIMITER Q$
JZ WORD3 ;YES, IGNORE
CMP C
JZ WORD3 ;YES, IGNORE
CPI 42Q ;" Q$
JZ WORD9
CPI 134Q ;\ Q$
JNZ WORD4
WORD9: MOV B,A ;RESET DELIMITERS
MOV C,A
WORD4: STAX D ;OUTPUT CHARACTER
INX D
MOV A,M ;GET NEXT INPUT CHARACTER
INX H
ORA A ;NULL Q$
JZ WORD7 ;YES, END OF LINE
CMP B ;DELIMITER Q$
JZ WORD8 ;YES, STOP
CMP C ;DELIMITER Q$
JNZ WORD4 ;NO, GET MORE CHARACTERS
WORD8: SHLD Q$INP ;UPDATE INPUT PTR
SUB A ;OUTPUT A NULL AT END OF STRING
STAX D
LHLD Q$Q$D ;COMPUTE LENGTH OF WORD
CALL Q$MHL
DAD D
MOV A,L
DCR A
LHLD Q$Q$D ;STORE IN LENGTH BYTE
MOV M,A
LDA Q$EOL ;PUSH END OF LINE FLAG
MOV L,A
MOV H,A
JMP Q$Q$PUSH
WORD6: MVI A,0FFH ;SET EOL TO -1
STA Q$EOL
WORD7: DCX H ;DECREMENT INPUT PTR
JMP WORD8
;
;
;LITERAL PROCESSOR
DB 7,'LITER' ;LITERAL
DW WORD
DW Q$COLN
LITER: DW PERIO
DW ILITE
DW Q$IF
DW LIT1-2-$
DW LIT
DW LIT
DW CCOMM
DW CCOMM
DW PUSH1
DW Q$SEMI
LIT1: DW PERIO
DW SLITE
DW Q$SEMI
DB 8,'ILITE' ;ILITERAL
DW LITER
DW $+2
ILITE: POP H ;POP INPUT POINTER
INX H
SHLD Q$T3 ;SET INPUT PTR
LXI H,0 ;ZERO SIGN,VALUE
SHLD Q$T4
SHLD Q$T5
CALL LITG ;GET NEXT CHAR
CPI 53Q ;"+" Q$
JZ ILIT1 ;IGNORE
CPI 55Q ;"-" Q$
JNZ ILIT2 ;NO
LXI H,-1 ;SET SIGN FLAG
SHLD Q$T4
ILIT1: CALL LITG ;GET NEXT CHAR
ILIT2: ORA A ;END OF LITERAL Q$
JZ ILIT4 ;YES, DONE
CPI 60Q ;TEST FOR LEGAL DIGIT
JC PUSH0 ;ILLEGAL
CPI 72Q
JC ILIT3
CPI 101Q
JC PUSH0 ;ILLEGAL
SUI 7
ILIT3: SUI 60Q
LHLD Q$RADIX
CMP L
JNC PUSH0 ;ILLEGAL
STA Q$T1
LHLD Q$RADIX ;MULTIPLY VALUE BY RADIX AND ADD DIGIT
XCHG
LHLD Q$T5
CALL Q$MUL
MOV A,H
ORA L
JNZ PUSH0 ;OVERFLOW
LDA Q$T1
MOV L,A
MVI H,0
DAD D
SHLD Q$T5 ;SET NEW VALUE
JMP ILIT1
ILIT4: LHLD Q$T4 ;GET SIGN
MOV A,H
ORA L
LHLD Q$T5 ;GET VALUE
CM Q$MHL ;NEGATE IF SIGN NON-ZERO
PUSH H ;PUSH RESULT
JMP PUSH1 ;PUSH -1
DB 8,'SLITE' ;SLITERAL
DW ILITE
DW $+2
SLITE: POP H ;POP INPUT POINTER
INX H
SHLD Q$T3 ;SET INPUT PTR
CALL LITG ;GET 1ST CHAR
CPI 47Q ;'
JZ SLIT1 ;STRING LITERAL
CPI 42Q ;"
JZ SLIT1 ;STRING LITERAL
CPI 134Q ;\
JNZ PUSH0 ;ILLEGAL STRING LITERAL
SLIT1: LXI H,SLIT ;OUTPUT S()
CALL Q$CCOM
LHLD Q$C ;SAVE PTR TO START OF LITERAL
SHLD Q$T1
SUB A ;ZERO LENGTH BYTE
CALL Q$CBCO
SLIT2: CALL LITG ;GET NEXT CHAR
ORA A
JZ SLIT7 ;END OF STRING LITERAL
CPI 46Q ;&
JZ SLIT4 ;START OF OCTAL INSERT
SLIT3: CALL Q$CBCO ;OUTPUT CHARACTER
LHLD Q$T1 ;INCREMENT LENGTH
INR M
JMP SLIT2
SLIT4: SUB A ;INITIALIZE VALUE TO 0
SLIT5: STA Q$T2
CALL LITG ;GET NEXT CHAR
CPI 46Q ;&
JZ SLIT6 ;END OF OCTAL NUMBER
CPI 60Q ;0
JM PUSH0 ;ILLEGAL DIGIT
CPI 70Q ;8
JP PUSH0 ;ILLEGAL DIGIT
SUI 60Q ;CONVERT TO VALUE
MOV B,A
LDA Q$T2 ;MULTIPLY VALUE BY 8 AND ADD DIGIT
RLC
RLC
RLC
ADD B
JMP SLIT5
SLIT6: LDA Q$T2 ;RETURN OCTAL VALUE
JMP SLIT3
SLIT7: CALL Q$CBCO ;OUTPUT FINAL NULL
JMP PUSH1 ;EXIT
LITG: LHLD Q$T3 ;GET NEXT INPUT CHAR
MOV A,M
INX H
SHLD Q$T3
RET
;
IF DEBUG
DB 6,'ERRCH' ;ERRCHK
DW SLITE
DW $+2
ERRCH: CALL DICTF
CALL CBF
LHLD Q$V ;VOCABULARY STACK PTR
XCHG
LXI H,-VSTACK-2 ;START OF VOCABULARY STACK + 2
DAD D
JNC ERRC1
LXI H,-LSTACK
DAD D
JC ERRC2
LHLD Q$Q$L ;LOOP STACK PTR
XCHG
LXI H,-LSTACK ;START OF LOOP STACK
DAD D
JNC ERRC3
LXI H,-RSTACK ;START OF RETURN STACK
DAD D
JC ERRC4
JMP Q$NEXT
ERRC1: LXI H,VSTACK+2 ;RESET VOCABULARY STACK PTR
SHLD Q$V
LXI H,VER1 ;VOCABULARY STACK EMPTY
JMP ERROR
ERRC2: LXI H,VER2 ;VOCABULARY STACK FULL
JMP ERROR
ERRC3: LXI H,LER1 ;LOOP STACK EMPTY
JMP ERROR
ERRC4: LXI H,LER2 ;LOOP STACK FULL
JMP ERROR
VER1: DB 22,'VOCABULARY STACK EMPTY'
VER2: DB 21,'VOCABULARY STACK FULL'
LER1: DB 16,'LOOP STACK EMPTY'
LER2: DB 15,'LOOP STACK FULL'
ENDIF
DW Q$COLN
COMPI: DW WORD ;GET NEXT WORD FROM INPUT STREAM
DW Q$IF
DW COMP1-2-$
DW Q$SEMI ;END OF LINE, RETURN
COMP1: DW PERIO ;DO A DICTIONARY LOOKUP
DW LOOKU
DW Q$IF
DW COMP2-2-$
DW Q$COMP ;FOUND, COMPILE OR EXECUTE IT
DW Q$ELSE
DW COMPI-2-$
COMP2: DW EXLIT ;NOT FOUND, MAYBE A LITERAL
DW UNDEF
DW Q$ELSE
DW COMPI-2-$
DW $+2
EXLIT: LHLD Q$LIT
JMP EXEC
DW $+2
Q$COMP: POP D ;PTR TO PARAMETER FIELD OF WORD
LXI H,-10 ;BACK UP TO PRECEDENCE FIELD
DAD D
MOV A,M ;GET 1ST BYTE OF ENTRY
ORA A
JM NEXT1 ;PRECEDENCE BIT SET, EXECUTE IT
LDA Q$STATE ;PRECEDENCE BIT ZERO, CHECK STATE
ORA A
JP NEXT1 ;STATE ZERO, EXECUTE IT
XCHG ;STORE ADDR OF PARAMETER FIELD IN COMPLILE BUFFER
CALL Q$CCOM
JMP Q$NEXT
DB 7,'PROMP' ;PROMPT0
IF DEBUG
DW ERRCH
ENDIF
IF NOT DEBUG
SLITE
ENDIF
DW $+2
PROM0: LHLD Q$INBLK ;EXECUTING A FILE Q$
INX H
MOV A,H
ORA L
JNZ Q$NEXT ;YES, NO PROMPT
CALL Q$IFCR ;TYPE A CR IF COLUMN NON-ZERO
LDA Q$CHECK ;TYPE CHECK
CALL Q$TTO
MVI A,76Q ;TYPE >
CALL Q$TTO
MVI A,40Q ;TYPE SPACE
CALL Q$TTO
JMP Q$NEXT ;RETURN
DW Q$COLN
GO: DW Q$GO1
GO1: DW EXPRO
GO8: DW RDLIN
DW COMPI
DW Q$GO2
DW Q$IF
DW GO1-2-$
DW LIT
DW Q$SEMI
DW CCOMM
DW EXCBUF
IF DEBUG
DW ERRCH
ENDIF
DW Q$ELSE
DW GO-2-$
DW $+2
EXPRO: LHLD Q$PROM ;EXECUTE @ PROMPT
JMP EXEC
DW $+2
EXCBUF: LXI D,CBUF+2 ;EXECUTE COMPILE BUFFER
JMP NEXT1
DW $+2
Q$GO1: MVI A,80H ;SET STATE TO 80 HEX
STA Q$STATE
MVI A,60Q ;SET CHECK TO "0"
STA Q$CHECK
LXI H,CBUF ;RESET .C TO START OF COMPILE BUFFER
SHLD Q$C
LXI H,Q$COLN ;OUTPUT (:) TO COMPILE BUFFER
CALL Q$CCOM
JMP Q$NEXT
DW $+2
Q$GO2: LDA Q$EOC ;END OF COMMAND Q$
ORA A
JZ PUSH0 ;NO, RETURN 0
LDA Q$CHECK ;CHECK = "0" Q$
CPI 60Q
JNZ PUSH0 ;NO, RETURN 0
JMP PUSH1 ;YES, RETURN -1
;
;
DB 5,'ENTER' ;ENTER
DW PROM0
DW $+2
ENTER: LHLD Q$ENT
JMP EXEC
DB 4,'ENT0',0 ;ENT0
DW ENTER
DW $+2
ENT0: LHLD Q$Q$D ;ZERO 6 BYTES AT END OF DICTIONARY
MVI A,6
ENT1: MVI M,0
INX H
DCR A
JNZ ENT1
POP B ;COPY NAME ONTO END OF DICTIONARY
MVI A,6 ;6 BYTES
STA Q$T1
ENT2: LDAX B ;MOVE NAME AND LENGTH
ORA A
JZ ENT3 ;FILL WITH NULLS
INX B
ENT3: CALL Q$BCOM
LXI H,Q$T1 ;DONE Q$
DCR M
JNZ ENT2 ;NO
;LINK NEW ENTRY INTO DICTIONARY
LHLD Q$CURR ;GET PTR TO PREVIOUS ENTRY
MOV E,M
INX H
MOV D,M
XCHG
CALL Q$COMM ;STORE IT IN LINK FIELD
LHLD Q$Q$D ;STORE $+2 IN CODE ADDRESS FIELD
INX H
INX H
CALL Q$COMM
LHLD Q$Q$D ;RESET CURRENT TO .
XCHG
LHLD Q$CURR
MOV M,E
INX H
MOV M,D
JMP Q$NEXT ;RETURN
;
;
Q$BRAN: XCHG ;PUSH @(DE) ON VOCABULARY STACK
MOV E,M
INX H
MOV D,M
BRAN1: LHLD Q$V
INX H
INX H
SHLD Q$V
MOV M,E
INX H
MOV M,D
JMP Q$NEXT
DB 10,'ASSEM' ;ASSEMBLER<
DW ENT0
DW Q$BRAN
ASSEM: DW Q$ASSE
DB 6,'STOIC' ;STOIC<
DW ASSEM
DW Q$BRAN
STOIC: DW Q$STOI
DB 2,'<L',0,0,0 ;<L
DW STOIC
DW $+2
LPUSH: POP H
CALL Q$LPUSH
JMP Q$NEXT
DB 2,'L>',0,0,0 ;L>
DW LPUSH
DW $+2
LPOP: CALL Q$LPOP
JMP Q$Q$PUSH
DB 4,'LOAD',0 ;LOAD
DW LPOP
DW $+2
LOAD: LHLD Q$INBLK
CALL Q$LPUSH
LHLD Q$INBYT
CALL Q$LPUSH
POP H
SHLD Q$INBLK
LXI H,0
SHLD Q$INBYT
JMP Q$NEXT
DB 2,';F',0,0,0 ;;F
DW LOAD
DW $+2
Q$SCLF: CALL Q$LPOP
SHLD Q$INBYT
CALL Q$LPOP
SHLD Q$INBLK
JMP Q$NEXT
;POP A NUMBER OFF THE LOOP STACK
;
; CALL Q$LPOP
; HL CONTAINS NUMBER
Q$LPOP: LHLD Q$Q$L ;LOOP STACK PTR
MOV E,M ;GET TOP OR STACK INTO DE
INX H
MOV D,M
DCX H
DCX H ;DECREMENT LOOP STACK PTR BY 2
DCX H
SHLD Q$Q$L
XCHG ;MOVE RESULT TO HL
RET ;RETURN
;PUSH A NUMBER ON THE LOOP STACK
;
; HL CONTAINS NUMBER
; CALL Q$LPUSH
Q$LPUSH: XCHG ;MOVE NUMBER TO DE
LHLD Q$Q$L ;INCREMENT LOOP STACK PTR BY 2
INX H
INX H
SHLD Q$Q$L
MOV M,E ;STORE NUMBER ON END OF RETURN STACK
INX H
MOV M,D
RET ;RETURN
DB 11,'DEFIN' ;DEFINTIONS
DW Q$SCLF
DW $+2
DEFIN: LHLD Q$V
MOV E,M
INX H
MOV D,M
XCHG
SHLD Q$CURR
JMP Q$NEXT
DB 1,'>',0,0,0,0 ;>
DW DEFIN
DW $+2
REVER: LHLD Q$V
DCX H
DCX H
SHLD Q$V
JMP Q$NEXT
DB 201Q,'^',0,0,0,0 ;^
DW REVER
DW $+2
UPARR: SUB A
STA Q$EOC
JMP Q$NEXT
DB 201Q,'%',0,0,0,0 ;%
DW UPARR
DW $+2
PERC: MVI A,0FFH
STA Q$EOL
JMP Q$NEXT
;
;
DB 201Q,':',0,0,0,0 ;:
DW PERC
DW $+2
COLON: LDA Q$CHECK
CPI 60Q
JNZ CHERR
INR A
STA Q$CHECK
LXI H,ENTER
CALL Q$CCOM
LXI H,COLN1
CALL Q$CCOM
LHLD Q$C
PUSH H
LXI H,0
CALL Q$CCOM
JMP Q$NEXT
CHERR: LXI H,CHERM
JMP ERROR
CHERM: DB 12,'SYNTAX ERROR'
Q$COLN: LHLD Q$I ;(;)
XCHG
DCX H ;SET .I TO W-2
DCX H
SHLD Q$I
LHLD Q$R ;INCREMENT RETURN STACK PTR BY 2
INX H
INX H
SHLD Q$R
MOV M,E ;STORE .I ON END OF RETURN STACK
INX H
MOV M,D
JMP Q$NEXT
DW $+2
COLN1: LHLD Q$I
INX H
INX H
MOV E,M
INX H
MOV D,M
INX H
COLN2: PUSH H
PUSH D
MOV A,M
CALL Q$BCOM
POP D
POP H
INX H
DCX D
MOV A,D
ORA E
JNZ COLN2
DCX H
DCX H
SHLD Q$I
LHLD Q$CURR
MOV E,M
INX H
MOV D,M
DCX D
DCX D
LXI H,Q$COLN
XCHG
MOV M,E
INX H
MOV M,D
JMP Q$NEXT
DB 205Q,'CODE<' ;CODE<
DW COLON
DW Q$COLN
CODE: DW LIT
DW ENTER
DW CCOMM
DW ASSEM
DW Q$SEMI
DB 201Q,';',0,0,0,0 ;;
DW CODE
DW $+2
SCOL: CALL Q$SCOL ;TERMINATE COLON DEFINITION
LXI H,Q$SEMI ;OUTPUT (;) TO COMPILE BUFFER
CALL Q$CCOM
JMP Q$NEXT
DB 206Q,';CODE' ;;CODE<
DW SCOL
DW $+2
SCLCD: CALL Q$SCOL ;TERMINATE COLON DEFINITION
LXI H,Q$SCOD ;OUTPUT (;CODE) TO COMPILE BUFFER
CALL Q$CCOM
LXI D,Q$ASSE ;ASSEMBLER<
JMP BRAN1
Q$SCOL: LDA Q$CHECK ;DECREMENT CHECK
DCR A
CPI 60Q
JNZ CHERR ;ERROR IF NOT ZERO
STA Q$CHECK
POP H ;OLD C.
XTHL
PUSH H
CALL Q$MHL ;COMPUTE DIFFERENCE
XCHG
LHLD Q$C ;C.
DAD D
XCHG
POP H ;OLD C.
MOV M,E ;STORE DIFFERENCE AT OLD C.
INX H
MOV M,D
RET
DB 8,'CONST' ;CONSTANT
DW SCLCD
DW Q$COLN
CONST: DW ENTER
DW COMMA
DW Q$SCOD
Q$CONS: XCHG ;(CONSTANT)
JMP ATPUS
;
;
DB 4,'PUSH',0 ;PUSH
DW 0
DW Q$CONS
PUSHQ$: DW Q$Q$PUSH
DB 4,'NEXT',0 ;NEXT
DW PUSHQ$
DW Q$CONS
NEXTQ$: DW Q$NEXT
DB 5,'DPUSH' ;DPUSH
DW NEXTQ$
DW Q$CONS
DPSHQ$: DW Q$DPUSH
DB 5,'@PUSH' ;@PUSH
DW DPSHQ$
DW Q$CONS
ATPSQ$: DW ATPUS
DB 5,'PUSHD' ;PUSHD
DW ATPSQ$
DW Q$CONS
PUSDQ$: DW PUSHD
DB 5,'0PUSH' ;0PUSH
DW PUSDQ$
DW Q$CONS
PUS0Q$: DW PUSH0
DB 6,'-1PUS' ;-1PUSH
DW PUS0Q$
DW Q$CONS
PUS1Q$: DW PUSH1
DB 3,'MUL',0,0 ;MUL
DW PUS1Q$
DW Q$CONS
MULQ$: DW Q$MUL
DB 3,'-HL',0,0 ;-HL
DW MULQ$
DW Q$CONS
MHLQ$: DW Q$MHL
DB 5,'(MSG)' ;(MSG)
DW MHLQ$
DW Q$CONS
MSGQ$: DW Q$MSG
DB 3,'(,)',0,0 ;(,)
DW MSGQ$
DW Q$CONS
COMMQ$: DW Q$COMM
DB 4,'(B,)',0 ;(B,)
DW COMMQ$
DW Q$CONS
BCOMQ$: DW Q$BCOM
DB 8,'(BRAN' ;(BRANCH)
DW BCOMQ$
DW Q$CONS
BRANQ$: DW Q$BRAN
DB 5,'ERROR' ;ERROR
DW BRANQ$
DW Q$CONS
ERRQ$: DW ERROR
DB 5,'(TTI)' ;(TTI)
DW ERRQ$
DW Q$CONS
TTIQ$: DW TTYIN
DB 5,'(TTO)' ;(TTO)
DW TTIQ$
DW Q$CONS
TTOQ$: DW Q$TTO
DB 6,'(READ' ;(READ)
DW TTOQ$
DW Q$CONS
READQ$: DW Q$RDERC
DB 7,'(WRIT' ;(WRITE)
DW READQ$
DW Q$CONS
WRITQ$: DW Q$WRERC
DB 8,'(RBLO' ;(RBLOCK)
DW WRITQ$
DW Q$CONS
RBLKQ$: DW RBLK
DB 8,'(WBLO' ;(WBLOCK)
DW RBLKQ$
DW Q$CONS
WBLKQ$: DW WBLK
DB 2,'T1',0,0,0 ;T1
DW WBLKQ$
DW Q$CONS
T1Q$: DW Q$T1
;8080 INSTRUCTION CLASSES
DB 2,'R0',0,0,0 ;R0
DW T1Q$
DW Q$COLN
XR0: DW CONST
DW Q$SCOD
LDAX D
CALL Q$BCOM
JMP Q$NEXT
DB 2,'R1',0,0,0 ;R1
DW XR0
DW Q$COLN
R1: DW CONST
DW Q$SCOD
CALL SH3
R11: CALL Q$BCOM
JMP Q$NEXT
DB 2,'R2',0,0,0 ;R2
DW R1
DW Q$COLN
R2: DW CONST
DW Q$SCOD
CALL SH3
R21: POP H
ADD L
JMP R11
DB 2,'R3',0,0,0 ;R3
DW R2
DW Q$COLN
R3: DW CONST
DW Q$SCOD
LDAX D
JMP R21
DB 2,'R4',0,0,0 ;R4
DW R3
DW Q$COLN
R4: DW CONST
DW Q$SCOD
LDAX D
R41: CALL Q$BCOM
POP H
MOV A,L
CALL Q$BCOM
JMP Q$NEXT
DB 2,'R5',0,0,0 ;R5
DW R4
DW Q$COLN
R5: DW CONST
DW Q$SCOD
CALL SH3
JMP R41
DB 2,'R6',0,0,0 ;R6
DW R5
DW Q$COLN
R6: DW CONST
DW Q$SCOD
CALL SH3
R61: CALL Q$BCOM
POP H
R62: CALL Q$COMM
JMP Q$NEXT
DB 2,'R7',0,0,0 ;R7
DW R6
DW Q$COLN
R7: DW CONST
DW Q$SCOD
LDAX D
JMP R61
DB 2,'R8',0,0,0 ;R8
DW R7
DW Q$COLN
R8: DW CONST
DW Q$SCOD
LDAX D
CALL Q$BCOM
LHLD Q$Q$D
PUSH H
LXI H,0
JMP R62
;SHIFT TOP OF STACK 3 LEFT AND ADD BYTE ADDRESSED BY DE
;LEAVING RESULT IN A
SH3: POP H
XTHL
DAD H
DAD H
DAD H
LDAX D
ADD L
RET
;
;UNIT NUMBER
Q$UNIT: DW 0
;BUFFER CONTROL TABLES
BCT1: DW -1 ;BLOCK #
DW BUF1 ;BUFFER ADDR
DW BCT2 ;LINK
DW 0 ;MODIFIED FLAG
BCT2: DW -1
DW BUF2
DW 0
DW 0
;I/O BUFFERS
BUF1: DS BSIZE
BUF2: DS BSIZE
;BUFFER HANDLER VARIABLES
NEWEST: DW BCT1 ;HEAD OF BCT LIST
PREV: DW 0 ;BUFFER STRATEGY TEMPORARIES
BUFP: DW 0
BLKN: DW 0
FLAG: DB 0
;START OF USER MEMORY
;VARIABLES
;
;***************
;*** WARNING ***
;***************
;
;DO NOT ADD, DELETE, OR REARRANGE THE FOLLOWING
;VARIABLES WITHOUT MAKING CORRESPONDING CHANGES
;TO THE BASIC DEFINITIONS FILE WHICH DEFINES THE
;ADDRESSES OF THESE VARIABLES.
;BYTE VARIABLES
Q$STATE: DB 0 ;STATE
Q$CHECK: DB 0 ;CHECK
Q$COLU: DB 0 ;COLUMN
;WORD VARIABLES
Q$I: DW 0 ;.I
Q$R: DW 0 ;.R
Q$Q$L: DW 0 ;.L
Q$V: DW VSTACK+2 ;.V
Q$Q$D: DW LASTW ;.D
Q$C: DW 0 ;.C
Q$CURR: DW Q$STOI ;CURRENT
Q$RADIX: DW 8 ;RADIX
Q$PROM: DW PROM0 ;PROMPT
Q$ERRM: DW ERRM0 ;ERRMSG
Q$ENT: DW ENT0 ;ENT
Q$MEMO: DW 0 ;MEMORY
Q$LIT: DW LITER ;LIT
Q$TYI: DW Q$TTYI ;(TTYIN)
Q$TYO: DW Q$TTYO ;(TTYOU)
Q$ABORT: DW Q$AB ;(ABORT)
;INTERNAL VARIABLES
Q$EOC: DB 0 ;EOC
Q$EOL: DB 0 ;EOL
Q$ASSE: DW R8 ;ASSEMBLER<
Q$STOI: DW CONST ;STOIC<
Q$INP: DW 0 ;INP
Q$INBYT: DW 0 ;INBYTE
Q$INBLK: DW 0 ;INBLK
Q$T1: DW 0 ;TEMPORARIES
Q$T2: DW 0
Q$T3: DW 0
Q$T4: DW 0
Q$T5: DW 0
Q$T6: DW 0
Q$T7: DW 0
Q$T8: DW 0
Q$T9: DW 0
Q$T10: DW 0
;PARAMETER STACK
SSTKE: DS SSIZE
SSTACK: DS 8 ;PROTECTION AGAINST STACK UNDERFLOW
;VOCABULARY STACK
VSTACK: DW 0
DW Q$STOI
DS VSIZE
;LOOP STACK
LSTACK: DS LSIZE
;RETURN STACK
RSTACK: DS RSIZE
;COMPILE BUFFER
CBUF: DS CSIZE
;KEYBOARD BUFFER
KBUF: DS KSIZE
;END OF KERNEL
LASTW EQU $
IF NOT CPM
;
;INITIALIZATION CODE, OVERWRITTER BY DICTIONARY
;SIZE MEMORY, SET Q$MEMO, JMP TO ABORT
SIZE: LXI H,0C000H ;FIRST DEVICE ADDRESS
MVI A,55H ;ALTERNATING 1'S AND 0'S
SIZE1: DCX H ;DECREMENT TO NEXT LOC
MOV M,A ;STORE BYTE IN MEMORY
CMP M ;CAN READ IT BACK Q$
JNZ SIZE1 ;NO, CONTINUE
INX H ;BACK UP
SHLD Q$MEMO ;SET MEMORY LIMIT
JMP ABORT ;START UP STOIC
;
ENDIF
;
;
;SET UP START ADDRESS
;
IF NOT CPM
START SET SIZE
ENDIF
;
IF CPM
START SET TPA
ENDIF
;
;
END START
***EOF***