Digital Research
This commit is contained in:
2020-11-06 18:50:37 +01:00
parent 621ed8ccaf
commit 31738079c4
8481 changed files with 1888323 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
TITLE 'ASM COMMON DATA AREA'
;
; COPYRIGHT (C) 1977, 1978
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE
; CALIFORNIA, 93950
;
; COMMON DATA FOR CP/M ASSEMBLER MODULE
ORG 100H
ENDA EQU 20F0H ;END OF ASSEMBLER PROGRAM
BDOS EQU 5H ;ENTRY TO DOS, USED TO COMPUTE END MEMORY
LXI SP,ENDMOD
LHLD BDOS+1
SHLD SYMAX ;COMPUTE END OF MEMORY
JMP ENDMOD
COPY: DB ' COPYRIGHT(C) 1978, DIGITAL RESEARCH '
ORG COPY
;
; PRINT BUFFER AND PRINT BUFFER POINTER
PBMAX EQU 120 ;MAX PRINT BUFFER
PBUFF: DS PBMAX
PBP: DS 1 ;PRINT BUFFER POINTER
;
; SCANNER PARAMETERS
TOKEN: DS 1 ;CURRENT TOKEN
VALUE: DS 2 ;BINARY VALUE FOR NUMBERS
ACCLEN: DS 1 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;LENGTH OF ACCUMULATOR
ACCUM: DS ACMAX ;ACCUMULATOR (MUST FOLLLOW ACCLEN)
;
; OPERAND EXPRESSION EVALUATOR PARAMETERS
EVALUE: DS 2 ;VALUE OF EXPRESSION AFTER EVALUATION
;
; SYMBOL TABLE MODULE PARAMETERS
SYTOP: DW ENDA ;FIRST LOCATION AVAILABLE FOR SYMBOL TABLE
SYMAX: DS 2 ;LAST AVAILABLE LOCATION FOR SYMBOL TABLE
;
; MISCELLANEOUS DATA AREAS
PASS: DS 1 ;PASS # 0,1
FPC: DS 2 ;FILL ADDRESS FOR NEXT HEX RECORD
ASPC: DS 2 ;ASSEMBLER'S PSEUDO PC
SYBAS: DW ENDA ;SYMBOL TABLE BASE
SYADR: DS 2 ;CURRENT SYMBOL BASE
ENDMOD EQU ($ AND 0FF00H)+100H
END


View File

@@ -0,0 +1,727 @@
TITLE 'ASM IO MODULE'
; I/O MODULE FOR CP/M ASSEMBLER
;
ORG 200H
BOOT EQU 000H ;REBOOT LOCATION
; I/O MODULE ENTRY POINTS
JMP INIT ;INITIALIZE, START ASSEMBLER
JMP SETUP ;FILE SETUP
JMP GNC ;GET NEXT CHARACTER
JMP PNC ;PUT NEXT OUTPUT CHARACTER
JMP PNB ;PUT NEXT HEX BYTE
JMP PCHAR ;PRINT CONSOLE CHARACTER
JMP PCON ;PRINT CONSOLE BUFFER TO CRLF
JMP WOBUFF ;WRITE OUTBUFFER
JMP PERR ;PLACE ERROR CHARACTER INTO PBUFF
JMP DHEX ;PLACE HEX BYTE INTO OUTPUT BUFFER
JMP EOR ;END OF ASSEMBLY
; DATA FOR I/O MODULE
BPC: DS 2 ;BASE PC FOR CURRENT HEX RECORD
DBL: DS 1 ;HEX BUFFER LENGTH
DBUFF: DS 16 ;HEX BUFFER
;
; DISK NAMES
CDISK: DS 1 ;CURRENTLY SELECTED DISK
ADISK: DS 1 ;.ASM DISK
PDISK: DS 1 ;.PRN DISK
HDISK: DS 1 ;.HEX DISK
;
;
;
; COMMON EQUATES
QBMAX EQU 120 ;MAX PRINT SIZE
QBUFF EQU 10CH ;PRINT BUFFER
QBP EQU QBUFF+QBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU QBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR DHEX ROUTINE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
EOF EQU 1AH ;END OF FILE MARK
;
;
; DOS ENTRY POINTS
BDOS EQU 5H ;DOS ENTRY POINT
READC EQU 1 ;READ CONSOLE DEVICE
WRITC EQU 2 ;WRITE CONSOLE DEVICE
REDYC EQU 11 ;CONSOLE CHARACTER READY
SELECT EQU 14 ;SELECT DISK SPECIFIED BY REGISTER E
OPENF EQU 15 ;OPEN FILE
CLOSF EQU 16 ;CLOSE FILE
DELEF EQU 19 ;DELETE FILE
READF EQU 20 ;READ FILE
WRITF EQU 21 ;WRITE FILE
MAKEF EQU 22 ;MAKE A FILE
CSEL EQU 25 ;RETURN CURRENTLY SELECTED DISK
SETDM EQU 26 ;SET DMA ADDRESS
;
; FILE AND BUFFERING PARAMETERS
NSB EQU 8 ;NUMBER OF SOURCE BUFFERS
NPB EQU 6 ;NUMBER OF PRINT BUFFERS
NHB EQU 6 ;NUMBER OF HEX BUFFERS
;
SSIZE EQU NSB*128
PSIZE EQU NPB*128
HSIZE EQU NHB*128
;
; FILE CONTROL BLOCKS
SCB: DS 9 ;FILE NAME
DB 'ASM' ;FILE TYPE
SCBR: DS 1 ;REEL NUMBER (ZEROED IN SETUP)
DS 19 ;MISC AND DISK MAP
SCBCR: DS 1 ;CURRENT RECORD (ZEROED IN SETUP)
;
PCB: DS 9
DB 'PRN',0
DS 19
DB 0 ;RECORD TO WRITE NEXT
;
HCB: DS 9
DB 'HEX',0
DS 19
DB 0
;
; POINTERS AND BUFFERS
SBP: DW SSIZE ;NEXT CHARACTER POSITION TO READ
SBUFF: DS SSIZE
;
PBP: DW 0
PBUFF: DS PSIZE
;
HBP: DW 0
HBUFF: DS HSIZE
FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS
FNM EQU 1 ;POSITION OF FILE NAME
FLN EQU 9 ;FILE NAME LENGTH
BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS
;
SEL: ;SELECT DISK IN REG-A
LXI H,CDISK
CMP M ;SAME?
RZ
MOV M,A ;CHANGE CURRENT DISK
MOV E,A
MVI C,SELECT
CALL BDOS
RET
;
SCNP: ;SCAN THE NEXT PARAMETER
INX H
MOV A,M
CPI ' '
JZ SCNP0
SBI 'A' ;NORMALIZE
RET
SCNP0: LDA CDISK
RET
;
PCON: ;PRINT MESSAGE AT H,L TO CONSOLE DEVICE
MOV A,M
CALL PCHAR
MOV A,M
INX H
CPI CR
JNZ PCON
MVI A,LF
CALL PCHAR
RET
;
FNAME: ;FILL NAME FROM DEFAULT FILE CONTROL BLOCK
LXI D,FCB
MVI B,FLN
FNAM0: LDAX D ;GET NEXT FILE CHARACTER
CPI '?'
JZ FNERR ;FILE NAME ERROR
MOV M,A ;STORE TO FILE CNTRL BLOCK
INX H
INX D
DCR B
JNZ FNAM0 ;FOR NEXT CHARACTER
RET
;
INIT: ;SET UP STACK AND FILES, START ASSEMBLER
LXI H,TITL
CALL PCON
JMP SET0
;
OPEN: ;OPEN FILE ADDRESSED BY D,E
MVI C,OPENF
CALL BDOS
CPI 255
RNZ
; OPEN ERROR
LXI H,ERROP
CALL PCON
JMP BOOT
;
CLOSE: ;CLOSE FILE ADDRESSED BY D,E
MVI C,CLOSF
CALL BDOS
CPI 255
RNZ ;CLOSE OK
LXI H,ERRCL
CALL PCON
JMP BOOT
;
DELETE: ;DELETE FILE ADDRESSED BY D,E
MVI C,DELEF
JMP BDOS
;
MAKE: ;MAKE FILE ADDRESSED BY D,E
MVI C,MAKEF
CALL BDOS
CPI 255
RNZ
; MAKE ERROR
LXI H,ERRMA
CALL PCON
JMP BOOT
;
SELA: LDA ADISK
CALL SEL
RET
;
NPR: ;RETURN ZERO FLAG IF NO PRINT FILE
LDA PDISK
CPI 'Z'-'A'
RZ
CPI 'X'-'A' ;CONSOLE
RET
;
SELP: LDA PDISK
CALL SEL
RET
;
SELH: LDA HDISK
CALL SEL
RET
;
SET0: ;SET UP FILES FOR INPUT AND OUTPUT
LDA FCB ;GET FIRST CHARACTER
CPI ' ' ;MAY HAVE FORGOTTEN NAME
JZ FNERR ;FILE NAME ERROR
MVI C,CSEL ;CURRENT DISK?
CALL BDOS ;GET IT TO REG-A
STA CDISK
;
; SCAN PARAMETERS
LXI H,FCB+FLN-1
CALL SCNP
STA ADISK
CALL SCNP
STA HDISK
CALL SCNP
STA PDISK
;
LXI H,SCB ;ADDRESS SOURCE FILE CONTROL BLOCK
CALL FNAME ;FILE NAME OBTAINED FROM DEFAULT FCB
;
CALL NPR ;Z OR X?
JZ NOPR
LXI H,PCB ;ADDRESS PRINT FILE CONTROL BLOCK
PUSH H ;SAVE A COPY FOR OPEN
PUSH H ;SAVE A COPY FOR DELETE
CALL FNAME ;FILL PCB
CALL SELP
POP D ;FCB ADDRESS
CALL DELETE
POP D ;FCB ADDRESS
CALL MAKE
;
NOPR: ;TEST FOR HEX FILE
LDA HDISK
CPI 'Z'-'A'
JZ NOHEX
LXI H,HCB
PUSH H
PUSH H
CALL FNAME
CALL SELH
POP D
CALL DELETE
POP D
CALL MAKE
;
; FILES SET UP, CALL ASSEMBLER
NOHEX: JMP ENDMOD
;
SETUP: ;SETUP INPUT FILE FOR SOURCE PROGRAM
LXI H,SSIZE
SHLD SBP ;CAUSE IMMEDIATE READ
XRA A ;ZERO VALUE
STA SCBR ;CLEAR REEL NUMBER
STA SCBCR ;CLEAR CURRENT RECORD
STA DBL ;CLEAR HEX BUFFER LENGTH
CALL SELA
LXI D,SCB
CALL OPEN
;
RET
;
FNERR: ;FILE NAME ERROR
LXI H,ERRFN
CALL PCON
JMP BOOT
;
;
GCOMP: ;COMPARE D,E AGAINS H,L
MOV A,D
CMP H
RNZ
MOV A,E
CMP L
RET
;
GNC: ;GET NEXT CHARACTER FROM SOURCE BUFFER
PUSH B
PUSH D
PUSH H ;ENVIRONMENT SAVED
LHLD SBP
LXI D,SSIZE
CALL GCOMP
JNZ GNC2
;
; READ ANOTHER BUFFER
CALL SELA
LXI H,0
SHLD SBP
MVI B,NSB ;NUMBER OF SOURCE BUFFERS
LXI H,SBUFF
GNC0: ;READ 128 BYTES
PUSH B ;SAVE COUNT
PUSH H ;SAVE BUFFER ADDRESS
MVI C,READF
LXI D,SCB
CALL BDOS ;PERFORM THE READ
POP H ;RESTORE BUFFER ADDRESS
POP B ;RESTORE BUFFER COUNT
ORA A ;SET FLAGS
MVI C,128
JNZ GNC1
; NORMAL READ OCCURRED
LXI D,BUFF ;SOURCE BUFFER ADDRESS
MVI C,128
MOV0: LDAX D ;GET CHARACTER
MOV M,A ;STORE CHARACTER
INX D
INX H
DCR C
JNZ MOV0
; BUFFER LOADED, TRY NEXT BUFFER
;
DCR B
JNZ GNC0
JMP GNC2
;
GNC1: ;EOF OR ERROR
CPI 3 ;ALLOW 0,1,2
JNC FRERR ;FILE READ ERROR
GNCE: MVI M,EOF ;STORE AND END OF FILE CHARACTER
INX H
DCR C
JNZ GNCE ;FILL CURRENT BUFFER WITH EOF'S
;
GNC2: ;GET CHARACTER TO ACCUMULATOR AND RETURN
LXI D,SBUFF
LHLD SBP
PUSH H ;SAVE CURRENT SBP
INX H ;READY FOR NEXT READ
SHLD SBP
POP H ;RESTORE PREVIOUS SBP
DAD D ;ABSOLUTE ADDRESS OF CHARACTER
MOV A,M ;GET IT
POP H
POP D
POP B
RET
;
FRERR: LXI H,ERRFR
CALL PCON ;PRINT READ ERROR MESSAGE
JMP BOOT
;
PNC: ;SAME AT PNCF, BUT ENVIRONMENT IS SAVED FIRST
PUSH B
; CHECK FOR CONSOLE OUTPUT / NO OUTPUT
MOV B,A ;SAVE CHARACTER
LDA PDISK ;Z OR X?
CPI 'Z'-'A' ;Z NO OUTPUT
JZ PNRET
;
CPI 'X'-'A'
MOV A,B ;RECOVER CHAR FOR CON OUT
JNZ PNGO
CALL PCHAR
JMP PNRET
;
; NOT X OR Z, SO PRINT IT
PNGO: PUSH D
PUSH H
CALL PNCF
POP H
POP D
PNRET: POP B
RET
;
PNCF: ;PRINT NEXT CHARACTER
LHLD PBP
XCHG
LXI H,PBUFF
DAD D
MOV M,A ;CHARACTER STORED AT PBP IN PBUFF
XCHG ;PBP TO H,L
INX H ;POINT TO NEXT CHARACTER
SHLD PBP ;REPLACE IT
XCHG
LXI H,PSIZE
CALL GCOMP ;AT END OF BUFFER?
RNZ ;RETURN IF NOT
;
; OVERFLOW, WRITE BUFFER
CALL SELP
LXI H,0
SHLD PBP
LXI H,PBUFF
LXI D,PCB ;D,E ADDRESS FILE CONTROL BLOCK
MVI B,NPB ;NUMBER OF BUFFERS TO B
; (DROP THROUGH TO WBUFF)
;
WBUFF: ;WRITE BUFFERS STARTING AT H,L FOR B BUFFERS
; CHECK FOR EOF'S
MOV A,M
CPI EOF
RZ ;DON'T DO THE WRITE
;
PUSH B ;SAVE NUMBER OF BUFFERS
PUSH D ;SAVE FCB ADDRESS
MVI C,128 ;READY FOR MOVE
LXI D,BUFF
WBUF0: ;MOVE TO BUFFER
MOV A,M ;GET CHARACTER
STAX D ;PUT CHARACTER
INX H
INX D
DCR C
JNZ WBUF0
;
; WRITE BUFFER
POP D ;RECOVER FCB ADDRESS
PUSH D ;SAVE IT AGAIN FOR LATER
PUSH H ;SAVE BUFFER ADDRESS
MVI C,WRITF ;DOS WRITE FUNCTION
CALL BDOS
POP H ;RECOVER BUFFER ADDRESS
POP D ;RECOVER FCB ADDRESS
POP B ;RECOVER BUFFER COUNT
ORA A ;SET ERROR RETURN FLAGS
JNZ FWERR
;
; WRITE OK
DCR B
RZ ;RETURN IF NO MORE BUFFERS TO WRITE
JMP WBUFF
;
FWERR: ;ERROR IN WRITE
LXI H,ERRFW
CALL PCON ;ERROR MESSAGE OUT
JMP EORC ;TO CLOSE AND REBOOT
;
;
PNB: ;PUT NEXT HEX BYTE
PUSH B
PUSH D
PUSH H
CALL PNBF
POP H
POP D
POP B
RET
;
PNBF: ;PUT NEXT BYTE
; (SIMILAR TO THE PNCF SUBROUTINE)
LHLD HBP
XCHG
LXI H,HBUFF
DAD D
MOV M,A ;CHARACTER STORED AT HBP IN HBUFF
XCHG
INX H ;HBP INCREMENTED
SHLD HBP
XCHG ;BACK TO D,E
LXI H,HSIZE
CALL GCOMP ;EQUAL?
RNZ
;
; OVERFLOW, WRITE BUFFERS
CALL SELH
LXI H,0
SHLD HBP
LXI H,HBUFF
LXI D,HCB ;FILE CONTROL BLOCK FOR HEX FILE
MVI B,NHB
JMP WBUFF ;WRITE BUFFERS
;
PCHAR: ;PRINT CHARACTER IN REGISTER A
PUSH B
PUSH D
PUSH H
MVI C,WRITC
MOV E,A
CALL BDOS
POP H
POP D
POP B
RET
;
WOCHAR: ;WRITE CHARACTER IN REG-A WITH REFLECT AT CONSOLE IF ERROR
MOV C,A ;SAVE THE CHAR
CALL PNC ;PRINT CHAR
LDA QBUFF
CPI ' '
RZ
; ERROR IN LINE
LDA PDISK
CPI 'X'-'A'
RZ ;ALREADY PRINTED IF 'X'
;
MOV A,C ;RECOVER CHARACTER
CALL PCHAR ;PRINT IT
RET
;
WOBUFF: ;WRITE THE OUTPUT BUFFER TO THE PRINT FILE
LDA QBP ;GET CHARACTER COUNT
LXI H,QBUFF ;BASE OF BUFFER
WOB0: ORA A ;ZERO COUNT?
JZ WOBE
; NOT END, SAVE COUNT AND GET CHARACTER
MOV B,A ;SAVE COUNT
MOV A,M
CALL WOCHAR ;WRITE CHARACTER
INX H ;ADDRESS NEXT CHARACTER OF BUFFER
MOV A,B ;GET COUNT
DCR A
JMP WOB0
;
WOBE: ;END OF PRINT - ZERO QBP
STA QBP
; FOLLOW BY CR LF
MVI A,CR
CALL WOCHAR
MVI A,LF
CALL WOCHAR
LXI H,QBUFF
MVI A,QBMAX ;READY TO BLANK OUT
WOB2: MVI M,' '
INX H
DCR A
JNZ WOB2
RET
;
;
PERR: ;FILL QBUFF ERROR MESSAGE POSITION
MOV B,A ;SAVE CHARACTER
LXI H,QBUFF
MOV A,M
CPI ' '
RNZ ;DON'T CHANGE IT IF ALREADY SET
MOV M,B ;STORE ERROR CHARACTER
RET
;
EOR: ;END OF ASSEMBLER
CALL NPR ;Z OR A?
JZ EOPR
; FILL OUTPUT FILES WITH EOF'S
EOR2: LHLD PBP
MOV A,L
ORA H ;VALUE ZERO?
JZ EOPR
MVI A,EOF ;CTL-Z IS END OF FILE
CALL PNC ;PUT ENDFILES IN PRINT BUFFER
JMP EOR2 ;EVENTUALLY BUFFER IS WRITTEN
;
EOPR: ;END OF PRINT FILE, CHECK HEX
LDA HDISK
CPI 'Z'-'A'
JZ EORC
EOR0: ;WRITE TERMINATING RECORD INTO HEX FILE
LDA DBL ;MAY BE ZERO ALREADY
ORA A
CNZ WHEX ;WRITE HEX BUFFER IF NOT ZERO
LHLD FPC ;GET CURRENT FPC AS LAST ADDRESS
SHLD BPC ;RECORD LENGTH ZERO, BASE ADDRESS 0000
CALL WHEX ;WRITE HEX BUFFER
;
; NOW CLEAR OUTPUT BUFFER FOR HEX FILE
EOR1: LHLD HBP
MOV A,L
ORA H
JZ EORC
MVI A,EOF
CALL PNB
JMP EOR1
;
; CLOSE FILES AND TERMINATE
EORC:
CALL NPR
JZ EORPC
CALL SELP
LXI D,PCB
CALL CLOSE
EORPC:
LDA HDISK
CPI 'Z'-'A'
JZ EORHC
CALL SELH
LXI D,HCB
CALL CLOSE
;
EORHC:
LXI H,ENDA
CALL PCON
JMP BOOT
;
TITL: DB 'CP/M ASSEMBLER - VER 1.4',CR
ERROP: DB 'NO SOURCE FILE PRESENT',CR
ERRMA: DB 'NO DIRECTORY SPACE',CR
ERRFN: DB 'SOURCE FILE NAME ERROR',CR
ERRFR: DB 'SOURCE FILE READ ERROR',CR
ERRFW: DB 'OUTPUT FILE WRITE ERROR',CR
ERRCL: DB 'CANNOT CLOSE FILES',CR
ENDA: DB 'END OF ASSEMBLY',CR
;
DHEX: ;DATA TO HEX BUFFER (BYTE IN REG-A)
PUSH B
MOV B,A ;HOLD CHARACTER FOR 'Z' TEST
LDA HDISK
CPI 'Z'-'A'
MOV A,B ;RECOVER CHARACTER
JZ DHRET
PUSH D ;ENVIRONMENT SAVED
PUSH PSW ;SAVE DATA BYTE
LXI H,DBL ;CURRENT LENGTH
MOV A,M ;TO ACCUM
ORA A ;ZERO?
JZ DHEX3
;
; LENGTH NOT ZERO, MAY BE FULL BUFFER
CPI 16
JC DHEX1 ;BR IF LESS THAN 16 BYTES
; BUFFER FULL, DUMP IT
CALL WHEX ;DBL = 0 UPON RETURN
JMP DHEX3 ;SET BPC AND DATA BYTE
;
DHEX1: ;PARTIAL BUFFER IN PROGRESS, CHECK FOR SEQUENTIAL BYTE LOAD
LHLD FPC
XCHG
LHLD BPC ;BASE PC IN H,L
MOV C,A ;CURRENT LENGTH OF BUFFER
MVI B,0 ;IS IN B,C
DAD B ;BPC+DBL TO H,L
MOV A,E ;READY FOR COMPARE
CMP L ;EQUAL?
JNZ DHEX2 ;BR IF NOT
MOV A,D ;CHECK HO BYTE
CMP H
JZ DHEX4 ;BR IF SAME ADDRESS
;
DHEX2: ;NON SEQUENTIAL ADDRESS, DUMP AND CHANGE BASE ADDRESS
CALL WHEX
DHEX3: ;SET NEW BASE
LHLD FPC
SHLD BPC
;
DHEX4: ;STORE DATA BYTE AND INC DBL
LXI H,DBL
MOV E,M ;LENGTH TO REG-E
INR M ;DBL=DBL+1
MVI D,0 ;HIGH ORDER ZERO FOR DOUBLE ADD
LXI H,DBUFF
DAD D ;DBUFF+DBL TO H,L
POP PSW ;RESTORE DATA BYTE
MOV M,A ;INTO DATA BUFFER
POP D
DHRET: POP B ;ENVIRONMENT RESTORED
RET
;
WRC: ;WRITE CHARACTER WITH CHECK SUM IN D
PUSH PSW
RRC
RRC
RRC
RRC
ANI 0FH
CALL HEXC ;OUTPUT HEX CHARACTER
POP PSW ;RESTORE BYTE
PUSH PSW ;SAVE A VERSION
ANI 0FH
CALL HEXC ;WRITE LOW NIBBLE
POP PSW ;RESTORE BYTE
ADD D ;COMPUTE CHECKSUM
MOV D,A ;SAVE CS
RET
;
HEXC: ;WRITE CHARACTER
ADI 90H
DAA
ACI 40H
DAA
JMP PNB ;PUT BYTE
;
WHEX: ;WRITE CURRENT HEX BUFFER
MVI A,':' ;RECORD HEADER
CALL PNB ;PUT BYTE
LXI H,DBL ;RECORD LENGTH ADDRESS
MOV E,M ;LENGTH TO REG-E
XRA A ;ZERO TO REG-A
MOV D,A ;CLEAR CHECKSUM
MOV M,A ;LENGTH IS ZEROED FOR NEXT WRITE
LHLD BPC ;BASE ADDRESS FOR RECORD
MOV A,E ;LENGTH TO A
CALL WRC ;WRITE HEX VALUE
MOV A,H ;HIGH ORDER BASE ADDR
CALL WRC ;WRITE HO BYTE
MOV A,L ;LOW ORDER BASE ADDR
CALL WRC ;WRITE LO BYTE
XRA A ;ZERO TO A
CALL WRC ;WRITE RECORD TYPE 00
MOV A,E ;CHECK FOR LENGTH 0
ORA A
JZ WHEX1
;
; NON - ZERO, WRITE DATA BYTES
LXI H,DBUFF
WHEX0: MOV A,M ;GET BYTE
INX H
CALL WRC ;WRITE DATA BYTE
DCR E ;END OF BUFFER?
JNZ WHEX0
;
; END OF DATA BYTES, WRITE CHECK SUM
WHEX1: XRA A
SUB D ;COMPUTE CHECKSUM
CALL WRC
;
; SEND CRLF AT END OF RECORD
MVI A,CR
CALL PNB
MVI A,LF
CALL PNB
RET
;
;
;
ENDMOD EQU ($ AND 0FFE0H)+20H
END


View File

@@ -0,0 +1,405 @@
TITLE 'ASM SCANNER MODULE'
ORG 1100H
JMP ENDMOD ;END OF THIS MODULE
JMP INITS ;INITIALIZE THE SCANNER
JMP SCAN ;CALL THE SCANNER
;
;
; ENTRY POINTS IN I/O MODULE
IOMOD EQU 200H
GNCF EQU IOMOD+6H
WOBUFF EQU IOMOD+15H
PERR EQU IOMOD+18H
;
LASTC: DS 1 ;LAST CHAR SCANNED
NEXTC: DS 1 ;LOOK AHEAD CHAR
STYPE: DS 1 ;RADIX INDICATOR
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
BINV EQU 2
OCTV EQU 8
DECV EQU 10
HEXV EQU 16
CR EQU 0DH
LF EQU 0AH
EOF EQU 1AH
TAB EQU 09H ;TAB CHARACTER
;
;
; UTILITY SUBROUTINES
GNC: ;GET NEXT CHARACTER AND ECHO TO PRINT FILE
CALL GNCF
PUSH PSW
CPI CR
JZ GNC0
CPI LF ;IF LF THEN DUMP CURRENT BUFFER
JZ GNC0
;
;NOT A CR OR LF, PLACE INTO BUFFER IF THERE IS ENOUGH ROOM
LDA PBP
CPI PBMAX
JNC GNC0
; ENOUGH ROOM, PLACE INTO BUFFER
MOV E,A
MVI D,0 ;DOUBLE PRECISION PBP IN D,E
INR A
STA PBP ;INCREMENTED PBP IN MEMORY
LXI H,PBUFF
DAD D ;PBUFF(PBP)
POP PSW
MOV M,A ;PBUFF(PBP) = CHAR
RET
GNC0: ;CHAR NOT PLACED INTO BUFFER
POP PSW
RET
;
INITS: ;INITIALIZE THE SCANNER
CALL ZERO
STA NEXTC ;CLEAR NEXT CHARACTER
STA PBP
MVI A,LF ;SET LAST CHAR TO LF
STA LASTC
CALL WOBUFF ;CLEAR BUFFER
MVI A,16 ;START OF PRINT LINE
STA PBP
RET
;
ZERO: XRA A
STA ACCLEN
STA STYPE
RET
;
SAVER: ;STORE THE NEXT CHARACTER INTO THE ACCUMULATOR AND UPDATE ACCLEN
LXI H,ACCLEN
MOV A,M
CPI ACMAX
JC SAV1 ;JUMP IF NOT UP TO LAST POSITION
MVI M,0
CALL ERRO
SAV1: MOV E,M ;D,E WILL HOLD INDEX
MVI D,0
INR M ;ACCLEN INCREMENTED
INX H ;ADDRESS ACCUMULATOR
DAD D ;ADD INDEX TO ACCUMULATOR
LDA NEXTC ;GET CHARACTER
MOV M,A ;INTO ACCUMULATOR
RET
;
TDOLL: ;TEST FOR DOLLAR SIGN, ASSUMING H,L ADDRESS NEXTC
MOV A,M
CPI '$'
RNZ
XRA A ;TO GET A ZERO
MOV M,A ;CLEARS NEXTC
RET ;WITH ZERO FLAG SET
;
NUMERIC: ;CHECK NEXTC FOR NUMERIC, RETURN ZERO FLAG IF NOT NUMERIC
LDA NEXTC
SUI '0'
CPI 10
; CARRY RESET IF NUMERIC
RAL
ANI 1B ;ZERO IF NOT NUMERIC
RET
;
HEX: ;RETURN ZERO FLAG IF NEXTC IS NOT HEXADECIMAL
CALL NUMERIC
RNZ ;RETURNS IF 0-9
LDA NEXTC
SUI 'A'
CPI 6
; CARRY SET IF OUT OF RANGE
RAL
ANI 1B
RET
;
LETTER: ;RETURN ZERO FLAG IF NEXTC IS NOT A LETTER
LDA NEXTC
SUI 'A'
CPI 26
RAL
ANI 1B
RET
;
ALNUM: ;RETURN ZERO FLAG IF NOT ALPHANUMERIC
CALL LETTER
RNZ
CALL NUMERIC
RET
;
TRANS: ;TRANSLATE TO UPPER CASE
LDA NEXTC
CPI 'A' OR 1100000B ;LOWER CASE A
RC ;CARRY IF LESS THAN LOWER A
CPI ('Z' OR 1100000B)+1 ;LOWER CASE Z
RNC ;NO CARRY IF GREATER THAN LOWER Z
ANI 1011111B ;CONVERT TO UPPER CASE
STA NEXTC
RET
;
GNCN: ;GET CHARACTER AND STORE TO NEXTC
CALL GNC
STA NEXTC
CALL TRANS ;TRANSLATE TO UPPER CASE
RET
;
EOLT: ;END OF LINE TEST FOR COMMENT SCAN
CPI CR
RZ
CPI EOF
RZ
CPI '!'
RET
;
SCAN: ;FIND NEXT TOKEN IN INPUT STREAM
XRA A
STA TOKEN
CALL ZERO
;
; DEBLANK
DEBL: LDA NEXTC
CPI TAB ;TAB CHARACTER TREATED AS BLANK OUTSIDE STRING
JZ DEB0
CPI ';' ;MAY BE A COMMENT
JZ DEB1 ;DEBLANK THROUGH COMMENT
CPI '*' ;PROCESSOR TECH COMMENT
JNZ DEB2 ;NOT *
LDA LASTC
CPI LF ;LAST LINE FEED?
JNZ DEB2 ;NOT LF*
; COMMENT FOUND, REMOVE IT
DEB1: CALL GNCN
CALL EOLT ;CR, EOF, OR !
JZ FINDL ;HANDLE END OF LINE
JMP DEB1 ;OTHERWISE CONTINUE SCAN
DEB2: ORI ' ' ;MAY BE ZERO
CPI ' '
JNZ FINDL
DEB0: CALL GNCN ;GET NEXT AND STORE TO NEXTC
JMP DEBL
;
; LINE DEBLANKED, FIND TOKEN TYPE
FINDL: ;LOOK FOR LETTER, DECIMAL DIGIT, OR STRING QUOTE
CALL LETTER
JZ FIND0
MVI A,IDEN
JMP STOKEN
;
FIND0: CALL NUMERIC
JZ FIND1
MVI A,NUMB
JMP STOKEN
;
FIND1: LDA NEXTC
CPI ''''
JNZ FIND2
XRA A
STA NEXTC ;DON'T STORE THE QUOTE
MVI A,STRNG
JMP STOKEN
;
FIND2: ;ASSUME IT IS A SPECIAL CHARACTER
CPI LF ;IF LF THEN DUMP THE BUFFER
JNZ FIND3
; LF FOUND
LDA PASS
ORA A
CNZ WOBUFF
LXI H,PBUFF ;CLEAR ERROR CHAR ON BOTH PASSES
MVI M,' '
MVI A,16
STA PBP ;START NEW LINE
FIND3: MVI A,SPECL
;
STOKEN: STA TOKEN
;
;
; LOOP WHILE CURRENT ITEM IS ACCUMULATING
SCTOK: LDA NEXTC
STA LASTC ;SAVE LAST CHARACTER
ORA A
CNZ SAVER ;STORE CHARACTER INTO ACCUM IF NOT ZERO
CALL GNCN ;GET NEXT TO NEXTC
LDA TOKEN
CPI SPECL
RZ ;RETURN IF SPECIAL CHARACTER
CPI STRNG
CNZ TRANS ;TRANSLATE TO UPPER CASE IF NOT IN STRING
LXI H,NEXTC
LDA TOKEN
;
CPI IDEN
JNZ SCT2
;
; ACCUMULATING AN IDENTIFIER
CALL TDOLL ;$?
JZ SCTOK ;IF SO, SKIP IT
CALL ALNUM ;ALPHA NUMERIC?
RZ ;RETURN IF END
; NOT END OF THE IDENTIFIER
JMP SCTOK
;
SCT2: ;NOT SPECIAL OR IDENT, CHECK NUMBER
CPI NUMB
JNZ SCT3
;
; ACCUMULATING A NUMBER, CHECK FOR $
CALL TDOLL
JZ SCTOK ;SKIP IF FOUND
CALL HEX ;HEX CHARACTER?
JNZ SCTOK ;STORE IT IF FOUND
; END OF NUMBER, LOOK FOR RADIX INDICATOR
;
LDA NEXTC
CPI 'O' ;OCTAL INDICATOR
JZ NOCT
CPI 'Q' ;OCTAL INDICATOR
JNZ NUM2
;
NOCT: ;OCTAL
MVI A,OCTV
JMP SSTYP
;
NUM2: CPI 'H'
JNZ NUM3
MVI A,HEXV
SSTYP: STA STYPE
XRA A
STA NEXTC ;CLEARS THE LOOKAHEAD CHARACTER
JMP NCON
;
; RADIX MUST COME FROM ACCUM
NUM3: LDA LASTC
CPI 'B'
JNZ NUM4
MVI A,BINV
JMP SSTY1
;
NUM4: CPI 'D'
MVI A,DECV
JNZ SSTY2
SSTY1: LXI H,ACCLEN
DCR M ;ACCLEN DECREMENTED TO REMOVE RADIX INDICATOR
SSTY2: STA STYPE
;
NCON: ;NUMERIC CONVERSION OCCURS HERE
LXI H,0
SHLD VALUE ;VALUE ACCUMULATES BINARY EQUIVALENT
LXI H,ACCLEN
MOV C,M ;C=ACCLEN
INX H ;ADDRESSES ACCUM
CLOP: ;NEXT DIGIT IS PROCESSED HERE
MOV A,M
INX H ;READY FOR NEXT LOOP
CPI 'A'
JNC CLOP1 ;NOT HEX A-F
SUI '0' ;NORMALIZE
JMP CLOP2
;
CLOP1: ;HEX A-F
SUI 'A'-10
CLOP2: ;CHECK SIZE AGAINST RADIX
PUSH H ;SAVE ACCUM ADDR
PUSH B ;SAVE CURRENT POSITION
MOV C,A
LXI H,STYPE
CMP M
CNC ERRV ;VALUE ERROR IF DIGIT>=RADIX
MVI B,0 ;DOUBLE PRECISION DIGIT
MOV A,M ;RADIX TO ACCUMULATOR
LHLD VALUE
XCHG ;VALUE TO D,E - ACCUMULATE RESULT IN H,L
LXI H,0 ;ZERO ACCUMULATOR
CLOP3: ;LOOP UNTIL RADIX GOES TO ZERO
ORA A
JZ CLOP4
RAR ;TEST LSB
JNC TTWO ;SKIP SUMMING OPERATION IF LSB=0
DAD D ;ADD IN VALUE
TTWO: ;MULTIPLY VALUE * 2 FOR SHL OPERATION
XCHG
DAD H
XCHG
JMP CLOP3
;
;
CLOP4: ;END OF NUMBER CONVERSION
DAD B ;DIGIT ADDED IN
SHLD VALUE
POP B
POP H
DCR C ;MORE DIGITS?
JNZ CLOP
RET ;DONE WITH THE NUMBER
;
SCT3: ;MUST BE A STRING
LDA NEXTC
CPI CR ;END OF LINE?
JZ ERRO ;AND RETURN
CPI ''''
JNZ SCTOK
CALL GNCN
CPI ''''
RNZ ;RETURN IF SINGLE QUOTE ENCOUNTERED
JMP SCTOK ;OTHERWISE TREAT AS ONE QUOTE
;
; END OF SCANNER
;
; ERROR MESSAGE ROUTINES
ERRV: ;'V' VALUE ERROR
PUSH PSW
MVI A,'V'
JMP ERR
;
ERRO: ;'O' OVERFLOW ERROR
PUSH PSW
MVI A,'O'
JMP ERR
;
ERR: ;PRINT ERROR MESSAGE
PUSH B
PUSH H
CALL PERR
POP H
POP B
POP PSW
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H
END


View File

@@ -0,0 +1,382 @@
TITLE 'ASM SYMBOL TABLE MODULE'
; SYMBOL TABLE MANIPULATION MODULE
;
ORG 1340H
IOMOD EQU 200H ;IO MODULE ENTRY POINT
PCON EQU IOMOD+12H
EOR EQU IOMOD+1EH
;
;
; ENTRY POINTS TO SYMBOL TABLE MODULE
JMP ENDMOD
JMP INISY
JMP LOOKUP
JMP FOUND
JMP ENTER
JMP SETTY
JMP GETTY
JMP SETVAL
JMP GETVAL
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
SYBAS EQU ASPC+2 ;BASE OF SYMBOL TABLE
SYADR EQU SYBAS+2 ;CURRENT SYMBOL BEING ACCESSED
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
CR EQU 0DH
;
; DATA AREAS
; SYMBOL TABLE BEGINS AT THE END OF THIS MODULE
FIXD EQU 5 ;5 BYTES OVERHEAD WITH EACH SYMBOL ENTRY
; 2BY COLLISION, 1BY TYPE/LEN, 2BY VALUE
HSIZE EQU 128 ;HASH TABLE SIZE
HMASK EQU HSIZE-1 ;HASH MASK FOR CODING
HASHT: DS HSIZE*2 ;HASH TABLE
HASHC: DS 1 ;HASH CODE AFTER CALL ON LOOKUP
;
; SYMBOL TABLE ENTRY FORMAT IS
; -----------------
; : HIGH VAL BYTE :
; -----------------
; : LOW VAL BYTE :
; -----------------
; : CHARACTER N :
; -----------------
; : ... :
; -----------------
; : CHARACTER 1 :
; -----------------
; : TYPE : LENG :
; -----------------
; : HIGH COLLISION:
; -----------------
; SYADR= : LOW COLLISION :
; -----------------
;
; WHERE THE LOW/HIGH COLLISION FIELD ADDRESSES ANOTHER ENTRY WITH
; THE SAME HASH CODE (OR ZERO IF THE END OF CHAIN), TYPE DESCRIBES
; THE ENTRY TYPE (GIVEN BELOW), LENG IS THE NUMBER OF CHARACTERS IN
; THE SYMBOL PRINTNAME -1 (I.E., LENG=0 IS A SINGLE CHARACTER PRINT-
; NAME, WHILE LENG=15 INDICATES A 16 CHARACTER NAME). CHARACTER 1
; THROUGH N GIVE THE PRINTNAME CHARACTERS IN ASCII UPPER CASE (ALL
; LOWER CASE NAMES ARE TRANSLATED ON INPUT), AND THE LOW/HIGH VALUE
; GIVE THE PARTICULAR ADDRESS OR CONSTANT VALUE ASSOCIATED WITH THE
; NAME. THE REPRESENTATION OF MACROS DIFFERS IN THE FIELDS WHICH
; FOLLOW THE VALUE FIELD (MACROS ARE NOT CURRENTLY IMPLEMENTED).
;
; THE TYPE FIELD CONSISTS OF FOUR BITS WHICH ARE ASSIGNED AS
; FOLLOWS:
;
; 0000 UNDEFINED SYMBOL
; 0001 LOCAL LABELLED PROGRAM
; 0010 LOCAL LABELLED DATA
; 0011 (UNUSED)
; 0100 EQUATE
; 0101 SET
; 0110 MACRO
; 0111 (UNUSED)
;
; 1000 (UNUSED)
; 1001 EXTERN LABELLED PROGRAM
; 1010 EXTERN LABELLED DATA
; 1011 REFERENCE TO MODULE
; 1100 (UNUSED)
; 1101 GLOBAL UNDEFINED SYMBOL
; 1110 GLOBAL LABELLED PROGRAM
; 1111 (UNUSED)
;
; TYPE DEFINITIONS
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL ATTRIBUTE
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL ATTRIBUTE
;
;
INISY: ;INITIALIZE THE SYMBOL TABLE
LXI H,HASHT ;ZERO THE HASH TABLE
MVI B,HSIZE
XRA A ;CLEAR ACCUM
INI0:
MOV M,A
INX H
MOV M,A ;CLEAR DOUBLE WORD
INX H
DCR B
JNZ INI0
;
; SET SYMBOL TABLE POINTERS
LXI H,0
SHLD SYADR
;
RET
;
CHASH: ;COMPUTE HASH CODE FOR CURRENT ACCUMULATOR
LXI H,ACCLEN
MOV B,M ;GET ACCUM LENGTH
XRA A ;CLEAR ACCUMULATOR
CH0: INX H ;MOVE TO FIRST/NEXT CHARACTER POSITION
ADD M ;ADD WITH OVERFLOW
DCR B
JNZ CH0
ANI HMASK ;MASK BITS FOR MODULO HZISE
STA HASHC ;FILL HASHC WITH RESULT
RET
;
SETLN: ;SET THE LENGTH FIELD OF THE CURRENT SYMBOL
MOV B,A ;SAVE LENGTH IN B
LHLD SYADR
INX H
INX H
MOV A,M ;GET TYPE/LENGTH FIELD
ANI 0F0H ;MASK OUT TYPE FIELD
ORA B ;MASK IN LENGTH
MOV M,A
RET
;
GETLN: ;GET THE LENGTH FIELD TO REG-A
LHLD SYADR
INX H
INX H
MOV A,M
ANI 0FH
INR A ;LENGTH IS STORED AS VALUE - 1
RET
;
FOUND: ;FOUND RETURNS TRUE IF SYADR IS NOT ZERO (TRUE IS NZ FLAG HERE)
LHLD SYADR
MOV A,L
ORA H
RET
;
LOOKUP: ;LOOK FOR SYMBOL IN ACCUMULATOR
CALL CHASH ;COMPUTE HASH CODE
; NORMALIZE IDENTIFIER TO 16 CHARACTERS
LXI H,ACCLEN
MOV A,M
CPI 17
JC LENOK
MVI M,16
LENOK:
; LOOK FOR SYMBOL THROUGH HASH TABLE
LXI H,HASHC
MOV E,M
MVI D,0 ;DOUBLE HASH CODE IN D,E
LXI H,HASHT ;BASE OF HASH TABLE
DAD D
DAD D ;HASHT(HASHC)
MOV E,M ;LOW ORDER ADDRESS
INX H
MOV H,M
MOV L,E ;HEADER TO LIST OF SYMBOLS IS IN H,L
LOOK0: SHLD SYADR
CALL FOUND
RZ ;RETURN IF SYADR BECOMES ZERO
;
; OTHERWISE EXAMINE CHARACTER STRING FOR MATCH
CALL GETLN ;GET LENGTH TO REG-A
LXI H,ACCLEN
CMP M
JNZ LCOMP
;
; LENGTH MATCH, TRY TO MATCH CHARACTERS
MOV B,A ;STRING LENGTH IN B
INX H ;HL ADDRESSES ACCUM
XCHG ;TO D,E
LHLD SYADR
INX H
INX H
INX H ;ADDRESSES CHARACTERS
LOOK1: LDAX D ;NEXT CHARACTER FROM ACCUM
CMP M ;NEXT CHARACTER IN SYMBOL TABLE
JNZ LCOMP
; CHARACTER MATCHED, INCREMENT TO NEXT
INX D
INX H
DCR B
JNZ LOOK1
;
; COMPLETE MATCH AT CURRENT SYMBOL, SYADR IS SET
RET
;
LCOMP: ;NOT FOUND, MOVE SYADR DOWN ONE COLLISION ADDRESS
LHLD SYADR
MOV E,M
INX H
MOV D,M ;COLLISION ADDRESS IN D,E
XCHG
JMP LOOK0
;
;
ENTER: ;ENTER SYMBOL IN ACCUMULATOR
; ENSURE THERE IS ENOUGH SPACE IN THE TABLE
LXI H,ACCLEN
MOV E,M
MVI D,0 ;DOUBLE PRECISION ACCLEN IN D,E
LHLD SYTOP
SHLD SYADR ;NEXT SYMBOL LOCATION
DAD D ;SYTOP+ACCLEN
LXI D,FIXD ;FIXED DATA/SYMBOL
DAD D ;HL HAS NEXT TABLE LOCATION FOR SYMBOL
XCHG ;NEW SYTOP IN D,E
LHLD SYMAX ;MAXIMUM SYMTOP VALUE
MOV A,E
SUB L ;COMPUTE 16-BIT DIFFERENCE
MOV A,D
SBB H
XCHG ;NEW SYTOP IN H,L
JNC OVERER ;OVERFLOW IN TABLE
;
; OTHERWISE NO ERROR
SHLD SYTOP ;SET NEW TABLE TOP
LHLD SYADR ;SET COLLISION FIELD
XCHG ;CURRENT SYMBOL ADDRESS TO D,E
LXI H,HASHC ;HASH CODE FOR CURRENT SYMBOL TO H,L
MOV C,M ;LOW BYTE
MVI B,0 ;DOUBLE PRECISION VALUE IN B,C
LXI H,HASHT ;BASE OF HASH TABLE
DAD B
DAD B ;HASHT(HASHC) IN H,L
; D,E ADDRESSES CURRENT SYMBOL - CHANGE LINKS
MOV C,M ;LOW ORDER OLD HEADER
INX H
MOV B,M ;HIGH ORDER OLD HEADER
MOV M,D ;HIGH ORDER NEW HEADER TO HASH TABLE
DCX H
MOV M,E ;LOW ORDER NEW HEADER TO HASH TABLE
XCHG ;H,L HOLDS SYMBOL TABLE ADDRESS
MOV M,C ;LOW ORDER OLD HEADER TO COLLISION FIELD
INX H
MOV M,B ;HIGH ORDER OLD HEADER TO COLLISION FIELD
;
; HASH CHAIN NOW REPAIRED FOR THIS ENTRY, COPY THE PRINTNAME
LXI D,ACCLEN
LDAX D ;GET SYMBOL LENGTH
CPI 17 ;LARGER THAN 16 SYMBOLS?
JC ENT1
MVI A,16 ;TRUNCATE TO 16 CHARACTERS
; COPY LENGTH FIELD, FOLLOWED BY PRINTNAME CHARACTERS
ENT1: MOV B,A ;COPY LENGTH TO B
DCR A ;1-16 CHANGED TO 0-15
INX H ;FOLLOWING COLLISION FIELD
MOV M,A ;STORE LENGTH WITH UNDEFINED TYPE (0000)
ENT2: INX H
INX D
LDAX D
MOV M,A ;STORE NEXT CHARACTER OF PRINTNAME
DCR B ;LENGTH=LENGTH-1
JNZ ENT2 ;FOR ANOTHER CHARACTER
;
; PRINTNAME COPIED, ZERO THE VALUE FIELD
XRA A ;ZERO A
INX H ;LOW ORDER VALUE
MOV M,A
INX H
MOV M,A ;HIGH ORDER VALUE
RET
;
OVERER: ;OVERFLOW IN SYMBOL TABLE
LXI H,ERRO
CALL PCON
JMP EOR ;END OF EXECUTION
ERRO: DB 'SYMBOL TABLE OVERFLOW',CR
;
SETTY: ;SET CURRENT SYMBOL TYPE TO VALUE IN REG-A
RAL
RAL
RAL
RAL
ANI 0F0H ;TYPE MOVED TO HIGH ORDER 4-BITS
MOV B,A ;SAVE IT IN B
LHLD SYADR ;BASE OF SYMBOL TO ACCESS
INX H
INX H ;ADDRESS OF TYPE/LENGTH FIELD
MOV A,M ;GET IT AND MASK
ANI 0FH ;LEAVE LENGTH
ORA B ;MASK IN TYPE
MOV M,A ;STORE IT
RET
;
GETTY: ;RETURN THE TYPE OF THE VALUE IN CURRENT SYMBOL
LHLD SYADR
INX H
INX H
MOV A,M
RAR
RAR
RAR
RAR
ANI 0FH ;TYPE MOVED TO LOW 4-BITS OF REG-A
RET
;
VALADR: ;GET VALUE FIELD ADDRESS FOR CURRENT SYMBOL
CALL GETLN ;PRINTNAME LENGTH TO ACCUM
LHLD SYADR ;BASE ADDRESS
MOV E,A
MVI D,0
DAD D ;BASE(LEN)
INX H
INX H ;FOR COLLISION FIELD
INX H ;FOR TYPE/LEN FIELD
RET ;WITH H,L ADDRESSING VALUE FIELD
;
SETVAL: ;SET THE VALUE FIELD OF THE CURRENT SYMBOL
; VALUE IS SENT IN H,L
PUSH H ;SAVE VALUE TO SET
CALL VALADR
POP D ;POP VALUE TO SET, HL HAS ADDRESS TO FILL
MOV M,E
INX H
MOV M,D ;FIELD SET
RET
;
GETVAL: ;GET THE VALUE FIELD OF THE CURRENT SYMBOL TO H,L
CALL VALADR ;ADDRESS OF VALUE FIELD TO H,L
MOV E,M
INX H
MOV D,M
XCHG
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H
END


View File

@@ -0,0 +1,415 @@
TITLE 'ASM TABLE SEARCH MODULE'
ORG 15A0H
JMP ENDMOD ;TO NEXT MODULE
JMP BSEAR
JMP BGET
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
CR EQU 0DH ;CARRIAGE RETURN
;
;
; TABLE DEFINITIONS
;
; TYPES
XBASE EQU 0 ;START OF OPERATORS
; O1 THROUGH O15 DENOTE OPERATIONS
RT EQU 16
PT EQU RT+1 ;RT IS REGISTER TYPE, PT IS PSEUDO OPERATION
OBASE EQU PT+1
O1 EQU OBASE+1 ;SIMPLE
O2 EQU OBASE+2 ;LXI
O3 EQU OBASE+3 ;DAD
O4 EQU OBASE+4 ;PUSH/POP
O5 EQU OBASE+5 ;JMP/CALL
O6 EQU OBASE+6 ;MOV
O7 EQU OBASE+7 ;MVI
O8 EQU OBASE+8 ;ACC IMMEDIATE
O9 EQU OBASE+9 ;LDAX/STAX
O10 EQU OBASE+10 ;LHLD/SHLD/LDA/STA
O11 EQU OBASE+11 ;ACCUM REGISTER
O12 EQU OBASE+12 ;INC/DEC
O13 EQU OBASE+13 ;INX/DCX
O14 EQU OBASE+14 ;RST
O15 EQU OBASE+15 ;IN/OUT
;
; X1 THROUGH X15 DENOTE OPERATORS
X1 EQU XBASE ;*
X2 EQU XBASE+1 ;/
X3 EQU XBASE+2 ;MOD
X4 EQU XBASE+3 ;SHL
X5 EQU XBASE+4 ;SHR
X6 EQU XBASE+5 ;+
X7 EQU XBASE+6 ;-
X8 EQU XBASE+7 ;UNARY -
X9 EQU XBASE+8 ;NOT
X10 EQU XBASE+9 ;AND
X11 EQU XBASE+10;OR
X12 EQU XBASE+11;XOR
X13 EQU XBASE+12;(
X14 EQU XBASE+13;)
X15 EQU XBASE+14;,
X16 EQU XBASE+15;CR
;
;
;
;
; RESERVED WORD TABLES
;
; BASE ADDRESS VECTOR FOR CHARACTERS
CINX: DW CHAR1 ;LENGTH 1 BASE
DW CHAR2 ;LENGTH 2 BASE
DW CHAR3 ;LENGTH 3 BASE
DW CHAR4 ;LENGTH 4 BASE
DW CHAR5 ;LENGTH 5 BASE
DW CHAR6 ;LENGTH 6 BASE
;
CMAX EQU ($-CINX)/2-1 ;LARGEST STRING TO MATCH
;
CLEN: ;LENGTH VECTOR GIVES THE NUMBER OF ITEMS IN EACH TABLE
DB CHAR2-CHAR1
DB (CHAR3-CHAR2)/2
DB (CHAR4-CHAR3)/3
DB (CHAR5-CHAR4)/4
DB (CHAR6-CHAR5)/5
;
TVINX: ;TABLE OF TYPE,VALUE PAIRS FOR EACH RESERVED SYMBOL
DW TV1
DW TV2
DW TV3
DW TV4
DW TV5
;
; CHARACTER VECTORS FOR 1,2,3,4, AND 5 CHARACTER NAMES
CHAR1: DB CR,'()*'
DB '+'
DB ',-/A'
DB 'BCDE'
DB 'HLM'
;
CHAR2: DB 'DBDIDSDW'
DB 'EIIFINOR'
DB 'SP'
;
CHAR3: DB 'ACIADCADDADI'
DB 'ANAANDANICMA'
DB 'CMCCMPCPIDAA'
DB 'DADDCRDCXEND'
DB 'EQUHLTINRINX'
DB 'JMPLDALXIMOD'
DB 'MOVMVINOPNOT'
DB 'ORAORGORIOUT'
DB 'POPPSWRALRAR'
DB 'RETRLCRRCRST'
DB 'SBBSBISETSHL'
DB 'SHRSTASTCSUB'
DB 'SUIXORXRAXRI'
;
CHAR4: DB 'CALLENDMLDAXLHLDPCHL'
DB 'PUSHSHLDSPHLSTAX'
DB 'XCHGXTHL'
;
CHAR5: DB 'ENDIFMACROTITLE'
;
CHAR6: ;END OF CHARACTER VECTOR
;
TV1: ;TYPE,VALUE PAIRS FOR CHAR1 VECTOR
DB X16,10, X13,20 ;CR (
DB X14,30, X1,80 ;) *
DB X6,70 ;+
DB X15,10, X7,70 ;, -
DB X2,80, RT,7 ;/ A
DB RT,0, RT,1 ;B C
DB RT,2, RT,3 ;D E
DB RT,4, RT,5 ;H L
DB RT,6 ;M
;
TV2: ;TYPE,VALUE PAIRS FOR CHAR2 VECTOR
DB PT,1, O1,0F3H ;DB DI
DB PT,2, PT,3 ;DS DW
DB O1,0FBH, PT,8 ;EI IF
DB O15,0DBH, X11,40 ;IN OR
DB RT,6 ;SP
;
;
TV3: ;TYPE,VALUE PAIRS FOR CHAR3 VECTOR
DB O8,0CEH, O11,88H ;ACI ADC
DB O11,80H, O8,0C6H ;ADD ADI
DB O11,0A0H, X10,50 ;ANA AND
DB O8,0E6H, O1,2FH ;ANI CMA
DB O1,3FH, O11,0B8H ;CMC CMP
DB O8,0FEH, O1,27H ;CPI DAA
DB O3,09H, O12,05H ;DAD DCR
DB O13,0BH, PT,4 ;DCX END
DB PT,7, O1,76H ;EQU HLT
DB O12,04H, O13,03H ;INR INX
DB O5,0C3H, O10,3AH ;JMP LDA
DB O2,01H, X3,80 ;LXI MOD
DB O6,40H, O7,06H ;MOV MVI
DB O1,00H, X9,60 ;NOP NOT
DB O11,0B0H, PT,10 ;ORA ORG
DB O8,0F6H, O15,0D3H ;ORI OUT
DB O4,0C1H, RT,6 ;POP PSW
DB O1,17H, O1,1FH ;RAL RAR
DB O1,0C9H, O1,07H ;RET RLC
DB O1,0FH, O14,0C7H ;RRC RST
DB O11,098H, O8,0DEH ;SBB SBI
DB PT,11, X4,80 ;SET SHL
DB X5,80, O10,32H ;STA STC
DB O1,37H, O11,90H ;STC SUB
DB O8,0D6H, X12,40 ;SUI XOR
DB O11,0A8H, O8,0EEH ;XRA XRI
;
;
TV4: ;TYPE,VALUE PAIRS FOR CHAR4 VECTOR
DB O5,0CDH ;CALL
DB PT,6, O9,0AH ;ENDM LDAX
DB O10,02AH, O1,0E9H ;LHLD PCHL
DB O4,0C5H, O10,22H ;PUSH SHLD
DB O1,0F9H, O9,02H ;SPHL STAX
DB O1,0EBH, O1,0E3H ;XCHG XTHL
;
TV5: ;TYPE,VALUE PAIRS FOR CHAR5 VECTOR
DB PT,5, PT,9 ;ENDIF MACRO
DB PT,12 ;TITLE
;
SUFTAB: ;TABLE OF SUFFIXES FOR J C AND R OPERATIONS
DB 'NZZ NCC POPEP M '
;
BSEAR: ;BINARY SEARCH MNEMONIC TABLE
; INPUT: UR = UPPER BOUND OF TABLE (I.E., TABLE LENGTH-1)
; SR = SIZE OF EACH TABLE ELEMENT
; H,L ADDRESS BASE OF TABLE TO SEARCH
; OUTPUT: ZERO FLAG INDICATES MATCH WAS FOUND, IN WHICH CASE
; THE ACCUMULATOR CONTAINS AN INDEX TO THE ELEMENT
; NOT ZERO FLAG INDICATES NO MATCH FOUND IN TABLE
;
UR EQU B ;UPPER BOUND REGISTER
LR EQU C ;LOWER BOUND REGISTER
SR EQU D ;SIZE REGISTER
MR EQU E ;MIDDLE POINTER REGISTER
SP1 EQU B ;SIZE PRIME, USED IN COMPUTING MIDDLE POSITON
SP1P EQU C ;ANOTHER COPY OF SIZE PRIME
KR EQU H ;K
;
MVI MR,255 ;MARK M <> OLD M
INR UR ;U=U+1
MVI LR,0 ;L = 0
;
; COMPUTE M' = (U+L)/2
NEXT: XRA A
MOV A,UR ;CY=0, A=U
ADD LR ;(U+L)
RAR ;(U+L)/2
CMP MR ;SAME AS LAST TIME THROUGH?
JZ NMATCH ;JUMP IF = TO NO MATCH
;
; MORE ELEMENTS TO SCAN
MOV MR,A ;NEW MIDDLE VALUE
PUSH H ;SAVE A COPY OF THE BASE ADDRESS
PUSH D ;SAVE S,M
PUSH B ;SAVE U,L
PUSH H ;SAVE ANOTHER COPY OF THE BASE ADDRESS
MOV SP1,SR ;S' = S
MOV SP1P,SP1 ;S'' = S'
MVI SR,0 ;FOR DOUBLE ADD OPERATION BELOW (DOUBLE M)
;
LXI KR,0 ;K=0
SUMK: DAD D ;K = K + M
DCR SP1 ;S' = S' - 1
JNZ SUMK ;DECREMENT IF SP1 <> 0
;
; K IS NOW RELATIVE BYTE POSITION
POP D ;TABLE BASE ADDRESS
DAD D ;H,L CONTAINS ABSOLUTE ADDRESS OF BYTE TO COMPARE
LXI D,ACCUM ;D,E ADDRESS CHARACTERS TO COMPARE
;
COMK: ;COMPARE NEXT CHARACTER
LDAX D ;ACCUM CHARACTER TO REG A
CMP M ;SAME AS TABLE ENTRY?
INX D
INX H ;TO NEXT POSITIONS
JNZ NCOM ;JUMP IF NOT THE SAME
DCR SP1P ;MORE CHARACTERS?
JNZ COMK
;
; COMPLETE MATCH AT M
POP B
POP D ;M RESTORED
POP H
MOV A,MR ;VALUE OF M COPIED IN A
RET ;WITH ZERO FLAG SET
;
NCOM: ;NO MATCH, DETERMINE IF LESS OR GREATER
POP B ;U,L
POP D ;S,M
POP H ;TABLE ADDRESS
JC NCOML
; ACCUM IS HIGHER
MOV LR,MR ;L = M
JMP NEXT
;
NCOML: ;ACCUMULATOR IS LOW
MOV UR,MR ;U = M
JMP NEXT
;
NMATCH: ;NO MATCH
XRA A
INR A ;SETS NOT ZERO FLAG
RET
;
PREFIX: ;J C OR R PREFIX?
LDA ACCUM
LXI B,(0C2H SHL 8) OR O5 ;JNZ OPCODE TO B, TYPE TO C
CPI 'J'
RZ ;RETURN WITH ZERO FLAG SET IF J
MVI B,0C4H ;CNZ OPCODE TO B, TYPE IS IN C
CPI 'C'
RZ
LXI B,(0C0H SHL 8) OR O1 ;RNZ OPCODE
CPI 'R'
RET
;
SUFFIX: ;J R OR C RECOGNIZED, LOOK FOR SUFFIX
LDA ACCLEN
CPI 4 ;CHECK LENGTH
JNC NSUFF ;CARRY IF 0,1,2,3 IN LENGTH
CPI 3
JZ SUF0 ;ASSUME 1 OR 2 IF NO BRANCH
CPI 2
JNZ NSUFF ;RETURNS IF 0 OR 1
LXI H,ACCUM+2
MVI M,' ' ;BLANK-OUT FOR MATCH ATTEMPT
SUF0: ;SEARCH 'TIL END OF TABLE
LXI B,8 ;B=0, C=8 COUNTS TABLE DOWN TO ZERO OR MATCH
LXI D,SUFTAB
NEXTS: ;LOOK AT NEXT SUFFIX
LXI H,ACCUM+1 ;SUFFIX POSITION
LDAX D ;CHARACTER TO ACCUM
CMP M
INX D ;READY FOR NEXT CHARACTER
JNZ NEXT0 ;JMP IF NO MATCH
LDAX D ;GET NEXT CHARACTER
INX H ;READY FOR COMPARE WITH ACCUM
CMP M ;SAME?
RZ ;RETURN WITH ZERO FLAG SET, B IS SUFIX
NEXT0: INX D ;MOVE TO NEXT CHARACTER
INR B ;COUNT SUFFIX UP
DCR C ;COUNT TABLE LENGTH DOWN
JNZ NEXTS
; END OF TABLE, MARK WITH NON ZERO FLAG
INR C
RET
;
NSUFF: ;NOT PROPER SUFFIX - SET NON ZERO FLAG
XRA A
INR A
RET
;
BGET: ;PERFORM BINARY SEARCH, AND EXTRACT TYPE AND VAL FIELDS FOR
; THE ITEM. ZERO FLAG INDICATES MATCH WAS FOUND, WITH TYPE
; IN THE ACCUMULATOR, AND VAL IN REGISTER B. THE SEARCH IS BASED
; UPON THE LENGTH OF THE ACCUMULATOR
LDA ACCLEN ;ITEM LENGTH
MOV C,A ;SAVE A COPY
DCR A ;ACCLEN-1
MOV E,A
MVI D,0 ;DOUBLE ACCLEN-1 TO D,E
PUSH D ;SAVE A COPY FOR LATER
CPI CMAX ;TOO LONG?
JNC NGET ;NOT IN RANGE IF CARRY
LXI H,CLEN ;LENGTH VECTOR
DAD D
MOV UR,M ;FILL UPPER BOUND FROM MEMORY
LXI H,CINX
DAD D
DAD D ;BASE ADDRESS TO H,L
MOV D,M
INX H
MOV H,M
MOV L,D ;NOW IN H,L
MOV SR,C ;FILL THE SIZE REGISTER
CALL BSEAR ;PERFORM THE BINARY SEARCH
JNZ SCASE ;ZERO IF FOUND
POP D ;RESTORE INDEX
LXI H,TVINX
DAD D
DAD D ;ADDRESSING PROPER TV ELEMENT
MOV E,M
INX H
MOV D,M
; D,E IS BASE ADDRESS OF TYPE/VALUE VECTOR, ADD DISPLACEMENT
MOV L,A
MVI H,0
DAD H ;DOUBLED
DAD D ;INDEXED
MOV A,M ;TYPE TO ACC
INX H
MOV B,M ;VALUE TO B
RET ;TYPE IN ACC, VALUE IN B
;
SCASE: ;NAME NOT TOO LONG, BUT NOT FOUND IN TABLES, MAY BE J C OR R
POP D ;RESTORE INDEX
CALL PREFIX
RNZ ;NOT FOUND AS PREFIX J C OR R IF NOT ZERO FLAG
PUSH B ;SAVE VALUE AND TYPE
CALL SUFFIX ;ZERO IF SUFFIX MATCHED
MOV A,B ;READY FOR MASK IF ZERO FLAG
POP B ;RECALL VALUE AND TYPE
RNZ ;RETURN IF NOT ZERO FLAG SET
; MASK IN THE PROPER BITS AND RETURN
ORA A ;CLEAR CARRY
RAL
RAL
RAL
ORA B ;VALUE SET TO JNZ ...
MOV B,A ;REPLACE
MOV A,C ;RETURN WITH TYPE IN REGISTER A
CMP A ;CLEAR THE ZERO FLAG
RET
;
NGET: ;CAN'T FIND THE ENTRY, RETURN WITH ZERO FLAG RESET
POP D ;GET THE ELEMENT BACK
XRA A ;CLEAR
INR A ;ZERO FLAG RESET
RET
;
;
ENDMOD EQU ($ AND 0FFE0H) + 20H ;NEXT MODULE ADDRESS
END


View File

@@ -0,0 +1,594 @@
TITLE 'ASM OPERAND SCAN MODULE'
; OPERAND SCAN MODULE
ORG 1860H
;
; EXTERNALS
IOMOD EQU 200H ;I/O MODULE
SCMOD EQU 1100H ;SCANNER MODULE
SYMOD EQU 1340H ;SYMBOL TABLE MODULE
BMOD EQU 15A0H ;BINARY SEARCH MODULE
;
;
PERR EQU IOMOD+18H
SCAN EQU SCMOD+6H ;SCANNER ENTRY POINT
CR EQU 0DH ;CARRIAGE RETURN
;
LOOKUP EQU SYMOD+6H ;LOOKUP
FOUND EQU LOOKUP+3 ;FOUND SYMBOL IF ZERO FLAG NOT SET
ENTER EQU FOUND+3 ;ENTER SYMBOL
SETTY EQU ENTER+3 ;SET TYPE FIELD
GETTY EQU SETTY+3 ;SET TYPE FIELD
SETVAL EQU GETTY+3 ;SET VALUE FIELD
GETVAL EQU SETVAL+3 ;GET VALUE FIELD
;
BSEAR EQU BMOD+3 ;BINARY SEARCH ROUTINE
BGET EQU BSEAR+3 ;GET VALUES WITH SEARCH
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
; TABLE DEFINITIONS
XBASE EQU 0 ;START OF OPERATORS
OPER EQU 15 ;LAST OPERATOR
RT EQU 16
PT EQU RT+1 ;RT IS REGISTER TYPE, PT IS PSEUDO OPERATION
OBASE EQU PT+1
;
PLUS EQU 5
MINUS EQU 6
NOTF EQU 8 ;NOT
LPAR EQU 12
RPAR EQU 13
OSMAX EQU 10
VSMAX EQU 8*2
;
;
; BEGINNING OF MODULE
JMP ENDMOD ;PAST THIS MODULE
JMP OPAND ;SCAN OPERAND FIELD
JMP MULF ;MULTIPLY FUNCTION
JMP DIVE ;DIVIDE FUNCTION
UNARY: DS 1 ;TRUE IF NEXT OPERATOR IS UNARY
OPERV: DS OSMAX ;OPERATOR STACK
HIERV: DS OSMAX ;OPERATOR PRIORITY
VSTACK: DS VSMAX ;VALUE STACK
OSP: DS 1 ;OPERATOR STACK POINTER
VSP: DS 1 ;VALUE STACK POINTER
;
;
;
STKV: ;PLACE CURRENT H,L VALUE AT TOP OF VSTACK
XCHG ;HOLD VALUE IN D,E
LXI H,VSP
MOV A,M
CPI VSMAX
JC STKV0
CALL ERREX ;OVERFLOW IN EXPRESSION
MVI M,0 ;VSP=0
STKV0: MOV A,M ;GET VSP
INR M ;VSP=VSP+1
INR M ;VSP=VSP+2
MOV C,A ;SAVE VSP
MVI B,0 ;DOUBLE VSP
LXI H,VSTACK
DAD B
MOV M,E ;LOW BYTE
INX H
MOV M,D ;HIGH BYTE
RET
;
STKO: ;STACK OPERATOR (REG-A) AND PRIORITY (REG-B)
PUSH PSW ;SAVE IT
LXI H,OSP
MOV A,M
CPI OSMAX
JC STKO1
MVI M,0
CALL ERREX ;OPERATOR STACK OVERFLOW
STKO1: MOV E,M ;GET OSP
MVI D,0
INR M ;OSP=OSP+1
POP PSW ;RECALL OPERATOR
LXI H,OPERV
DAD D ;OPERV(OSP)
MOV M,A ;OPERV(OSP)=OPERATOR
LXI H,HIERV
DAD D
MOV M,B ;HIERV(OSP)=PRIORITY
RET
;
LODV1: ;LOAD TOP ELEMENT FROM VSTACK TO H,L
LXI H,VSP
MOV A,M
ORA A
JNZ LODOK
CALL ERREX ;UNDERFLOW
LXI H,0
RET
;
LODOK: DCR M
DCR M ;VSP=VSP-2
MOV C,M ;LOW BYTE
MVI B,0
LXI H,VSTACK
DAD B ;VSTACK(VSP)
MOV C,M ;GET LOW BYTE
INX H
MOV H,M
MOV L,C
RET
;
LODV2: ;LOAD TOP TWO ELEMENTS DE HOLDS TOP, HL HOLDS TOP-1
CALL LODV1
XCHG
CALL LODV1
RET
;
APPLY: ;APPLY OPERATOR IN REG-A TO TOP OF STACK
MOV L,A
MVI H,0
DAD H ;OPERATOR NUMBER*2
LXI D,OPTAB
DAD D ;INDEXED OPTAB
MOV E,M ;LOW ADDRESS
INX H
MOV H,M ;HIGH ADDRESS
MOV L,E
PCHL ;SET PC AND GO TO SUBROUTINE
;
OPTAB: DW MULOP
DW DIVOP
DW MODOP
DW SHLOP
DW SHROP
DW ADDOP
DW SUBOP
DW NEGOP
DW NOTOP
DW ANDOP
DW OROP
DW XOROP
DW ERREX ;(
;
; SPECIFIC HANDLERS FOLLOW
SHFT: ;SET UP OPERANDS FOR SHIFT L AND R
CALL LODV2
MOV A,D ;ENSURE 0-15
ORA A
JNZ SHERR
MOV A,E
CPI 17
RC ;RETURN IF 0-16 SHIFT
SHERR: CALL ERREX
MVI A,16
RET
;
NEGF: ;COMPUTE 0-H,L TO H,L
XRA A
SUB L
MOV L,A
MVI A,0
SBB H
MOV H,A
RET
;
DIVF: CALL LODV2
DIVE: ;(EXTERNAL ENTRY FROM MAIN PROGRAM)
XCHG ;SWAP D,E WITH H,L FOR DIVIDE FUNCTION
; COMPUTE X/Y WHERE X IS IN D,E AND Y IS IN H,L
; THE VALUE OF X/Y APPEARS IN D,E AND X MOD Y IS IN H,L
;
SHLD DTEMP ;SAVE X IN TEMPORARY
LXI H,BNUM ;STORE BIT COUNT
MVI M,11H
LXI B,0 ;INTIALIZE RESULT
PUSH B
XRA A ;CLEAR FLAGS
DLOOP:
MOV A,E ;GET LOW Y BYTE
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
DCR M ;DECREMENT BIT COUNT
POP H ;RESTORE TEMP RESULT
RZ ;ZERO BIT COUNT MEANS ALL DONE
MVI A,0 ;ADD IN CARRY
ACI 0 ;CARRY
DAD H ;SHIFT TEMP RESULT LEFT ONE BIT
MOV B,H ;COPY HA AND L TO A A ND C
ADD L
LHLD DTEMP ;GET ADDRESS OF X
SUB L ;SUBTRACT FROM TEMPORARY RESULT
MOV C,A
MOV A,B
SBB H
MOV B,A
PUSH B ;SAVE TEMP RESULT IN STACK
JNC DSKIP ;NO BORROW FROM SUBTRACT
DAD B ;ADD X BACK IN
XTHL ;REPLACE TEMP RESULT ON STACK
DSKIP: LXI H,BNUM ;RESTORE H,L
CMC
JMP DLOOP ;REPEAT LOOP STEPS
;
DTEMP: DS 2
BNUM: DS 1
;
MULF: ;MULTIPLY D,E BY H,L AND REPLACE H,L WITH RESULT
MOV B,H
MOV C,L ;COPY OF 1ST VALUE TO B,C FOR SHIFT AND ADD
LXI H,0 ;H,L IS THE ACCUMULATOR
MUL0: XRA A
MOV A,B ;CARRY IS CLEARED
RAR
MOV B,A
MOV A,C
RAR
MOV C,A
JC MUL1 ;SKIP THIS ADD IF LSB IS ZERO
ORA B
RZ ;RETURN WITH H,L
JMP MUL2 ;SKIP ADD
MUL1: DAD D ;ADD CURRENT VALUE OF D
MUL2: XCHG ;READY FOR *2
DAD H
XCHG
JMP MUL0
;
MULOP: ;MULTIPLY D,E BY H,L
CALL LODV2
CALL MULF
JMP ENDOP
;
DIVOP: ;DIVIDE H,L BY D,E
CALL DIVF
XCHG ;RESULT TO H,L
JMP ENDOP
;
MODOP: CALL DIVF
JMP ENDOP
;
SHLOP: CALL SHFT ;CHECK VALUES
SHL0: ORA A ;DONE?
JZ ENDOP
DAD H ;HL=HL*2
DCR A
JMP SHL0
;
SHROP: CALL SHFT
SHR0: ORA A ;DONE?
JZ ENDOP
PUSH PSW ;SAVE CURRENT COUNT
XRA A
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
POP PSW
DCR A
JMP SHR0
;
ADDOP: CALL LODV2
ADD0: DAD D
JMP ENDOP
;
SUBOP: CALL LODV2
XCHG ;TREAT AS HL+(-DE)
CALL NEGF ;0-HL
JMP ADD0
;
NEGOP: CALL LODV1
NEG0: CALL NEGF ;COMPUTE 0-HL
JMP ENDOP
;
NOTOP: CALL LODV1
INX H ;65536-HL = 65535-(HL+1)
JMP NEG0
;
ANDOP: CALL LODV2
MOV A,D
ANA H
MOV H,A
MOV A,E
ANA L
MOV L,A
JMP ENDOP
;
OROP: CALL LODV2
MOV A,D
ORA H
MOV H,A
MOV A,E
ORA L
MOV L,A
JMP ENDOP
;
XOROP: CALL LODV2
MOV A,D
XRA H
MOV H,A
MOV A,E
XRA L
MOV L,A
;
ENDOP: JMP STKV
;
;
;
ENDEXP: ;RETURNS ZERO FLAG IF SYMBOL IS CR, ;, OR ,
LDA TOKEN
CPI SPECL
RNZ ;NOT END IF NOT SPECIAL
;
LDA ACCUM
CPI CR
RZ
CPI ';'
RZ
CPI ','
RZ
CPI '!'
RET
;
OPAND: ;SCAN THE OPERAND FIELD OF AN INSTRUCTION
; (NOT A DB WITH FIRST TOKEN STRING > 2 OR 0)
XRA A
STA OSP ;ZERO OPERATOR STACK POINTER
STA VSP
DCR A ;255
STA UNARY
LXI H,0
SHLD EVALUE
;
OP0: ;ARRIVE HERE WITH NEXT ITEM ALREADY SCANNED
CALL ENDEXP ;DONE?
JNZ OP1
; EMPTY THE OPERATOR STACK
EMPOP: LXI H,OSP
MOV A,M ;GET THE OSP AND CHECK FOR EMPTY
ORA A
JZ CHKVAL ;JUMP IF EMPTY
DCR M ;POP ELEMENT
MOV E,A ;COPY FOR DOUBLE ADD
DCR E
MVI D,0
LXI H,OPERV
DAD D ;INDEXED - OPERV(OSP)
MOV A,M ;GET OPERATOR
CALL APPLY ;APPLY OPERATOR
JMP EMPOP
;
CHKVAL:
LDA VSP ;MUST HAVE ONE ELEMENT IT THE STACK
CPI 2
CNZ ERREX
LDA PBUFF
CPI ' '
RNZ ;EVALUE REMAINS AT ZERO
LHLD VSTACK ;GET DOUBLE BYTE IN STACK
SHLD EVALUE
RET
;
OP1: ;MORE TO SCAN
LDA PBUFF
CPI ' '
JNZ GETOP
LDA TOKEN
CPI STRNG ;IS THIS A STRING?
JNZ OP3
;
; STRING - CONVERT TO DOUBLE PRECISION
LDA ACCLEN
ORA A
CZ ERREX ;ERROR IF LENGTH=0
CPI 3
CNC ERREX ;ERROR IF LENGTH>2
MVI D,0
LXI H,ACCUM
MOV E,M ;LSBYTE
INX H
DCR A ;A HAS THE LENGTH
JZ OP2 ;ONE OR TWO BYTES
MOV D,M ;FILL HIGH ORDER
OP2: XCHG ;VALUE TO H,L
JMP STNUM ;STORE TO STACK
;
OP3: ;NOT A STRING, CHECK FOR NUMBER
CPI NUMB
JNZ OP4
LHLD VALUE ;NUMERIC VALUE
JMP STNUM
;
OP4: ;NOT STRING OR NUMBER, MUST BE ID OR SPECL
CALL BGET ;BINARY SEARCH, GET ATTRIBUTES
JNZ OP6 ;MATCH?
; YES, MAY BE OPERATOR
CPI OPER+1
JNC OP5
; OPERATOR ENCOUNTERED MS NIBBLE OF B IS PRIORITY NUMBER LS NIBBLE
; IS THE OPERATOR
; ACC HAS THE OPERATOR NUMBER, B HAS PRIORITY
CPI LPAR ;(?
MOV C,A ;SAVE COPY OF OPERATOR NUMBER
LDA UNARY
JNZ OPER1 ;JUMP IF NOT A (
; ( ENCOUNTERED, UNARY MUST BE TRUE
ORA A
CZ ERREX
MVI A,0FFH
STA UNARY ;UNARY IS SET TRUE
MOV A,C ;RECOVER OPERATOR
JMP OPER4 ;CALLS STKO AND SETS UNARY TO TRUE
;
;
OPER1: ;NOT A LEFT PAREN
ORA A
JNZ OPER6 ;MUST BE + OR - SINCE UNARY IS SET
;
; UNARY NOT SET, MUST BE BINARY OPERATOR
OPER2: ;COMPARE HIERARCHY OF TOS
PUSH B ;SAVE PRIORITY AND OPERATOR NUMBER
LDA OSP
ORA A
JZ OPER3 ;NO MORE OPERATORS IN STACK
MOV E,A ;OSP TO E
DCR E ;OSP-1
MVI D,0
LXI H,HIERV
DAD D ;HL ADDRESSES TOP OF OPERATOR STACK
MOV A,M ;PRIORITY OF TOP OPERATOR
CMP B ;CURRENT GREATER?
JC OPER3 ;JUMP IF SO
; APPLY TOP OPERATOR TO VALUE STACK
LXI H,OSP
MOV M,E ;OSP=OSP-1
LXI H,OPERV
DAD D
MOV A,M ;OPERATOR NUMBER TO ACC
CALL APPLY
POP B ;RESTORE OPERATOR NUMBER AND PRIORITY
JMP OPER2 ;FOR ANOTHER TEST
;
OPER3: ;ARRIVE HERE WHEN OPERATOR IS STACKED
; CHECK FOR RIGHT PAREN BALANCE
POP B ;OPERATOR NUMBER IN C, PRIORITY IN B
MOV A,C
CPI RPAR
JNZ OPER4 ;JUMP IF NOT A RIGHT PAREN
;
; RIGHT PAREN FOUND, STACK MUST CONTAIN LEFT PAREN TO DELETE
LXI H,OSP
MOV A,M
ORA A ;ZERO?
JZ LPERR ;PAREN ERROR IF SO
DCR A ;OSP-1
MOV M,A ;STORED TO MEMORY
MOV E,A
MVI D,0
LXI H,OPERV
DAD D
MOV A,M ;TOP OPERATOR IN REG-A
CPI LPAR
JZ NLERR ;JMP IF NO ERROR - PARENS BALANCE
LPERR: CALL ERREX
NLERR: ;ERROR REPORTING COMPLETE
XRA A
JMP OPER5 ;TO CLEAR UNARY FLAG
;
OPER4: ;ORDINARY OPERATOR
CALL STKO
MVI A,0FFH ;TO SET UNARY FLAG
OPER5: STA UNARY
JMP GETOP ;FOR ANOTHER ELEMENT
;
OPER6: ;UNARY SET, MUST BE + OR -
MOV A,C ;RECALL OPERATOR
CPI PLUS
JZ GETOP ;IGNORE UNARY PLUS
CPI MINUS
JNZ CHKNOT
INR A ;CHANGE TO UNARY MINUS
MOV C,A
JMP OPER2
CHKNOT: ;UNARY NOT SYMBOL?
CPI NOTF
CNZ ERREX
JMP OPER2
;
;
OP5: ;ELEMENT FOUND IN TABLE, NOT AN OPERATOR
CPI PT ;PSEUDO OPERATOR?
CZ ERREX ;ERROR IF SO
MOV L,B ;GET LOW VALUE TO L
MVI H,0 ;ZERO HIGH ORDER BYTE
JMP STNUM ;STORE IT
;
OP6: ;NOT FOUND IN TABLE SCAN, $?
LDA TOKEN
CPI SPECL
JNZ OP7
LDA ACCUM
CPI '$'
JZ CURPC ;USE CURRENT PC
CALL ERREX
LXI H,0
JMP STNUM
CURPC: LHLD ASPC ;GET CURRENT PC
JMP STNUM
;
OP7: ;NOT $, LOOK IT UP
CALL LOOKUP
CALL FOUND
JNZ FIDENT
; NOT FOUND IN SYMBOL TABLE, ENTER IF PASS 1
MVI A,'P'
CALL PERR
CALL ENTER ;ENTER SYMBOL WITH ZERO TYPE FIELD
JMP FIDE0
FIDENT: CALL GETTY ;TYPE TO H,L
ANI 111B
MVI A,'U'
CZ PERR
;
FIDE0:
CALL GETVAL ;VALUE TO H,L
;
STNUM: ;STORE H,L TO VALUE STACK
LDA UNARY
ORA A ;UNARY OPERATION SET
CZ ERREX ;OPERAND ENCOUNTERED WITH UNARY OFF
XRA A
STA UNARY ;SET TO OFF
CALL STKV ;STACK THE VALUE
;
GETOP: CALL SCAN
JMP OP0
;
ERREX: ;PUT 'E' ERROR IN OUTPUT BUFFER
PUSH H
MVI A,'E'
CALL PERR
POP H
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H ;NEXT HALF PAGE
END


View File

@@ -0,0 +1,889 @@
TITLE 'ASM MAIN MODULE'
; CP/M RESIDENT ASSEMBLER MAIN PROGRAM
;
; COPYRIGHT (C) 1976, 1977, 1978
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE
; CALIFORNIA, 93950
;
;
ORG 1BA0H
; MODULE ENTRY POINTS
IOMOD EQU 200H ;IO MODULE
SCMOD EQU 1100H ;SCANNER MODULE
SYMOD EQU 1340H ;SYMBOL TABLE MODULE
BMOD EQU 15A0H ;BINARY SEARCH MODULE
OPMOD EQU 1860H ;OPERAND SCAN MODULE
;
SETUP EQU IOMOD+3H ;FILE SETUP FOR EACH PASS
PCON EQU IOMOD+12H ;WRITE CONSOLE BUFFER TO CR
WOBUFF EQU IOMOD+15H ;WRITE PRINT BUFFER AND REINITIALIZE
PERR EQU IOMOD+18H ;WRITE ERROR CHARACTER TO PRINT BUFFER
DHEX EQU IOMOD+1BH ;SEND HEX CHARACTER TO MACHINE CODE FILE
EOR EQU IOMOD+1EH ;END OF PROCESSING, CLOSE FILES AND TERMINATE
;
INITS EQU SCMOD+3H ;INITIALIZE SCANNER MODULE
SCAN EQU SCMOD+6H ;SCAN NEXT TOKEN
;
INISY EQU SYMOD+3H ;INITIALIZE SYMBOL TABLE
LOOKUP EQU SYMOD+6H ;LOOKUP SYMBOL IN ACCUMULATOR
FOUND EQU SYMOD+9H ;FOUND IF NZ FLAG
ENTER EQU SYMOD+0CH ;ENTER SYMBOL IN ACCUMULATOR
SETTY EQU SYMOD+0FH ;SET TYPE FIELD
GETTY EQU SYMOD+12H ;GET TYPE FIELD
SETVAL EQU SYMOD+15H ;SET VALUE FIELD
GETVAL EQU SYMOD+18H ;GET VALUE FIELD
;
BGET EQU BMOD+6H ;BINARY SEARCH AND GET TYPE/VALUE PAIR
;
OPAND EQU OPMOD+3H ;GET OPERAND VALUE TO 'EVALUE'
MULF EQU OPMOD+6H ;MULT D,E BY H,L TO H,L
DIVF EQU OPMOD+9H ;DIVIDE HL BY DE, RESULT TO DE
;
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
SYBAS EQU ASPC+2 ;BASE OF SYMBOL TABLE
SYADR EQU SYBAS+2 ;CURRENT SYMBOL ADDRESS
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
EOF EQU 1AH ;END OF FILE
NBMAX EQU 16 ;STARTING POSITION OF PRINT LINE
;
;
RT EQU 16 ;REGISTER TYPE
PT EQU RT+1 ;PSEUDO OPERATION
PENDIF EQU 5 ;PSEUDO OPERATOR 'ENDIF'
OBASE EQU PT+1
O1 EQU OBASE+1 ;FIRST OPERATOR
O15 EQU OBASE+15;LAST OPERATOR
;
; MAIN STATEMENT PROCESSING LOOP
XRA A
STA PASS ;SET TO PASS 0 INITIALLY
CALL INISY ;INITIALIZE THE SYMBOL TABLE
RESTART: ;PASS LOOP GOES FROM 0 TO 1
CALL INITS ;INITIALIZE THE SCANNER
CALL SETUP ;SET UP THE INPUT FILE
LXI H,0
SHLD SYLAB ;ASSUME NO STARTING LABEL
SHLD FPC
SHLD ASPC
SHLD EPC ;END PC
;
SCNEXT: ;SCAN THE NEXT INPUT ITEM
CALL SCAN
SCN0: LDA TOKEN
CPI NUMB ;SKIP LEADING NUMBERS FROM LINE EDITORS
JZ SCNEXT
CPI SPECL ;MAY BE PROCESSOR TECH'S COMMENT
JNZ SCN1
; SPECIAL CHARACTER, CHECK FOR *
LDA ACCUM
CPI '*'
JNZ CHEND ;END OF LINE IF NOT *
; * FOUND, NO PRECEDING LABEL ALLOWED
CALL SETLA
JNZ STERR ;ERROR IF LABEL
JMP CHEN1 ;SCAN THE COMMENT OTHERWISE
;
SCN1: ;NOT NUMBER OR SPECIAL CHARACTER, CHECK FOR IDENTIFIER
CPI IDEN
JNZ STERR ;ERROR IF NOT
;
; IDENTIFIER FOUND, MAY BE LABEL, OPCODE, OR MACRO
CALL BGET ;BINARY SEARCH FIXED DATA
JZ CHKPT ;CHECK FOR PSEUDO OR REAL OPERATOR
;
; BINARY SEARCH WAS UNSUCCESSFUL, CHECK FOR MACRO
CALL LOOKUP
CALL FOUND
JNZ LFOUN ;NZ FLAG SET IF FOUND
;
; NOT FOUND, ENTER IT
CALL ENTER ;THIS MUST BE PASS 0
LDA PASS
ORA A
CNZ ERRP ;PHASE ERROR IF NOT
JMP SETSY ;SET SYLAB
;
; ITEM WAS FOUND, CHECK FOR MACRO
LFOUN: CALL GETTY
CPI MACT
JNZ SETSY
;
; MACRO DEFINITION FOUND, EXPAND MACRO
CALL ERRN ;NOT CURRENTLY IMPLEMENTED
JMP CHEN1 ;SCANS TO END OF CURRENT LINE
;
SETSY: ;LABEL FOUND - IS IT THE ONLY ONE?
LHLD SYLAB
MOV A,L
ORA H
CNZ ERRL ;LABEL ERROR IF NOT
LHLD SYADR ;ADDRESS OF SYMBOL
SHLD SYLAB ;MARK AS LABEL FOUND
;
; LABEL FOUND, SCAN OPTIONAL ':'
CALL SCAN
LDA TOKEN
CPI SPECL
JNZ SCN0 ;SKIP NEXT SCAN IF NOT SPECIAL
LDA ACCUM
CPI ':'
JNZ SCN0
JMP SCNEXT ;TO IGNORE ':'
;
; BINARY SEARCH FOUND SYMBOL, CHECK FOR PSEUDO OR REAL OP
CHKPT: CPI PT ;PSEUDO OPCODE?
JNZ CHKOT
;
; PSEUDO OPCODE FOUND, BRANCH TO CASES
MOV E,B ;B HAS PARTICULAR OPERATOR NUMBER
MVI D,0 ;DOUBLE PRECISION VALUE TO D,E
DCX D ;BIASED BY +1
LXI H,PTTAB ;BASE OF JUMP TABLE
DAD D
DAD D
MOV E,M
INX H
MOV H,M
MOV L,E
PCHL ;JUMP INTO TABLE
;
PTTAB: ;PSEUDO OPCODE JUMP TABLE
DW SDB ;DB
DW SDS ;DS
DW SDW ;DW
DW SEND ;END
DW SENDIF ;ENDIF
DW SENDM ;ENDM
DW SEQU ;EQU
DW SIF ;IF
DW SMACRO ;MACRO
DW SORG ;ORG
DW SSET ;SET
DW STITLE ;TITLE
;
SDB:
CALL FILAB ;SET LABEL FOR THIS LINE TO ASPC
SDB0:
CALL SCAN ;PAST DB TO NEXT ITEM
LDA TOKEN ;LOOK FOR LONG STRING
CPI STRNG
JNZ SDBC ;SKIP IF NOT STRING
LDA ACCLEN
DCR A ;LENGTH 1 STRING?
JZ SDBC
; LENGTH 0,2,... STRING
MOV B,A
INR B
INR B ;BECOMES 1,3,... FOR 0,2,... LENGTHS
LXI H,ACCUM ;ADDRESS CHARACTERS IN STRING
SDB1: DCR B ;COUNT DOWN TO ZERO
JZ SDB2 ;SCAN DELIMITER AT END OF STRING
PUSH B ;SAVE COUNT
MOV B,M ;GET CHARACTER
INX H
PUSH H ;SAVE ACCUM POINTER
CALL FILHB ;SEND TO HEX FILE
POP H
POP B
JMP SDB1
SDB2: CALL SCAN ;TO THE DELIMITER
JMP SDB3
;
; NOT A LONG STRING
SDBC: CALL OPAND ;COMPUTE OPERAND
LHLD EVALUE ;VALUE TO H,L
MOV A,H
ORA A ;HIGH ORDER MUST BE ZERO
CNZ ERRD ;DATA ERROR
MOV B,L ;GET LOW BYTE
CALL FILHB
SDB3: ;END OF ITEM - UPDATE ASPC
CALL SETAS ;SET ASPC TO FPC
CALL DELIM
CPI ','
JZ SDB0 ;FOR ANOTHER ITEM
JMP CHEND ;CHECK END OF LINE SYNTAX
;
SDS:
CALL FILAB ;HANDLE LABEL IF IT OCCURRED
CALL PADD ;PRINT ADDRESS
CALL EXP16 ;SCAN AND GET 16BIT OPERAND
XCHG ;TO D,E
LHLD ASPC ;CURRENT PSEUDO PC
DAD D ;+EXPRESSION
SHLD ASPC
SHLD FPC ;NEXT TO FILL
JMP CHEND
;
SDW:
CALL FILAB ;HANDLE OPTIONAL LABEL
SDW0:
CALL EXP16 ;GET 16BIT OPERAND
PUSH H ;SAVE A COPY
MOV B,L ;LOW BYTE FIRST
CALL FILHB ;SEND LOW BYTE
POP H ;RECLAIM A COPY
MOV B,H ;HIGH BYTE NEXT
CALL FILHB ;SEND HIGH BYTE
CALL SETAS ;SET ASPC=FPC
CALL DELIM ;CHECK DELIMITER SYNTAX
CPI ','
JZ SDW0 ;GET MORE DATA
JMP CHEND
;
SEND:
CALL FILAB
CALL PADD ;WRITE LAST LOC
LDA PBUFF
CPI ' '
JNZ CHEND
CALL EXP16 ;GET EXPRESSION IF IT'S THERE
LDA PBUFF
CPI ' '
JNZ SEND0
SHLD EPC ;EXPRESSION FOUND, STORE IT FOR LATER
SEND0: MVI A,' '
STA PBUFF ;CLEAR ERROR, IF IT OCCURRED
CALL SCAN ;CLEAR CR
LDA TOKEN
CPI SPECL
JNZ STERR
LDA ACCUM
CPI LF
JNZ STERR
JMP ENDAS ;END OF ASSEMBLER
;
SENDIF:
JMP POEND
;
SENDM:
CALL ERRN
JMP POEND
;
SEQU:
CALL SETLA
JZ STERR ;MUST BE A LABEL
LHLD ASPC ;HOLD TEMP ASPC
PUSH H ;IN STACK
CALL EXP16 ;GET 16BIT OPERAND
SHLD ASPC ;VALUE OF EXPRESSION
CALL FILAB
CALL PADDR ;COMPUTED VALUE
LXI H,PBUFF+6 ;SPACE AFTER VALUE
MVI M,'='
POP H ;REAL ASPC
SHLD ASPC ;CHANGE BACK
JMP CHEND
;
SIF:
CALL FILAB ;IN CASE OF LABEL
CALL EXP16 ;GET IF EXPRESSION
LDA PBUFF
CPI ' '
JNZ CHEND ;SKIP IF ERROR
MOV A,L ;GET LSB
RAR
JC CHEND ;TRUE IF CARRY BIT SET
;
; SKIP TO EOF OR ENDIF
SIF0: CALL SCAN
LDA TOKEN
CPI SPECL
JNZ SIF1
LDA ACCUM
CPI EOF
MVI A,'B' ;BALANCE ERROR
CZ PERR
JZ ENDAS
JMP SIF0 ;FOR ANOTHER
SIF1: ;NOT A SPECIAL CHARACTER
CPI IDEN
JNZ SIF0 ;NOT AN IDENTIFIER
CALL BGET ;LOOK FOR ENDIF
JNZ SIF0 ;NOT FOUND
CPI PT ;PSEUDO OP?
JNZ SIF0
MOV A,B ;GET OPERATOR NUMBER
CPI PENDIF ;ENDIF?
JNZ SIF0 ;GET ANOTHER TOKEN
JMP POEND ;OK, CHECK END OF LINE
;
SMACRO:
CALL ERRN
JMP CHEND
;
SORG:
CALL EXP16
LDA PBUFF
CPI ' '
JNZ CHEND ;SKIP ORG IF ERROR
SHLD ASPC ;CHANGE PC
SHLD FPC ;CHANGE NEXT TO FILL
CALL FILAB ;IN CASE OF LABEL
CALL PADD
JMP CHEND
;
SSET:
CALL SETLA
JZ STERR ;MUST BE LABELLED
;
CALL GETTY
CPI SETT
CNZ ERRL ;LABEL ERROR
MVI A,SETT
CALL SETTY ;REPLACE TYPE WITH 'SET'
CALL EXP16 ;GET THE EXPRESSION
PUSH H ;SAVE IT
CALL SETLA ;RE-ADDRESS LABEL
POP H ;RECLAIM IT
CALL SETVAL
LXI H,0
SHLD SYLAB ;PREVENT LABEL PROCESSING
JMP CHEND
;
;
STITLE:
CALL ERRN ;NOT IMPLEMENTED
;
POEND: ;PSEUDO OPERATOR END - SCAN TO NEXT TOKEN
CALL SCAN
JMP CHEND
;
; NOT A PSEUDO OPCODE, CHECK FOR REAL OPCODE
CHKOT: SUI O1 ;BASE OF OPCODES
CPI O15 ;PAST LAST OPCODE?
JNC STERR ;STATEMENT ERROR IF SO
;
; FOUND OPCODE, COMPUTE INDEX INTO TABLE AND JUMP TO CASE
MOV E,A
MVI D,0
LXI H,OPTAB
DAD D
DAD D
MOV E,M
INX H
MOV H,M
MOV L,E
PCHL ;JUMP TO CASE
;
OPTAB: ;OPCODE CATEGORIES
DW SSIMP ;SIMPLE
DW SLXI ;LXI
DW SDAD ;DAD
DW SPUSH ;PUSH/POP
DW SJMP ;JMP/CALL
DW SMOV ;MOV
DW SMVI ;MVI
DW SACCI ;ACCUM IMMEDIATE
DW SLDAX ;LDAX/STAX
DW SLHLD ;LHLD/SHLD/LDA/STA
DW SACCR ;ACCUM-REGISTER
DW SINC ;INC/DCR
DW SINX ;INX/DCX
DW SRST ;RESTART
DW SIN ;IN/OUT
;
SSIMP: ;SIMPLE OPERATION CODES
CALL FILHB ;SEND HEX VALUE TO MACHINE CODE FILE
CALL SCAN ;TO NEXT TOKEN
JMP INCPC
;
SLXI: ;LXI H,16B
CALL SHDREG ;SCAN DOUBLE PRECISION REGISTER
CALL CHCOM ;CHECK FOR COMMA FOLLOWING REGISTER
CALL SETADR ;SCAN AND EMIT DOUBLE PRECISION OPERAND
JMP INCPC
;
SDAD: ;DAD B
CALL SHDREG ;SCAN AND EMIT DOUBLE PRECISION REGISTER
JMP INCPC
;
SPUSH: ;PUSH B POP D
CALL SHREG ;SCAN SINGLE PRECISION REGISTER TO A
CPI 111000B ;MAY BE PSW
JZ SPU0
; NOT PSW, MUST BE B,D, OR H
ANI 001000B ;LOW BIT MUST BE 0
CNZ ERRR ;REGISTER ERROR IF NOT
SPU0: MOV A,C ;RECALL REGISTER AND MASK IN CASE OF ERROR
ANI 110000B
ORA B ;MASK IN OPCODE FOR PUSH OR POP
JMP FILINC ;FILL HEX VALUE AND INCREMENT PC
;
SJMP: ;JMP 16B/ CALL 16B
CALL FILHB ;EMIT JMP OR CALL OPCODE
CALL SETADR ;EMIT 16BIT OPERAND
JMP INCPC
;
SMOV: ;MOV A,B
CALL SHREG
ORA B ;MASK IN OPCODE
MOV B,A ;SAVE IN B TEMPORARILY
CALL CHCOM ;MUST BE COMMA SEPARATOR
CALL EXP3 ;VALUE MUST BE 0-7
ORA B ;MASK IN OPCODE
JMP FILINC
;
SMVI: ;MVI A,8B
CALL SHREG
ORA B ;MASK IN OPCODE
CALL FILHEX ;EMIT OPCODE
CALL CHCOM ;SCAN COMMA
CALL SETBYTE ;EMIT 8BIT VALUE
JMP INCPC
;
SACCI: ;ADI 8B
CALL FILHB ;EMIT IMMEDIATE OPCODE
CALL SETBYTE ;EMIT 8BIT OPERAND
JMP INCPC
;
SLDAX: ;LDAX B/STAX D
CALL SHREG
ANI 101000B ;MUST BE B OR D
CNZ ERRR ;REGISTER ERROR IF NOT
MOV A,C ;RECOVER REGISTER NUMBER
ANI 010000B ;CHANGE TO B OR D IF ERROR
ORA B ;MASK IN OPCODE
JMP FILINC ;EMIT OPCODE
;
SLHLD: ;LHLD 16B/ SHLD 16B/ LDA 16B/ STA 16B
CALL FILHB ;EMIT OPCODE
CALL SETADR ;EMIT OPERAND
JMP INCPC
;
SACCR: ;ADD B
CALL EXP3 ;RIGHT ADJUSTED 3BIT VALUE FOR REGISTER
ORA B ;MASK IN OPCODE
JMP FILINC
;
SINC: ;INR B/DCR D
CALL SHREG ;GET REGISTER
ORA B
JMP FILINC
;
SINX: ;INX H/DCX B
CALL SHREG
ANI 001000B ;MUST BE B D M OR SP
CNZ ERRR ;REGISTER ERROR IF NOT
MOV A,C ;RECOVER REGISTER
ANI 110000B ;IN CASE OF ERROR
ORA B ;MASK IN OPCODE
JMP FILINC
;
SRST: ;RESTART 4
CALL SHREG ;VALUE IS 0-7
ORA B ;OPCODE MASKED
JMP FILINC
;
SIN: ;IN 8B/OUT 8B
CALL FILHB ;EMIT OPCODE
CALL SETBYTE ;EMIT 8BIT OPERAND
JMP INCPC
;
FILINC: ;FILL HEX VALUE FROM A BEFORE INCREMENTING PC
CALL FILHEX
;
INCPC: ;CHANGE ASSEMBLER'S PSEUDO PROGRAM COUNTER
CALL FILAB ;SET ANY LABELS WHICH OCCUR ON THE LINE
CALL SETAS ;ASPC=FPC
JMP CHEND ;END OF LINE SCAN
;
;
; UTILITY SUBROUTINES FOR OPERATION CODES
;
DELIM: ;CHECK DELIMITER SYNTAX FOR DATA STATEMENTS
LDA TOKEN
CPI SPECL
CNZ ERRD
LDA ACCUM
CPI ','
RZ
CPI ';'
RZ
CPI CR
CNZ ERRD
RET
;
EXP16: ;GET 16BIT VALUE TO H,L
PUSH B
CALL SCAN ;START SCANNING OPERAND FIELD
CALL OPAND
LHLD EVALUE ;VALUE TO H,L
POP B
RET
;
EXP8: ;GET 8BIT VALUE TO REG A
CALL EXP16
MOV A,H
ORA A
CNZ ERRV ;VALUE ERROR IF HIGH BYTE NOT ZERO
MOV A,L
RET
;
EXP3: ;GET 3BIT VALUE TO REG A
CALL EXP8
CPI 8
CNC ERRV ;VALUE ERROR IF >=8
ANI 111B ;REDUCE IF ERROR OCCURS
RET
;
SHREG: ;GET 3BIT VALUE AND SHIFT LEFT BY 3
CALL EXP3
RAL
RAL
RAL
ANI 111000B
MOV C,A ;COPY TO C
RET
;
SHDREG: ;GET DOUBLE REGISTER TO A
CALL SHREG
ANI 001000B ;CHECK FOR A,C,E, OR L
CNZ ERRR ;REGISTER ERROR
MOV A,C ;RECOVER REGISTER
ANI 110000B ;FIX IT IF ERROR OCCURRED
ORA B ;MASK OPCODE
JMP FILHEX ;EMIT IT
;
SETBYTE: ;EMIT 16BIT OPERAND
CALL EXP8
JMP FILHEX
;
SETADR: ;EMIT 16BIT OPERAND
CALL EXP16
JMP FILADR
;
CHCOM: ;CHECK FOR COMMA FOLLOWING EXPRESSION
PUSH PSW
PUSH B
LDA TOKEN
CPI SPECL
JNZ COMER
; SPECIAL CHARACTER, CHECK FOR COMMA
LDA ACCUM
CPI ','
JZ COMRET ;RETURN IF COMMA FOUND
COMER: ;COMMA ERROR
MVI A,'C'
CALL PERR
COMRET:
POP B
POP PSW
RET
;
CHEND: ;END OF LINE CHECK
CALL FILAB ;IN CASE OF A LABEL
LDA TOKEN
CPI SPECL
JNZ STERR ;MUST BE A SPECIAL CHARACTER
LDA ACCUM
CPI CR ;CARRIAGE RETURN
JNZ CHEN0
; CARRIAGE RETURN FOUND, SCAN PICKS UP LF AND PUSHES LINE
CALL SCAN
JMP SCNEXT
;
CHEN0: ;NOT CR, CHECK FOR COMMENT
CPI ';'
JNZ CHEN2
CALL FILAB ;IN CASE LABELLED EMPTY LINE
; CLEAR COMMENT TO END OF LINE
CHEN1: CALL SCAN
LDA TOKEN
CPI SPECL
JNZ CHEN1
LDA ACCUM
CPI LF
JZ SCNEXT
CPI EOF
JZ ENDAS ;END OF ASSEMBLY IF EOF
CPI '!'
JZ SCNEXT ;LOGICAL END OF LINE
JMP CHEN1 ;NONE OF THE ABOVE
;
; NOT CR OR LF, MAY BE LOGICAL END OF LINE
CHEN2: CPI '!'
JZ SCNEXT
CPI EOF
JZ ENDAS
;
; STATEMENT ERROR IN OPERAND FIELD
STERR: MVI A,'S'
CALL PERR
JMP CHEN1 ;TO DUMP LINE
;
DIFF: ;COMPUTE DE-HL TO HL
MOV A,E
SUB L
MOV L,A
MOV A,D
SBB H
MOV H,A
RET
;
ENDAS: ;END OF ASSEMBLY FOR THIS PASS
LXI H,PASS
MOV A,M
INR M ;PASS NUMBER INCREMENTED
ORA A
JZ RESTART
CALL SCAN ;TO CLEAR LAST LINE FEED
CALL PADD ;WRITE LAST ADDRESS
LXI H,PBUFF+5
MVI M,CR ;SET TO CR FOR END OF MESSAGE
LXI H,PBUFF+1
CALL PCON ;PRINT LAST ADDRESS
;
; COMPUTE REMAINING SPACE
LHLD SYTOP
XCHG
LHLD SYBAS
CALL DIFF ;DIFFERENCE TO H,L
PUSH H ;SYTOP-SYBAS TO STACK
LHLD SYMAX
XCHG
LHLD SYBAS
CALL DIFF ;SYMAX-SYBAS TO H,L
MOV E,H
MVI D,0 ;DIVIDED BY 256
POP H ;SYTOP-SYBAS TO H,L
CALL DIVF ;RESULT TO DE
XCHG
CALL PADDR ;PRINT H,L TO PBUFF
LXI H,PBUFF+5 ;MESSAGE
LXI D,EMSG ;END MESSAGE
ENDA0: LDAX D
ORA A ;ZERO?
JZ ENDA1
MOV M,A
INX H
INX D
JMP ENDA0
;
EMSG: DB 'H USE FACTOR',CR,0
;
ENDA1: LXI H,PBUFF+2 ;BEGINNING OF RATIO
CALL PCON
LHLD EPC
SHLD FPC ;END PROGRAM COUNTER
JMP EOR
;
; UTILITY SUBROUTINES
COMDH: ;COMPARE D,E WITH H,L FOR EQUALITY (NZ FLAG IF NOT EQUAL)
MOV A,D
CMP H
RNZ
MOV A,E
CMP L
RET
;
SETAS: ;ASPC=FPC
LHLD FPC
SHLD ASPC
RET
;
SETLA: ;SYADR=SYLAB, FOLLOWED BY CHECK FOR ZERO
LHLD SYLAB
SHLD SYADR
CALL FOUND
RET
;
FILAB: ;FILL LABEL VALUE WITH CURRENT ASPC, IF LABEL FOUND
CALL SETLA
RZ ;RETURN IF NO LABEL DETECTED
;
; LABEL FOUND, MUST BE DEFINED ON PASS-1
LXI H,0
SHLD SYLAB ;TO MARK NEXT STATEMENT WITH NO LABEL
LDA PASS
ORA A
JNZ FIL1
;
; PASS 0
CALL GETTY
PUSH PSW ;SAVE A COPY OF TYPE
ANI 111B ;CHECK FOR UNDEFINED
CNZ ERRL ;LABEL ERROR
POP PSW ;RESTORE TYPE
ORI PLABT ;SET TO LABEL TYPE
CALL SETTY ;SET TYPE FIELD
LHLD ASPC ;GET CURRENT PC
CALL SETVAL ;PLACE INTO VALUE FIELD
RET
;
FIL1: ;CHECK FOR DEFINED VALUE
CALL GETTY
ANI 111B
CZ ERRP ;PHASE ERROR
; GET VALUE AND COMPARE WITH ASPC
CALL GETVAL ;TO H,L
XCHG
LHLD ASPC
CALL COMDH
CNZ ERRP ;PHASE ERROR IF NOT THE SAME
RET
;
FILHEX: ;WRITE HEX BYTE IN REGISTER A TO MACHINE CODE FILE IF PASS-1
MOV B,A
FILHB: LDA PASS
ORA A
MOV A,B
JZ FILHI
;
; PASS - 1, WRITE HEX AND PRINT DATA
PUSH B ;SAVE A COPY
CALL DHEX ;INTO MACHINE CODE FILE
; MAY BE COMPLETELY EMPTY LINE, SO CHECK ADDRESS
LDA PBUFF+1
CPI ' '
LHLD ASPC
CZ PADDR ;PRINT ADDRESS FIELD
;
LDA NBP
CPI NBMAX ;TRUNCATE CODE IF TOO MUCH ON THIS LINE
POP B ;RECALL HEX DIGIT
JNC FILHI
; ROOM FOR DIGIT ON THIS LINE
MOV A,B
CALL WHEXB ;WRITE HEX BYTE TO PRINT LINE
FILHI: LHLD FPC
INX H
SHLD FPC ;READY FOR NEXT BYTE
RET
;
FILADR: ;EMIT DOUBLE PRECISION VALUE FROM H,L
PUSH H ;SAVE A COPY
MOV B,L
CALL FILHB ;LOW BYTE EMITTED
POP H ;RECOVER A COPY OF H,L
MOV B,H
JMP FILHB ;EMIT HIGH BYTE AND RETURN
;
; UTILITY FUNCTIONS FOR PRINTING HEX ADDRESSES AND DATA
CHEX: ;CONVERT TO HEX
ADI '0'
CPI '0'+10
RC
ADI 'A'-'0'-10
RET
;
WHEXN: ;WRITE HEX NIBBLE
CALL CHEX ;CONVERT TO ASCII FROM HEX
LXI H,NBP
MOV E,M ;NEXT POSITION TO PRINT
MVI D,0 ;DOUBLE PRECISION
INR M ;NBP=NBP+1
LXI H,PBUFF
DAD D
MOV M,A ;STORE IN PRINT BUFFER
RET
;
WHEXB: ;WRITE HEX BYTE TO PRINT BUFFER
PUSH PSW
RAR
RAR
RAR
RAR
ANI 0FH ;HIGH ORDER NIBBLE NORMALIZE IN A
CALL WHEXN ;WRITE IT
POP PSW
ANI 0FH
JMP WHEXN ;WRITE AND RETURN
;
PADD: LHLD ASPC
PADDR: ;PRINT ADDRESS FIELD OF PRINT LINE FROM H,L
XCHG
LXI H,NBP ;INITIALIZE NEXT TO FILL
PUSH H ;SAVE A COPY OF NBP'S ADDRESS
MVI M,1
MOV A,D ;PRINT HIGH BYTE
PUSH D ;SAVE A COPY
CALL WHEXB
POP D
MOV A,E
CALL WHEXB
POP H ;ADDRESSING NBP
INR M ;SKIP A SPACE AFTER ADDRESS FIELD
RET
;
ERRR: ;EMIT REGISTER ERROR
PUSH PSW
PUSH B
MVI A,'R'
CALL PERR
POP B
POP PSW
RET
;
ERRV: ;EMIT VALUE ERROR
PUSH PSW
PUSH H
MVI A,'V'
CALL PERR
POP H
POP PSW
RET
;
ERRD: PUSH PSW
MVI A,'D' ;DATA ERROR
JMP ERR
;
ERRP: PUSH PSW
MVI A,'P'
JMP ERR
;
ERRL: PUSH PSW
MVI A,'L' ;LABEL ERROR
JMP ERR
;
ERRN: PUSH PSW
MVI A,'N' ;NOT IMPLEMENTED
;
ERR:
CALL PERR
POP PSW
RET
;
SYLAB: DS 2 ;ADDRESS OF LINE LABEL
EPC: DS 2 ;END PC VALUE
NBP: DS 1 ;NEXT BYTE POSITION TO WRITE FOR MACHINE CODE
END


View File

@@ -0,0 +1,422 @@
TITLE 'CP/M VERSION 2.0 SYSTEM RELOCATOR - 8/79'
; CPM RELOCATOR PROGRAM, INCLUDED WITH THE MODULE TO PERFORM
; THE MOVE FROM 900H TO THE DESTINATION ADDRESS
;
; COPYRIGHT (C) 1979
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE CALIFORNIA
; 93950
;
ORG 100H
JMP PASTCOPY
COPY: DB 'COPYRIGHT (C) DIGITAL RESEARCH, 1979 '
PASTCOPY:
BIOSWK EQU 03H ;THREE PAGES FOR BIOS WORKSPACE
STACK EQU 800H
MODSIZ EQU 801H ;MODULE SIZE IS STORED HERE
VERSION EQU 20 ;CPM VERSION NUMBER
BOOTSIZ EQU 100H ;SIZE OF THE COLD START LOADER
; (MAY HAVE FIRST 80H BYTES = 00H)
BDOSL EQU 0800H ;RELATIVE LOCATION OF BDOS
BIOS EQU 1600H ;RELATIVE LOCATION OF BIOS
;
BOOT EQU 0000H ;REBOOT LOCATION
BDOS EQU 0005H
PRNT EQU 9 ;PRINT BUFFER FUNCTION
FCB EQU 5CH ;DEFAULT FCB
MODULE EQU 900H ;MODULE ADDRESS
;
CR EQU 0DH
LF EQU 0AH
LXI SP,STACK
;
; MAY BE MEMORY SIZE SPECIFIED IN COMMAND
LXI D,FCB+1
LDAX D
CPI ' '
JZ FINDTOP
CPI '?' ;WAS * SPECIFIED?
JZ FINDTOP
;
; MUST BE MEMORY SIZE SPECIFICATION
LXI H,0
CLOOP: ;CONVERT TO DECIMAL
LDAX D
INX D
CPI ' '
JZ ECON
ORA A
JZ ECON
; MUST BE DECIMAL DIGIT
SUI '0'
CPI 10
JNC CERROR
; DECIMAL DIGIT IS IN A
DAD H ;*2
PUSH H
DAD H ;*4
DAD H ;*8
POP B ;*2 IN B,C
DAD B ;*10 IN H,L
MOV C,A
MVI B,0
DAD B ;*10+X
JMP CLOOP
ECON: ;END OF CONVERSION, CHECK FOR PROPER RANGE
MOV A,H
ORA A
JNZ CERROR
MOV A,L
CPI 16
JC CERROR
MVI L,0
MOV H,A
DAD H ;SHL 1
DAD H ;SHL 2 FOR KILOBYTES
; H,L HAVE TOP OF MEMORY+1
JMP SETASC
;
CERROR:
LXI D,CONMSG
CALL PRINT
JMP BOOT
CONMSG: DB CR,LF,'INVALID MEMORY SIZE$'
;
;
; FIND END OF MEMORY
FINDTOP:
LXI H,0
FINDM: INR H ;TO NEXT PAGE
JZ MSIZED ;CAN OVERFLOW ON 64K SYSTEMS
MOV A,M
CMA
MOV M,A
CMP M
CMA
MOV M,A ;BITS INVERTED FOR RAM OPERATIONAL TEST
JZ FINDM
; BITS DIDN'T CHANGE, MUST BE END OF MEMORY
; ALIGN ON EVEN BOUNDARY
MSIZED: MOV A,H
ANI 1111$1100B ;EVEN 1K BOUNDARY
MOV H,A
SETASC: ;SET ASCII VALUE OF MEMORY SIZE
PUSH H ;SAVE FOR LATER
; **** SERIALIZATION ****
LHLD BDOS+1
SHLD SER1
; **** SERIALIZATION ****
POP H
PUSH H
MOV A,H
RRC
RRC
ANI 11$1111B ;FOR 1K COUNTS
JNZ NOT64 ;MAY BE 64 K MEM SIZE
MVI A,64 ;SET TO LITERAL IF SO
NOT64: MOV B,A ;READY FOR COUNT DOWN
LXI H,AMEM
MVI A,'0'
MOV M,A
INX H
MOV M,A ;BOTH ARE SET TO ASCII 0
ASC0: LXI H,AMEM+1 ;ADDRESS OF ASCII EQUIVALENT
INR M
MOV A,M
CPI '9'+1
JC ASC1
MVI M,'0'
DCX H
INR M
ASC1: DCR B ;COUNT DOWN BY KILOBYTES
JNZ ASC0
LXI D,MEMSG
CALL PRINT ;MEMORY SIZE MESSAGE
;
LXI H,MODSIZ
MOV C,M
INX H
MOV B,M ;B,C CONTAINS MODULE SIZE
PUSH B ;MODULE SIZE STACKED ON MEM SIZE
;
; TRY TO FIND THE ASCII STRING 'K CP/M VER X.X' TO SET SIZE
LXI H,MODULE
; B,C CONTAINS MODULE LENGTH
SLOOP: ;SEARCH LOOP
LXI D,AMSG
MOV A,B
ORA C
JZ ESEAR ;END OF SEARCH
DCX B ;COUNT SEARCH LENGTH DOWN
PUSH B
MVI C,LAMSG ;LENGTH OF SEARCH MESSAGE
PUSH H ;SAVE BASE ADDRESS OF SEARCH
CHLOOP: ;CHARACTER LOOP, MATCH ON CONTENTS OF D,E AND H,L
LDAX D
CMP M
JNZ NOMATCH
INX D ;TO NEXT SEARCH CHARACTER
INX H ;TO NEXT MATCH CHARACTER
DCR C ;COUNT LENGTH DOWN
JZ FSEAR ;FOUND SEARCH STRING
JMP CHLOOP
;
; **** SERIALIZATION ****
DB LXI ;CONFUSE DISASSEMBLER
BADSER: ;BAD SERIAL NUMBER, LOOP TO CONFUSE ICE-80
XRA A
BADSER0:
DCR A
JNZ BADSER0
;
LXI H,DI OR (HLT SHL 8)
SHLD PRHLT
LXI H,PRJMP
MVI M,CALL ;CHANGE JMP BDOS TO CALL
LXI D,SYNCMSG-5
LXI H,5
DAD D ;TO CONFUSE SEARCHES ON ADDRESSES
XCHG
JMP PRINT
; **** SERIALIZATION ****
;
NOMATCH:
;NOT FOUND AT THIS ADDRESS, LOOK AT NEXT ADDRESS
POP H
INX H
POP B ;RECALL MODULE LENGTH
JMP SLOOP
;
FSEAR:
;FOUND STRING, SET MEMORY SIZE
POP H ;START ADDRESS OF STRING BEING MATCHED
POP B ;CLEAR B,C WHICH WAS STACKED
DCX H
LXI D,AMEM+1
LDAX D
MOV M,A
DCX H
DCX D
LDAX D
MOV M,A
; END OF FILL
;
ESEAR: ;END OF SEARCH
; **** SERIALIZATION ****
; CHECK FOR LEAST SIGNIFICANT BYTE OF 06 IN SER1
LXI B,SER1
LDAX B
CPI 6
MVI A,0
JNZ SETJMP ;BAD SERIALIZATION IF NOT 06
STAX B ;STORE 00 TO LEAST SIGNIFICANT BYTE
; **** SERIALIZATION ****
POP B ;RECOVER MODULE LENGTH
POP H ;H,L CONTAINS END OF MEMORY
PUSH B ;SAVE LENGTH FOR RELOCATION BELOW
MOV A,B
ADI BIOSWK ;ADD BIOS WORK SPACE TO MODULE LENGTH
MOV B,A
MOV A,L
SUB C ;COMPUTE MEMTOP-MODULE SIZE
MOV L,A
MOV A,H
SBB B
MOV H,A
; H,L CONTAINS THE BASE OF THE RELOCATION AREA
SHLD RELBAS ;SAVE THE RELOCATION BASE
XCHG ;MODULE BASE TO D,E
LXI H,MODULE;READY FOR THE MOVE
POP B ;RECOVER ACTUAL MODULE LENGTH
PUSH B ;SAVE FOR RELOCATION
LDA FCB+17 ;CHECK FOR NO MOVE CONDITION
CPI ' '
JZ MOVE
; SECOND PARAMETER SPECIFIED, LEAVE THE DATA AT 'MODULE'
DAD B ;MOVE H,L TO BIT MAP POSITION
JMP RELOC
;
; **** SERIALIZATION ****
SETJMP: LXI H,BADSER ;BAD SERIALIZATION
SHLD JMPSER+1 ;FILL JUMP INSTRUCTION
JMP JMPSER ;EVENTUAL JUMP TO MESSAGE
; **** SERIALIZATION ****
;
MOVE:
MOV A,B ;BC=0?
ORA C
JZ RELOC
DCX B ;COUNT MODULE SIZE DOWN TO ZERO
MOV A,M ;GET NEXT ABSOLUTE LOCATION
STAX D ;PLACE IT INTO THE RELOC AREA
INX D
INX H
JMP MOVE
;
RELOC: ;STORAGE MOVED, READY FOR RELOCATION
; HL ADDRESSES BEGINNING OF THE BIT MAP FOR RELOCATION
POP B ;RECALL MODULE LENGTH
PUSH H ;SAVE BIT MAP BASE IN STACK
LHLD RELBAS
XCHG
LXI H,BOOTSIZ
DAD D ;TO FIND BIAS VALUE
; REGISTER H CONTAINS BIAS VALUE
;
; RELOCATE AT 'MODULE' IF SECOND PARAMETER GIVEN
LDA FCB+17
CPI ' '
JZ REL0
;
; IMAGE NOT MOVED, ADJUST VALUES AT 'MODULE'
LXI D,MODULE
REL0: MOV A,B ;BC=0?
ORA C
JZ ENDREL
; **** SERIALIZATION ****
JMP PASTSYNC
SYNCMSG:
DB CR,LF,'SYNCRONIZATION ERROR$'
PASTSYNC:
; **** SERIALIZATION ****
;
; NOT END OF THE RELOCATION, MAY BE INTO NEXT BYTE OF BIT MAP
DCX B ;COUNT LENGTH DOWN
MOV A,E
ANI 111B ;0 CAUSES FETCH OF NEXT BYTE
JNZ REL1
; FETCH BIT MAP FROM STACKED ADDRESS
XTHL
MOV A,M ;NEXT 8 BITS OF MAP
INX H
XTHL ;BASE ADDRESS GOES BACK TO STACK
MOV L,A ;L HOLDS THE MAP AS WE PROCESS 8 LOCATIONS
REL1: MOV A,L
RAL ;CY SET TO 1 IF RELOCATION NECESSARY
MOV L,A ;BACK TO L FOR NEXT TIME AROUND
JNC REL2 ;SKIP RELOCATION IF CY=0
;
; CURRENT ADDRESS REQUIRES RELOCATION
LDAX D
ADD H ;APPLY BIAS IN H
STAX D
JMP REL2
;
REL2: INX D ;TO NEXT ADDRESS
JMP REL0 ;FOR ANOTHER BYTE TO RELOCATE
;
ENDREL: ;END OF RELOCATION
POP D ;CLEAR STACKED ADDRESS
; **** SERIALIZATION ****
LXI D,MODULE+BDOSL+BOOTSIZ ;ADDRESSING NEW SERIAL NUMBER
LHLD SER1 ;ADDRESSING HOST SERIAL NUMBER
MVI C,6 ;LENGTH OF SERIAL NUMBER
CHKSER: LDAX D
CMP M
JNZ SETJMP
INX H
INX D
DCR C
JNZ CHKSER
; **** SERIALIZATION ****
;
LDA FCB+17
CPI ' '
JZ TRANSFER
; DON'T GO TO THE LOADED PROGRAM, LEAVE IN MEMORY
; MAY HAVE TO MOVE THE PROGRAM IMAGE DOWN 1/2 PAGE
MVI B,128 ;CHECK FOR 128 ZEROES
LXI H,MODULE
TR0: MOV A,M
ORA A
JNZ TREND
INX H
DCR B
JNZ TR0
;
; ALL ZERO FIRST 1/2 PAGE, MOVE DOWN 80H BYTES
XCHG ;NEXT TO GET IN D,E
LHLD MODSIZ
LXI B,-128
DAD B ;NUMBER OF BYTES TO MOVE IN H,L
MOV B,H
MOV C,L ;TRANSFERRED TO B,C
LXI H,MODULE;DESTINATION IN H,L
TRMOV: MOV A,B
ORA C ;ALL MOVED?
JZ TREND
DCX B
LDAX D
MOV M,A ;ONE BYTE TRANSFERRED
INX D
INX H
JMP TRMOV
;
;
; **** SERIALIZATION ****
DB LXI
JMPSER: JMP JMPSER ;ADDRESS FIELD FILLED-IN
; **** SERIALIZATION ****
;
TREND: ;SET ASCII MEMORY IMAGE SIZE
LXI H,MODSIZ
MOV C,M
INX H
MOV B,M
LXI H,MODULE;B,C MODULE SIZE, H,L BASE
DAD B
MOV B,H ;B CONTAINS NUMBER OF PAGES TO SAVE+1
LXI H,SAVMEM;ASCII MEMORY SIZE
MVI A,'0'
MOV M,A
INX H
MOV M,A
; '00' STORED INTO MESSAGE
TRCOMP:
DCR B
JZ TRC1
LXI H,SAVMEM+1 ;ADDRESSING LEAST DIGIT
INR M
MOV A,M
CPI '9'+1
JC TRCOMP
MVI M,'0'
DCX H
INR M
JMP TRCOMP
; FILL CPMXX.COM FROM SAVMEM
TRC1: LHLD AMEM
SHLD SAVM0
; MESSAGE SET, PRINT IT AND REBOOT
LXI D,RELOK
CALL PRINT
JMP BOOT
RELOK: DB CR,LF,'READY FOR "SYSGEN" OR'
DB CR,LF,'"SAVE '
SAVMEM: DB '00 CPM'
SAVM0: DB '00.COM"$'
;
TRANSFER:
; GO TO THE RELOCATED MEMORY IMAGE
LXI D,BOOTSIZ+BIOS ;MODULE
LHLD RELBAS ;RECALL BASE OF RELOC AREA
DAD D ;INDEX TO 'BOOT' ENTRY POINT
PCHL ;GO TO RELOCATED PROGRAM
;
; **** SERIALIZATION ****
PRINT:
MVI C,PRNT
PRJMP: JMP BDOS
PRHLT:
;
; DATA AREAS
SER1: DS 2 ;SERIAL NUMBER ADDRESS FOR HOST
RELBAS: DS 2 ;RELOCATION BASE
MEMSG: DB CR,LF,'CONSTRUCTING '
AMEM: DB '00'
AMSG: DB 'k CP/M vers '
DB VERSION/10+'0','.',VERSION MOD 10 +'0'
LAMSG EQU $-AMSG ;LENGTH OF MESSAGE
DB '$' ;TERMINATOR FOR MESSAGE
END


View File

@@ -0,0 +1,87 @@
; DDT RELOCATOR PROGRAM, INCLUDED WITH THE MODULE TO PERFORM
; THE MOVE FROM 200H TO THE DESTINATION ADDRESS
VERSION EQU 14 ;1.4
;
; COPYRIGHT (C) 1976, 1977, 1978
; DIGITAL RESEARCH
; BOX 579 PACIFIC GROVE
; CALIFORNIA 93950
;
ORG 100H
STACK EQU 200H
BDOS EQU 0005H
PRNT EQU 9 ;BDOS PRINT FUNCTION
MODULE EQU 200H ;MODULE ADDRESS
;
LXI B,0 ;ADDRESS FIELD FILLED-IN WHEN MODULE BUILT
JMP START
DB 'COPYRIGHT (C) 1978, DIGITAL RESEARCH '
SIGNON: DB 'DDT VERS '
DB VERSION/10+'0','.'
DB VERSION MOD 10 + '0','$'
START: LXI SP,STACK
PUSH B
PUSH B
LXI D,SIGNON
MVI C,PRNT
CALL BDOS
POP B ;RECOVER LENGTH OF MOVE
LXI H,BDOS+2;ADDRESS FIELD OF JUMP TO BDOS (TOP MEMORY)
MOV A,M ;A HAS HIGH ORDER ADDRESS OF MEMORY TOP
DCR A ;PAGE DIRECTLY BELOW BDOS
SUB B ;A HAS HIGH ORDER ADDRESS OF RELOC AREA
MOV D,A
MVI E,0 ;D,E ADDRESSES BASE OF RELOC AREA
PUSH D ;SAVE FOR RELOCATION BELOW
;
LXI H,MODULE;READY FOR THE MOVE
MOVE: MOV A,B ;BC=0?
ORA C
JZ RELOC
DCX B ;COUNT MODULE SIZE DOWN TO ZERO
MOV A,M ;GET NEXT ABSOLUTE LOCATION
STAX D ;PLACE IT INTO THE RELOC AREA
INX D
INX H
JMP MOVE
;
RELOC: ;STORAGE MOVED, READY FOR RELOCATION
; HL ADDRESSES BEGINNING OF THE BIT MAP FOR RELOCATION
POP D ;RECALL BASE OF RELOCATION AREA
POP B ;RECALL MODULE LENGTH
PUSH H ;SAVE BIT MAP BASE IN STACK
MOV H,D ;RELOCATION BIAS IS IN D
;
REL0: MOV A,B ;BC=0?
ORA C
JZ ENDREL
;
; NOT END OF THE RELOCATION, MAY BE INTO NEXT BYTE OF BIT MAP
DCX B ;COUNT LENGTH DOWN
MOV A,E
ANI 111B ;0 CAUSES FETCH OF NEXT BYTE
JNZ REL1
; FETCH BIT MAP FROM STACKED ADDRESS
XTHL
MOV A,M ;NEXT 8 BITS OF MAP
INX H
XTHL ;BASE ADDRESS GOES BACK TO STACK
MOV L,A ;L HOLDS THE MAP AS WE PROCESS 8 LOCATIONS
REL1: MOV A,L
RAL ;CY SET TO 1 IF RELOCATION NECESSARY
MOV L,A ;BACK TO L FOR NEXT TIME AROUND
JNC REL2 ;SKIP RELOCATION IF CY=0
;
; CURRENT ADDRESS REQUIRES RELOCATION
LDAX D
ADD H ;APPLY BIAS IN H
STAX D
REL2: INX D ;TO NEXT ADDRESS
JMP REL0 ;FOR ANOTHER BYTE TO RELOCATE
;
ENDREL: ;END OF RELOCATION
POP D ;CLEAR STACKED ADDRESS
MVI L,0
PCHL ;GO TO RELOCATED PROGRAM
END


File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
;*****************************************************
;* *
;* Sector Deblocking Algorithms for CP/M 2.0 *
;* *
;*****************************************************
;
; utility macro to compute sector mask
smask macro hblk
;; compute log2(hblk), return @x as result
;; (2 ** @x = hblk on return)
@y set hblk
@x set 0
;; count right shifts of @y until = 1
rept 8
if @y = 1
exitm
endif
;; @y is not 1, shift right one position
@y set @y shr 1
@x set @x + 1
endm
endm
;
;*****************************************************
;* *
;* CP/M to host disk constants *
;* *
;*****************************************************
blksiz equ 2048 ;CP/M allocation size
hstsiz equ 512 ;host disk sector size
hstspt equ 20 ;host disk sectors/trk
hstblk equ hstsiz/128 ;CP/M sects/host buff
cpmspt equ hstblk * hstspt ;CP/M sectors/track
secmsk equ hstblk-1 ;sector mask
smask hstblk ;compute sector mask
secshf equ @x ;log2(hstblk)
;
;*****************************************************
;* *
;* BDOS constants on entry to write *
;* *
;*****************************************************
wrall equ 0 ;write to allocated
wrdir equ 1 ;write to directory
wrual equ 2 ;write to unallocated
;
;*****************************************************
;* *
;* The BDOS entry points given below show the *
;* code which is relevant to deblocking only. *
;* *
;*****************************************************
;
; DISKDEF macro, or hand coded tables go here
dpbase equ $ ;disk param block base
;
boot:
wboot:
;enter here on system boot to initialize
xra a ;0 to accumulator
sta hstact ;host buffer inactive
sta unacnt ;clear unalloc count
ret
;
seldsk:
;select disk
mov a,c ;selected disk number
sta sekdsk ;seek disk number
mov l,a ;disk number to HL
mvi h,0
rept 4 ;multiply by 16
dad h
endm
lxi d,dpbase ;base of parm block
dad d ;hl=.dpb(curdsk)
ret
;
settrk:
;set track given by registers BC
mov h,b
mov l,c
shld sektrk ;track to seek
ret
;
setsec:
;set sector given by register c
mov a,c
sta seksec ;sector to seek
ret
;
setdma:
;set dma address given by BC
mov h,b
mov l,c
shld dmaadr
ret
;
sectran:
;translate sector number BC
mov h,b
mov l,c
ret
;
;*****************************************************
;* *
;* The READ entry point takes the place of *
;* the previous BIOS defintion for READ. *
;* *
;*****************************************************
read:
;read the selected CP/M sector
xra a
sta unacnt
mvi a,1
sta readop ;read operation
sta rsflag ;must read data
mvi a,wrual
sta wrtype ;treat as unalloc
jmp rwoper ;to perform the read
;
;*****************************************************
;* *
;* The WRITE entry point takes the place of *
;* the previous BIOS defintion for WRITE. *
;* *
;*****************************************************
write:
;write the selected CP/M sector
xra a ;0 to accumulator
sta readop ;not a read operation
mov a,c ;write type in c
sta wrtype
cpi wrual ;write unallocated?
jnz chkuna ;check for unalloc
;
; write to unallocated, set parameters
mvi a,blksiz/128 ;next unalloc recs
sta unacnt
lda sekdsk ;disk to seek
sta unadsk ;unadsk = sekdsk
lhld sektrk
shld unatrk ;unatrk = sectrk
lda seksec
sta unasec ;unasec = seksec
;
chkuna:
;check for write to unallocated sector
lda unacnt ;any unalloc remain?
ora a
jz alloc ;skip if not
;
; more unallocated records remain
dcr a ;unacnt = unacnt-1
sta unacnt
lda sekdsk ;same disk?
lxi h,unadsk
cmp m ;sekdsk = unadsk?
jnz alloc ;skip if not
;
; disks are the same
lxi h,unatrk
call sektrkcmp ;sektrk = unatrk?
jnz alloc ;skip if not
;
; tracks are the same
lda seksec ;same sector?
lxi h,unasec
cmp m ;seksec = unasec?
jnz alloc ;skip if not
;
; match, move to next sector for future ref
inr m ;unasec = unasec+1
mov a,m ;end of track?
cpi cpmspt ;count CP/M sectors
jc noovf ;skip if no overflow
;
; overflow to next track
mvi m,0 ;unasec = 0
lhld unatrk
inx h
shld unatrk ;unatrk = unatrk+1
;
noovf:
;match found, mark as unnecessary read
xra a ;0 to accumulator
sta rsflag ;rsflag = 0
jmp rwoper ;to perform the write
;
alloc:
;not an unallocated record, requires pre-read
xra a ;0 to accum
sta unacnt ;unacnt = 0
inr a ;1 to accum
sta rsflag ;rsflag = 1
;
;*****************************************************
;* *
;* Common code for READ and WRITE follows *
;* *
;*****************************************************
rwoper:
;enter here to perform the read/write
xra a ;zero to accum
sta erflag ;no errors (yet)
lda seksec ;compute host sector
rept secshf
ora a ;carry = 0
rar ;shift right
endm
sta sekhst ;host sector to seek
;
; active host sector?
lxi h,hstact ;host active flag
mov a,m
mvi m,1 ;always becomes 1
ora a ;was it already?
jz filhst ;fill host if not
;
; host buffer active, same as seek buffer?
lda sekdsk
lxi h,hstdsk ;same disk?
cmp m ;sekdsk = hstdsk?
jnz nomatch
;
; same disk, same track?
lxi h,hsttrk
call sektrkcmp ;sektrk = hsttrk?
jnz nomatch
;
; same disk, same track, same buffer?
lda sekhst
lxi h,hstsec ;sekhst = hstsec?
cmp m
jz match ;skip if match
;
nomatch:
;proper disk, but not correct sector
lda hstwrt ;host written?
ora a
cnz writehst ;clear host buff
;
filhst:
;may have to fill the host buffer
lda sekdsk
sta hstdsk
lhld sektrk
shld hsttrk
lda sekhst
sta hstsec
lda rsflag ;need to read?
ora a
cnz readhst ;yes, if 1
xra a ;0 to accum
sta hstwrt ;no pending write
;
match:
;copy data to or from buffer
lda seksec ;mask buffer number
ani secmsk ;least signif bits
mov l,a ;ready to shift
mvi h,0 ;double count
rept 7 ;shift left 7
dad h
endm
; hl has relative host buffer address
lxi d,hstbuf
dad d ;hl = host address
xchg ;now in DE
lhld dmaadr ;get/put CP/M data
mvi c,128 ;length of move
lda readop ;which way?
ora a
jnz rwmove ;skip if read
;
; write operation, mark and switch direction
mvi a,1
sta hstwrt ;hstwrt = 1
xchg ;source/dest swap
;
rwmove:
;C initially 128, DE is source, HL is dest
ldax d ;source character
inx d
mov m,a ;to dest
inx h
dcr c ;loop 128 times
jnz rwmove
;
; data has been moved to/from host buffer
lda wrtype ;write type
cpi wrdir ;to directory?
lda erflag ;in case of errors
rnz ;no further processing
;
; clear host buffer for directory write
ora a ;errors?
rnz ;skip if so
xra a ;0 to accum
sta hstwrt ;buffer written
call writehst
lda erflag
ret
;
;*****************************************************
;* *
;* Utility subroutine for 16-bit compare *
;* *
;*****************************************************
sektrkcmp:
;HL = .unatrk or .hsttrk, compare with sektrk
xchg
lxi h,sektrk
ldax d ;low byte compare
cmp m ;same?
rnz ;return if not
; low bytes equal, test high 1s
inx d
inx h
ldax d
cmp m ;sets flags
ret
;
;*****************************************************
;* *
;* WRITEHST performs the physical write to *
;* the host disk, READHST reads the physical *
;* disk. *
;* *
;*****************************************************
writehst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. write "hstsiz" bytes
;from hstbuf and return error flag in erflag.
;return erflag non-zero if error
ret
;
readhst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. read "hstsiz" bytes
;into hstbuf and return error flag in erflag.
ret
;
;*****************************************************
;* *
;* Unitialized RAM data areas *
;* *
;*****************************************************
;
sekdsk: ds 1 ;seek disk number
sektrk: ds 2 ;seek track number
seksec: ds 1 ;seek sector number
;
hstdsk: ds 1 ;host disk number
hsttrk: ds 2 ;host track number
hstsec: ds 1 ;host sector number
;
sekhst: ds 1 ;seek shr secshf
hstact: ds 1 ;host active flag
hstwrt: ds 1 ;host written flag
;
unacnt: ds 1 ;unalloc rec cnt
unadsk: ds 1 ;last unalloc disk
unatrk: ds 2 ;last unalloc track
unasec: ds 1 ;last unalloc sector
;
erflag: ds 1 ;error reporting
rsflag: ds 1 ;read sector flag
readop: ds 1 ;1 if read operation
wrtype: ds 1 ;write operation type
dmaadr: ds 2 ;last dma address
hstbuf: ds hstsiz ;host buffer
;
;*****************************************************
;* *
;* The ENDEF macro invocation goes here *
;* *
;*****************************************************
end


View File

@@ -0,0 +1,219 @@
0000 ED#
0000 ED#
0AF3 17 0AF3 18 0AFC 19 0AFC 22 0B00 24
0B07 25 0B08 26 0B13 27 0B14 29 0B18 31
0B20 32 0B24 33 0B2C 34 0B31 35 0B38 36
0B39 37 0B39 38 0B41 39 0B42 40 0B47 41
0B4C 42 0B51 43 0B56 44 0B57 45 0B5B 47
0B73 48 0B78 49 0B7D 50 0B8C 51 0B93 52
0B9A 53 0B9B 54 0B9F 56 0BA7 57 0BAA 58
0BCB 59 0BCB 60 0BCF 62 0BDA 64 0BDF 65
0BE7 66 0BE7 67 0BEE 68 0BEF 69 0BEF 70
0BF4 71 0BF9 72 0BFA 73 0C00 75 0C09 76
0C0A 77 0C10 79 0C13 80 0C1B 81 0C1C 82
0C22 84 0C2B 85 0C2C 87 0C32 89 0C3E 90
0C3F 91 0C45 93 0C51 94 0C52 95 0C58 97
0C64 98 0C65 99 0C6B 101 0C74 102 0C75 103
0C7B 105 0C85 106 0C85 107 0C8B 109 0C95 110
0C95 111 0C9B 113 0CA7 114 0CA8 115 0CAE 117
0CB7 118 0CB8 120 0CB8 121 0CBD 122 0CC3 123
0CC4 124 0CC4 125 0CD0 127 0CD8 128 0CDB 129
0CDB 130 0CDE 131 0CDE 132 0CDE 133 0CE7 134
0CE7 135 0CEB 137 0CF6 138 0CF7 139 0CFD 141
0D06 142 0D07 143 0D07 144 0D0E 145 0D14 146
0D17 147 0D18 149 0D1E 151 0D26 152 0D29 153
0D2C 154 0D2D 155 0D2D 156 0D33 157 0D39 158
0D3A 159 0D40 161 0D54 162 0D55 163 0D55 164
0D5B 165 0D61 166 0D70 167 0D80 168 0D8A 170
0D91 171 0D97 172 0D9F 173 0DA5 174 0DA5 175
0DAC 176 0DB2 177 0DBA 179 0DC0 180 0DC8 181
0DCB 182 0DD1 183 0DD4 184 0DD7 185 0DDF 187
0DE5 188 0DE8 189 0DEB 190 0DF3 191 0DF9 192
0DFF 193 0E05 194 0E0F 196 0E16 197 0E1C 198
0E1C 199 0E22 200 0E28 201 0E2E 202 0E33 203
0E3B 204 0E3E 205 0E44 206 0E45 207 0E45 208
0E59 209 0E5A 210 0E5A 211 0E61 212 0E67 213
0E68 214 0ED3 216 0ED3 217 0ED9 218 0E68 219
0E6B 220 0E72 221 0E81 222 0E8E 223 0E9C 225
0EA5 226 0EA8 227 0EB2 228 0EB8 229 0EBB 230
0EC5 231 0ECF 232 0ED2 233 0EDA 234 0EDA 236
0EE6 237 0EE9 238 0EFA 239 0F01 240 0F05 241
0F05 242 0F66 244 0F66 245 0F6C 246 0F05 247
0F0C 248 0F20 249 0F21 250 0F24 251 0F33 252
0F40 253 0F4B 254 0F4E 255 0F58 256 0F62 257
0F65 258 0F6D 259 0F71 261 0F7D 262 0F80 263
0F8C 264 0F93 265 0F94 266 0F98 268 0FA0 270
0FA3 271 0FAE 272 0FB1 273 0FB6 274 0FB6 275
0FC3 276 0FCA 277 0FCB 278 103B 279 103B 280
104B 281 0FCB 282 0FD0 283 0FDB 284 0FE2 285
0FE7 286 0FEA 287 0FED 288 0FF3 289 0FFB 290
0FFE 291 1004 292 1007 293 100E 294 101E 295
1024 296 1027 297 102D 298 1034 299 103A 300
104C 306 1050 308 1058 309 1059 310 1060 311
1061 313 1065 315 1079 316 1079 317 107D 319
1088 320 108E 321 1092 322 1092 323 1096 325
109D 326 10A5 327 10A9 328 10A9 329 10AF 331
10B5 332 10BA 333 10C6 334 10D4 335 10E1 336
10EF 337 10FF 339 1104 340 110D 341 1110 342
1115 343 1118 344 1119 345 111F 347 1127 348
1128 349 1130 350 1135 351 113A 352 1141 353
1149 354 114E 355 114F 356 114F 357 1157 358
1158 359 1158 360 1160 361 1161 362 1164 363
1165 364 1165 365 116E 367 1175 368 1178 369
1182 371 118E 373 119E 374 11A1 375 11A1 376
11A6 377 11A6 378 11BA 379 11BA 380 11C1 381
11C9 382 11D0 384 11D5 385 11E5 387 11F1 388
11FA 389 11FD 390 1200 391 1205 392 1208 393
120D 394 1212 395 1217 396 1217 397 1228 398
1233 399 1247 400 1247 401 1247 402 124E 403
1254 404 1255 405 1255 406 125D 408 1260 409
126B 410 126E 411 1273 412 1273 413 1287 414
1287 416 1287 417 128D 418 128E 419 128E 420
129B 421 129B 422 129B 423 12A1 424 12A2 425
12A2 426 12AA 428 12B1 429 12B4 430 12B4 431
12B7 432 12B7 433 12B7 435 12BD 436 12C5 438
12CC 439 12D2 440 12D8 441 12DC 442 12DF 444
12E5 445 12EB 446 12F1 447 12F1 448 12F6 449
12FD 450 132A 451 1330 452 1333 453 133A 454
134D 455 1355 457 135A 458 1368 459 136B 460
1372 461 1378 462 137B 463 1383 465 1389 466
1390 467 1393 469 139A 470 13A1 471 13A1 472
13A2 473 13A2 474 13A9 475 13AA 476 13AA 477
13B1 478 13B2 479 13B2 480 13B9 481 13BA 482
13BA 483 13C1 484 13C2 485 13C2 486 13C9 487
13CA 488 13CE 490 13D6 491 13E2 492 13E5 493
13EC 495 13FC 496 13FF 497 140A 498 140D 499
140D 500 1413 501 141F 502 1422 503 1432 504
1439 505 1440 507 144B 508 144E 509 144E 510
1451 511 1452 512 1452 513 1457 514 1458 515
1458 516 145D 517 145E 518 145E 519 1461 520
1464 521 1465 522 1465 523 146D 525 1473 526
147F 527 1488 528 1494 529 1497 531 149D 532
14AF 533 14B8 534 14C3 535 14C3 536 14C4 537
1504 539 1508 541 150F 542 1517 543 151B 544
14C4 545 14C4 546 14D0 547 14D3 548 14E2 550
14E5 551 14E6 552 14E6 553 14F1 554 14F4 555
14FC 557 14FF 558 1500 559 1500 560 1503 561
151B 562 151B 564 151B 565 1527 567 152A 568
152B 569 152B 570 152E 571 153D 572 1545 574
1548 575 1549 576 1549 577 154C 578 154D 579
154D 580 1550 581 1557 582 1569 583 156F 584
1572 585 1575 586 1576 587 1576 588 157B 589
1581 590 1587 591 158A 592 1591 593 1594 594
159B 595 159E 596 15A1 597 15AD 599 15B2 600
15B5 601 15B5 602 15B6 603 15B6 604 15B9 605
15BC 606 15BD 607 15BD 608 15C0 609 15CB 610
15D2 611 15D5 612 15D8 613 15D9 614 15D9 615
15E6 616 15E9 617 15F4 618 15F7 619 15FF 620
1602 621 1603 622 1603 623 1624 624 1624 625
1652 626 1652 627 165F 628 166B 629 166E 630
1624 631 162B 632 1633 634 1638 635 163B 636
1640 637 1640 638 1648 639 164B 640 164E 641
1651 642 166F 643 1675 646 167B 647 1680 648
1696 649 16A0 650 16A6 651 16D3 652 16DA 653
16E1 654 16E4 655 16E7 656 16EE 658 16F5 659
16F8 660 16F8 661 16FC 662 16FC 663 16FC 664
1701 665 1704 666 170A 667 170B 668 170B 669
1719 670 171C 671 171D 672 171D 673 1737 674
1738 675 1738 676 1745 677 1746 678 1746 681
1749 682 174E 683 1756 685 175C 686 1762 687
1765 688 176B 689 178C 690 178F 691 17A1 692
17A9 694 17AC 695 17B3 696 17BA 697 17BD 698
17BD 699 17CC 700 17D9 701 17DA 702 17DA 703
17E0 704 17E1 705 17E1 706 17E7 707 17E8 708
17E8 709 17EE 710 17EF 711 17EF 713 17F2 714
17F5 715 17F8 716 17FE 717 1803 718 1806 719
1809 720 180F 721 1830 722 1836 723 1839 724
183A 725 183A 727 1848 728 184F 729 1852 730
1857 731 1861 732 1862 733 1862 734 1867 735
186D 736 186E 737 186E 738 1871 739 1878 740
1884 741 188A 742 188D 743 1890 744 1891 745
1891 746 1896 747 1899 748 189E 749 18A1 750
18A2 751 18A2 753 18A7 754 18B1 755 18BB 756
18C5 757 18C6 758 18C6 759 18CB 760 18D1 761
18D4 762 18D5 763 18D9 765 18FC 766 18FC 767
1900 769 190B 771 190E 772 1915 773 191D 774
1927 775 192A 776 1932 777 1935 778 1938 779
1938 780 193B 781 01C0 782 01DA 783 01E9 784
01F9 786 01FF 787 0202 788 0202 789 0211 790
021E 791 022A 792 0236 793 023F 794 0246 795
0253 796 025D 797 0262 798 027A 799 027D 800
0288 801 0291 803 0298 804 029D 805 029D 806
02A8 807 02B1 808 02B8 809 02BB 810 02BE 811
02C3 812 02C9 813 02CF 814 02D4 815 02D7 816
02DF 817 02E2 818 02EA 819 02ED 820 02F5 821
02FD 822 0303 823 030A 824 0310 825 0317 826
031A 827 0322 828 0327 829 0327 830 032C 831
032F 832 0335 833 033E 835 0341 836 034B 837
035C 838 035F 839 0362 840 036B 842 036E 843
0374 844 037A 845 0380 846 0383 847 0386 848
038E 850 03AB 851 03AE 852 03B4 853 03BB 854
03C3 855 03E7 857 03ED 858 03F2 859 03F9 861
03FC 862 03FF 863 0402 865 0405 866 0408 867
0410 869 0413 870 0416 871 0419 872 0423 873
0426 874 0429 875 0429 876 042C 877 0434 879
0441 880 0446 881 045F 883 046D 885 0470 886
0475 887 047A 888 0480 889 0485 890 0488 891
048D 892 049A 893 04A0 894 04A6 895 04B0 896
04B3 897 04B6 898 04BC 899 04BC 900 04BC 901
04C1 902 04C7 903 04CA 904 04D2 906 04DE 907
04E1 908 04E4 909 04F3 910 04FB 911 0502 912
0507 913 050A 915 0516 917 051B 918 0524 919
0524 920 052C 921 0532 923 053A 925 0542 926
054C 927 0554 928 0562 929 0562 930 0565 931
0565 932 0565 933 056D 934 0570 935 0578 936
0585 937 058A 938 058D 939 0590 940 0598 941
059B 942 05A6 943 05A9 944 05AC 945 05B5 946
05B8 947 05C0 950 05C5 951 05C8 952 05CF 953
05D8 954 05DB 955 05DE 956 05E1 957 05E6 958
05F5 960 0605 961 060B 962 060E 963 0617 964
061A 965 061D 966 0627 967 062D 968 0632 969
063A 971 063F 972 0642 973 0642 974 064D 975
0650 976 0653 977 0658 978 065F 979 0669 980
0676 981 067D 982 0680 983 0683 984 0686 985
068F 987 0695 988 0698 989 193B 992 193B 993
194A 994 194A 995 194A 996 1950 997 1957 998
196F 999 1972 1000 1975 1001 1976 1002 1976 1003
1982 1005 1987 1006 1995 1007 1998 1009 199D 1010
19A9 1011 19A9 1012 069B 1013 069E 1014 06A6 1016
06A9 1017 06AE 1018 06AE 1019 06B6 1021 06B9 1022
06BC 1023 06BF 1024 06C6 1026 06C9 1027 06D1 1029
06D6 1030 06D9 1031 06D9 1032 06DC 1033 06E4 1035
06E7 1036 06EA 1037 06ED 1038 06F5 1039 06FC 1040
06FC 1041 0703 1042 0708 1043 0710 1045 0717 1046
071D 1047 0723 1048 0726 1049 0729 1050 0731 1052
0734 1053 0737 1054 073A 1055 0742 1057 0745 1058
0748 1059 074B 1060 0753 1062 0756 1063 0759 1064
075C 1065 0764 1066 076A 1067 0772 1069 0779 1071
077E 1072 0781 1073 0784 1074 0787 1075 078E 1076
0791 1077 0794 1078 0797 1079 079A 1080 07A2 1081
07A8 1082 07B0 1083 07BE 1084 07C6 1086 07CD 1088
07DB 1089 07E0 1090 07E8 1091 07EB 1092 07EE 1093
07F9 1094 07FC 1095 0804 1097 081C 1099 081F 1100
0822 1101 0825 1102 0825 1103 0828 1104 083B 1106
0843 1108 0848 1109 084E 1110 0854 1111 0857 1112
085E 1113 0861 1114 0868 1115 086B 1116 086E 1117
0873 1118 0876 1119 0879 1120 0881 1122 0884 1123
088B 1124 088E 1125 0891 1126 0894 1127 089C 1130
089F 1131 08A2 1132 08A8 1133 08AB 1134 08B2 1135
08B5 1136 08BC 1137 08CA 1138 08D7 1139 08DA 1140
08DD 1141 08E3 1142 08F3 1143 08F6 1144 0906 1145
090B 1146 090E 1147 0914 1148 0917 1149 091A 1150
0932 1152 0937 1153 0943 1154 0946 1155 0961 1156
0964 1157 096A 1158 096F 1159 0979 1160 097C 1161
0984 1163 0987 1164 098E 1165 099C 1166 09A3 1167
09A6 1168 09A9 1169 09AC 1170 09AF 1171 09B4 1172
09BA 1173 09BD 1174 09C0 1175 09C5 1176 09D1 1177
09D4 1178 09D7 1179 09DA 1180 09DD 1181 09E5 1183
09E8 1184 09EB 1185 09F2 1186 09F5 1187 0A06 1188
0A10 1189 0A1D 1190 0A24 1191 0A27 1192 0A2A 1193
0A2D 1194 0A30 1195 0A38 1196 0A3E 1197 0A46 1199
0A49 1200 0A50 1202 0A53 1203 0A59 1204 0A5C 1207
0A64 1209 0A67 1210 0A6C 1211 0A72 1212 0A78 1213
0A80 1214 0A83 1215 0A83 1216 0A86 1217 0A98 1218
0AA3 1219 0AB0 1220 0AB0 1221 0AB3 1222 0ABB 1224
0AC2 1226 0ACA 1227 0ACD 1228 0ACD 1229 0AD4 1230
0AD7 1231 0ADA 1232 0ADD 1233 0AE5 1234 0AE8 1235
0AEB 1236 0AEE 1237 0AEE 1238 0AF1 1239
0000 MODULE#

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
; assembly language version of mem$move for ed speedup
; version 2.0 of ED
;
mem$move equ 13cah
moveflag equ 1d34h
direction equ 1d20h
front equ 1d22h
back equ 1d24h
first equ 1d26h
last equ 1d28h
baseline equ 1c10h
memory equ 1d4dh
;
forward equ 1
lf equ 0ah
;
org mem$move
lxi h,moveflag
mov m,c ;1 = move data
lxi d,memory
lhld front
dad d ;memory+front
push h
lhld back
dad d
push h
lda direction
cpi forward
jnz moveback
lhld last
mov a,c ;moveflag to a
rar
jc moveforw
; set back to last
shld back
pop h
pop h
ret
;
moveforw:
dad d ;memory+last
mov b,h
mov c,l
pop h
pop d ;bc=last, de=front, hl=back
movef: mov a,l ;back < last?
sub c
mov a,h
sbb b ;cy if true
jnc emove
inx h ;back=back+1
mov a,m ;char to a
cpi lf ;end of line?
jnz notlff
push h
lhld baseline
inx h ;baseline=baseline+1
shld baseline
pop h
notlff:
stax d ;to front
inx d ;front=front+1
jmp movef
moveback:
lhld first
dad d ;memory+first
mov b,h
mov c,l
pop h
pop d ;bc=first, de=front, hl=last
moveb: mov a,c ;first > front?
sub e
mov a,b
sbb d ;cy if true
jnc emove
dcx d ;front=front-1
ldax d ;char to a
cpi lf
jnz notlfb
push h
lhld baseline
dcx h ;baseline=baseline-1
shld baseline
pop h
notlfb: push psw ;save char
lda moveflag
rar
jnc nomove
pop psw
mov m,a ;store to back
dcx h
jmp moveb
nomove: pop psw
jmp moveb
;
emove: push d
lxi d,-memory
dad d ;relative value of back
shld back
pop h
dad d ;relative value of front
shld front
ret
end


View File

@@ -0,0 +1,47 @@
0000 LOAD#
0000 LOAD#
023B 13 023B 14 023F 15 0240 16 0240 17
02D0 22 02D4 24 02DF 25 02E0 26 02E0 27
02E5 28 02EA 29 02EB 30 02EF 32 02F8 33
0306 34 030F 35 0310 36 0314 38 0321 39
032A 40 032B 41 0331 43 0339 44 0341 45
0342 46 0348 48 0351 49 0352 50 0358 52
035B 53 0363 54 0364 56 036A 58 0370 59
0378 60 037E 61 0386 62 0389 63 038A 65
0390 67 039C 68 039D 69 03A3 71 03AF 72
03B0 73 03B6 75 03C2 76 03C3 77 03C3 78
03CE 79 03CF 80 03D5 82 03DE 83 03DF 84
03E5 86 03EF 87 03EF 88 03F5 90 03FF 91
03FF 92 0405 94 0411 95 0412 96 0418 98
0421 99 0422 100 0431 102 043D 103 0447 104
044E 105 0455 106 0458 107 0459 108 0459 110
0469 111 0472 112 0497 113 04A5 114 04BA 116
04C2 117 04C8 118 04D1 119 04D7 120 04D7 121
04DA 122 04E0 123 04E4 124 04E4 126 05FD 129
0601 131 060D 132 0613 133 0624 134 0632 135
064A 136 0651 137 0658 138 065C 139 0667 141
066D 142 066D 143 0670 144 067F 145 0680 146
06E6 148 06E6 149 06E9 150 06F1 151 06F6 152
06FB 153 0680 154 0686 155 068E 156 0694 157
069C 158 06A2 159 06A5 160 06B1 161 06BC 162
06BF 163 06D0 164 06D7 165 06DC 166 06DF 167
06E2 168 06E5 169 06FC 170 06FC 172 070B 173
0711 174 071D 176 0723 177 0726 178 0726 179
072E 180 072E 181 072E 182 073D 183 073D 184
073D 186 0748 187 074C 188 074C 189 0752 191
0763 192 04E4 193 04F0 194 04F4 195 04FD 196
0502 197 0502 198 050A 199 050D 200 0512 201
051D 202 0520 203 052E 204 0541 205 054D 206
0553 207 0559 208 0565 209 056C 210 0573 211
0576 212 0582 213 0589 214 0595 216 059B 217
059E 218 059E 219 05A1 220 05A7 221 05B3 222
05B8 223 05BF 224 05C2 225 05C8 226 05D0 227
05D6 228 05DE 229 05E4 230 05EC 231 05F2 232
05F9 233 05FC 234 0240 236 0247 237 024B 238
0251 239 0257 240 0263 241 026F 242 0275 243
027D 244 0283 245 028F 246 0295 247 029B 248
02A1 249 02A9 250 02B2 252 02B5 253 02BB 254
02C3 255 02C9 256 02C9 257 02CC 258 02CF 259
0000 MODULE#


View File

@@ -0,0 +1,360 @@
LOAD:
DO;
/* C P / M C O M M A N D F I L E L O A D E R
COPYRIGHT (C) 1976, 1977, 1978
DIGITAL RESEARCH
BOX 579 PACIFIC GROVE
CALIFORNIA 93950
*/
DECLARE
TPA LITERALLY '0100H', /* TRANSIENT PROGRAM AREA */
DFCBA LITERALLY '005CH', /* DEFAULT FILE CONTROL BLOCK */
DBUFF LITERALLY '0080H'; /* DEFAULT BUFFER ADDRESS */
/* JMP LOADCOM TO START LOAD */
DECLARE JUMP BYTE DATA(0C3H);
DECLARE JUMPA ADDRESS DATA(.LOADCOM);
DECLARE COPYRIGHT(*) BYTE DATA
(' COPYRIGHT (C) 1978, DIGITAL RESEARCH ');
MON1: PROCEDURE(F,A) EXTERNAL;
DECLARE F BYTE, A ADDRESS;
END MON1;
MON2: PROCEDURE(F,A) BYTE EXTERNAL;
DECLARE F BYTE, A ADDRESS;
END MON2;
DECLARE SP ADDRESS;
BOOT: PROCEDURE;
STACKPTR = SP;
RETURN;
END BOOT;
LOADCOM: PROCEDURE;
DECLARE FCB (33) BYTE AT (DFCBA),
FCBA LITERALLY 'DFCBA';
DECLARE BUFFER (128) BYTE AT (DBUFF),
BUFFA LITERALLY 'DBUFF';
DECLARE SFCB(33) BYTE, /* SOURCE FILE CONTROL BLOCK */
BSIZE LITERALLY '1024',
EOFILE LITERALLY '1AH',
SBUFF(BSIZE) BYTE, /* SOURCE FILE BUFFER */
RFLAG BYTE, /* READER FLAG */
SBP ADDRESS; /* SOURCE FILE BUFFER POINTER */
/* LOADCOM LOADS TRANSIENT COMMAND FILES TO THE DISK FROM THE
CURRENTLY DEFINED READER PERIPHERAL. THE LOADER PLACES THE MACHINE
CODE INTO A FILE WHICH APPEARS IN THE LOADCOM COMMAND */
DECLARE
TRUE LITERALLY '1',
FALSE LITERALLY '0',
FOREVER LITERALLY 'WHILE TRUE',
CR LITERALLY '13',
LF LITERALLY '10',
WHAT LITERALLY '63';
PRINTCHAR: PROCEDURE(CHAR);
DECLARE CHAR BYTE;
CALL MON1(2,CHAR);
END PRINTCHAR;
CRLF: PROCEDURE;
CALL PRINTCHAR(CR);
CALL PRINTCHAR(LF);
END CRLF;
PRINTNIB: PROCEDURE(N);
DECLARE N BYTE;
IF N > 9 THEN CALL PRINTCHAR(N+'A'-10); ELSE
CALL PRINTCHAR(N+'0');
END PRINTNIB;
PRINTHEX: PROCEDURE(B);
DECLARE B BYTE;
CALL PRINTNIB(SHR(B,4)); CALL PRINTNIB(B AND 0FH);
END PRINTHEX;
PRINTADDR: PROCEDURE(A);
DECLARE A ADDRESS;
CALL PRINTHEX(HIGH(A)); CALL PRINTHEX(LOW(A));
END PRINTADDR;
PRINTM: PROCEDURE(A);
DECLARE A ADDRESS;
CALL MON1(9,A);
END PRINTM;
PRINT: PROCEDURE(A);
DECLARE A ADDRESS;
/* PRINT THE STRING STARTING AT ADDRESS A UNTIL THE
NEXT DOLLAR SIGN IS ENCOUNTERED WITH PRECEDING CRLF */
CALL CRLF;
CALL PRINTM(A);
END PRINT;
DECLARE LA ADDRESS; /* CURRENT LOAD ADDRESS */
PERROR: PROCEDURE(A);
/* PRINT ERROR MESSAGE */
DECLARE A ADDRESS;
CALL PRINT(.('ERROR: $'));
CALL PRINTM(A);
CALL PRINTM(.(', LOAD ADDRESS $'));
CALL PRINTADDR(LA);
CALL BOOT;
END PERROR;
DECLARE DCNT BYTE;
OPEN: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(15,FCB);
END OPEN;
CLOSE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(16,FCB);
END CLOSE;
SEARCH: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(17,FCB);
END SEARCH;
SEARCHN: PROCEDURE;
DCNT = MON2(18,0);
END SEARCHN;
DELETE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL MON1(19,FCB);
END DELETE;
DISKREAD: PROCEDURE(FCB) BYTE;
DECLARE FCB ADDRESS;
RETURN MON2(20,FCB);
END DISKREAD;
DISKWRITE: PROCEDURE(FCB) BYTE;
DECLARE FCB ADDRESS;
RETURN MON2(21,FCB);
END DISKWRITE;
MAKE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(22,FCB);
END MAKE;
RENAME: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL MON1(23,FCB);
END RENAME;
MOVE: PROCEDURE(S,D,N);
DECLARE (S,D) ADDRESS, N BYTE,
A BASED S BYTE, B BASED D BYTE;
DO WHILE (N:=N-1) <> 255;
B = A; S=S+1; D=D+1;
END;
END MOVE;
GETCHAR: PROCEDURE BYTE;
/* GET NEXT CHARACTER */
DECLARE I BYTE;
IF (SBP := SBP+1) <= LAST(SBUFF) THEN
RETURN SBUFF(SBP);
/* OTHERWISE READ ANOTHER BUFFER FULL */
DO SBP = 0 TO LAST(SBUFF) BY 128;
IF (I:=DISKREAD(.SFCB)) = 0 THEN
CALL MOVE(80H,.SBUFF(SBP),80H); ELSE
DO;
IF I<>1 THEN CALL PERROR(.('DISK READ$'));
SBUFF(SBP) = EOFILE;
SBP = LAST(SBUFF);
END;
END;
SBP = 0; RETURN SBUFF(0);
END GETCHAR;
DECLARE
STACKPOINTER LITERALLY 'STACKPTR';
/* INTEL HEX FORMAT LOADER */
RELOC: PROCEDURE;
DECLARE (RL, CS, RT) BYTE;
DECLARE
TA ADDRESS, /* TEMP ADDRESS */
SA ADDRESS, /* START ADDRESS */
FA ADDRESS, /* FINAL ADDRESS */
NB ADDRESS, /* NUMBER OF BYTES LOADED */
MBUFF(256) BYTE,
P BYTE,
L ADDRESS;
SETMEM: PROCEDURE(B);
/* SET MBUFF TO B AT LOCATION LA MOD LENGTH(MBUFF) */
DECLARE (B,I) BYTE;
IF LA < L THEN
CALL PERROR(.('INVERTED LOAD ADDRESS$'));
DO WHILE LA > L + LAST(MBUFF); /* WRITE A PARAGRAPH */
DO I = 0 TO 127; /* COPY INTO BUFFER */
BUFFER(I) = MBUFF(LOW(L)); L = L + 1;
END;
/* WRITE BUFFER ONTO DISK */
P = P + 1;
IF DISKWRITE(FCBA) <> 0 THEN
DO; CALL PERROR(.('DISK WRITE$'));
END;
END;
MBUFF(LOW(LA)) = B;
END SETMEM;
DIAGNOSE: PROCEDURE;
DECLARE M BASED TA BYTE;
NEWLINE: PROCEDURE;
CALL CRLF; CALL PRINTADDR(TA); CALL PRINTCHAR(':');
CALL PRINTCHAR(' ');
END NEWLINE;
/* PRINT DIAGNOSTIC INFORMATION AT THE CONSOLE */
CALL PRINT(.('LOAD ADDRESS $')); CALL PRINTADDR(TA);
CALL PRINT(.('ERROR ADDRESS $')); CALL PRINTADDR(LA);
CALL PRINT(.('BYTES READ:$')); CALL NEWLINE;
DO WHILE TA < LA;
IF (LOW(TA) AND 0FH) = 0 THEN CALL NEWLINE;
CALL PRINTHEX(MBUFF(TA-L)); TA=TA+1;
CALL PRINTCHAR(' ');
END;
CALL CRLF;
CALL BOOT;
END DIAGNOSE;
READHEX: PROCEDURE BYTE;
/* READ ONE HEX CHARACTER FROM THE INPUT */
DECLARE H BYTE;
IF (H := GETCHAR) - '0' <= 9 THEN RETURN H - '0';
IF H - 'A' > 5 THEN
DO; CALL PRINT(.('INVALID HEX DIGIT$'));
CALL DIAGNOSE;
END;
RETURN H - 'A' + 10;
END READHEX;
READBYTE: PROCEDURE BYTE;
/* READ TWO HEX DIGITS */
RETURN SHL(READHEX,4) OR READHEX;
END READBYTE;
READCS: PROCEDURE BYTE;
/* READ BYTE WHILE COMPUTING CHECKSUM */
DECLARE B BYTE;
CS = CS + (B := READBYTE);
RETURN B;
END READCS;
MAKE$DOUBLE: PROCEDURE(H,L) ADDRESS;
/* CREATE A BOUBLE BYTE VALUE FROM TWO SINGLE BYTES */
DECLARE (H,L) BYTE;
RETURN SHL(DOUBLE(H),8) OR L;
END MAKE$DOUBLE;
/* INITIALIZE */
SA, FA, NB = 0;
P = 0; /* PARAGRAPH COUNT */
TA,L = TPA; /* BASE ADDRESS OF TRANSIENT ROUTINES */
SBUFF(0) = EOFILE;
/* READ RECORDS UNTIL :00XXXX IS ENCOUNTERED */
DO FOREVER;
/* SCAN THE : */
DO WHILE GETCHAR <> ':';
END;
/* SET CHECK SUM TO ZERO, AND SAVE THE RECORD LENGTH */
CS = 0;
/* MAY BE THE END OF TAPE */
IF (RL := READCS) = 0 THEN
GO TO FIN;
NB = NB + RL;
TA, LA = MAKE$DOUBLE(READCS,READCS);
IF SA = 0 THEN SA = LA;
/* READ THE RECORD TYPE (NOT CURRENTLY USED) */
RT = READCS;
/* PROCESS EACH BYTE */
DO WHILE (RL := RL - 1) <> 255;
CALL SETMEM(READCS); LA = LA+1;
END;
IF LA > FA THEN FA = LA - 1;
/* NOW READ CHECKSUM AND COMPARE */
IF CS + READBYTE <> 0 THEN
DO; CALL PRINT(.('CHECK SUM ERROR $'));
CALL DIAGNOSE;
END;
END;
FIN:
/* EMPTY THE BUFFERS */
TA = LA;
DO WHILE L < TA;
CALL SETMEM(0); LA = LA+1;
END;
/* PRINT FINAL STATISTICS */
CALL PRINT(.('FIRST ADDRESS $')); CALL PRINTADDR(SA);
CALL PRINT(.('LAST ADDRESS $')); CALL PRINTADDR(FA);
CALL PRINT(.('BYTES READ $')); CALL PRINTADDR(NB);
CALL PRINT(.('RECORDS WRITTEN $')); CALL PRINTHEX(P);
CALL CRLF;
END RELOC;
/* ARRIVE HERE FROM THE SYSTEM MONITOR, READY TO READ THE HEX TAPE */
/* SET UP STACKPOINTER IN THE LOCAL AREA */
DECLARE STACK(16) ADDRESS;
SP = STACKPOINTER; STACKPOINTER = .STACK(LENGTH(STACK));
LA = TPA;
SBP = LENGTH(SBUFF);
/* SET UP THE SOURCE FILE */
CALL MOVE(FCBA,.SFCB,33);
CALL MOVE(.('HEX',0),.SFCB(9),4);
CALL OPEN(.SFCB);
IF DCNT = 255 THEN CALL PERROR(.('CANNOT OPEN SOURCE$'));
CALL MOVE(.('COM'),FCBA+9,3);
/* REMOVE ANY EXISTING FILE BY THIS NAME */
CALL DELETE(FCBA);
/* THEN OPEN A NEW FILE */
CALL MAKE(FCBA); CALL OPEN(FCBA);
IF DCNT = 255 THEN CALL PERROR(.('NO MORE DIRECTORY SPACE$')); ELSE
DO; CALL RELOC;
CALL CLOSE(FCBA);
IF DCNT = 255 THEN CALL PERROR(.('CANNOT CLOSE FILE$'));
END;
CALL CRLF;
CALL BOOT;
END LOADCOM;
END;


View File

@@ -0,0 +1,16 @@
; movcpm patch for cp/m 2.0 10/4/79
;
; the BDOS system reset function, number 0,
; previously executed a cold start, rather
; than a warm start.
;
; assembly language source change:
; 0844 DW WBOOTF, FUNC1, FUNC2, FUNC3
;
; assembly language patch
bias equ 0a00h ;bias within movcpm
wbootf equ 1603h ;relative wbootf addr
org 0844h+bias
dw wbootf
end


View File

@@ -0,0 +1,127 @@
title 'mds cold start loader at 3000h'
;
; MDS-800 Cold Start Loader for CP/M 2.0
;
; Version 2.0 August, 1979
;
false equ 0
true equ not false
testing equ false ;if true, then go to mon80 on errors
;
if testing
bias equ 03400h
endif
if not testing
bias equ 0000h
endif
cpmb equ bias ;base of dos load
bdos equ 806h+bias ;entry to dos for calls
bdose equ 1880h+bias ;end of dos load
boot equ 1600h+bias ;cold start entry point
rboot equ boot+3 ;warm start entry point
;
org 03000h ;loaded down from hardware boot at 3000h
;
bdosl equ bdose-cpmb
ntrks equ 2 ;number of tracks to read
bdoss equ bdosl/128 ;number of sectors in dos
bdos0 equ 25 ;number of bdos sectors on track 0
bdos1 equ bdoss-bdos0 ;number of sectors on track 1
;
mon80 equ 0f800h ;intel monitor base
rmon80 equ 0ff0fh ;restart location for mon80
base equ 078h ;'base' used by controller
rtype equ base+1 ;result type
rbyte equ base+3 ;result byte
reset equ base+7 ;reset controller
;
dstat equ base ;disk status port
ilow equ base+1 ;low iopb address
ihigh equ base+2 ;high iopb address
bsw equ 0ffh ;boot switch
recal equ 3h ;recalibrate selected drive
readf equ 4h ;disk read function
stack equ 100h ;use end of boot for stack
;
rstart:
lxi sp,stack;in case of call to mon80
; clear disk status
in rtype
in rbyte
; check if boot switch is off
coldstart:
in bsw
ani 02h ;switch on?
jnz coldstart
; clear the controller
out reset ;logic cleared
;
;
mvi b,ntrks ;number of tracks to read
lxi h,iopb0
;
start:
;
; read first/next track into cpmb
mov a,l
out ilow
mov a,h
out ihigh
wait0: in dstat
ani 4
jz wait0
;
; check disk status
in rtype
ani 11b
cpi 2
;
if testing
cnc rmon80 ;go to monitor if 11 or 10
endif
if not testing
jnc rstart ;retry the load
endif
;
in rbyte ;i/o complete, check status
; if not ready, then go to mon80
ral
cc rmon80 ;not ready bit set
rar ;restore
ani 11110b ;overrun/addr err/seek/crc/xxxx
;
if testing
cnz rmon80 ;go to monitor
endif
if not testing
jnz rstart ;retry the load
endif
;
;
lxi d,iopbl ;length of iopb
dad d ;addressing next iopb
dcr b ;count down tracks
jnz start
;
;
; jmp to boot to print initial message, and set up jmps
jmp boot
;
; parameter blocks
iopb0: db 80h ;iocw, no update
db readf ;read function
db bdos0 ;# sectors to read on track 0
db 0 ;track 0
db 2 ;start with sector 2 on track 0
dw cpmb ;start at base of bdos
iopbl equ $-iopb0
;
iopb1: db 80h
db readf
db bdos1 ;sectors to read on track 1
db 1 ;track 1
db 1 ;sector 1
dw cpmb+bdos0*128 ;base of second read
;
end


View File

@@ -0,0 +1,831 @@
title 'console command processor (CCP), ver 2.0'
; assembly language version of the CP/M console command processor
;
; version 2.0 July, 1979
;
; Copyright (c) 1976, 1977, 1978, 1979
; Digital Research
; Box 579, Pacific Grove,
; California, 93950
;
false equ 0000h
true equ not false
testing equ false ;true if debugging
;
;
if testing
org 3400h
bdosl equ $+800h ;bdos location
else
org 000h
bdosl equ $+800h ;bdos location
endif
tran equ 100h
tranm equ $
ccploc equ $
;
; ********************************************************
; * Base of CCP contains the following code/data *
; * ccp: jmp ccpstart (start with command) *
; * jmp ccpclear (start, clear command) *
; * ccp+6 127 (max command length) *
; * ccp+7 comlen (command length = 00) *
; * ccp+8 ' ... ' (16 blanks) *
; ********************************************************
; * Normal entry is at ccp, where the command line given *
; * at ccp+8 is executed automatically (normally a null *
; * command with comlen = 00). An initializing program *
; * can be automatically loaded by storing the command *
; * at ccp+8, with the command length at ccp+7. In this *
; * case, the ccp executes the command before prompting *
; * the console for input. Note that the command is exe-*
; * cuted on both warm and cold starts. When the command*
; * line is initialized, a jump to "jmp ccpclear" dis- *
; * ables the automatic command execution. *
; ********************************************************
;
jmp ccpstart ;start ccp with possible initial command
jmp ccpclear ;clear the command buffer
maxlen: db 127 ;max buffer length
comlen: db 0 ;command length (filled in by dos)
; (command executed initially if comlen non zero)
combuf:
db ' ' ;8 character fill
db ' ' ;8 character fill
db 'COPYRIGHT (C) 1979, DIGITAL RESEARCH '; 38
ds 128-($-combuf)
; total buffer length is 128 characters
comaddr:dw combuf ;address of next to char to scan
staddr: ds 2 ;starting address of current fillfcb request
;
diska equ 0004h ;disk address for current disk
bdos equ 0005h ;primary bdos entry point
buff equ 0080h ;default buffer
fcb equ 005ch ;default file control block
;
rcharf equ 1 ;read character function
pcharf equ 2 ;print character function
pbuff equ 9 ;print buffer function
rbuff equ 10 ;read buffer function
breakf equ 11 ;break key function
liftf equ 12 ;lift head function (no operation)
initf equ 13 ;initialize bdos function
self equ 14 ;select disk function
openf equ 15 ;open file function
closef equ 16 ;close file function
searf equ 17 ;search for file function
searnf equ 18 ;search for next file function
delf equ 19 ;delete file function
dreadf equ 20 ;disk read function
dwritf equ 21 ;disk write function
makef equ 22 ;file make function
renf equ 23 ;rename file function
logf equ 24 ;return login vector
cself equ 25 ;return currently selected drive number
dmaf equ 26 ;set dma address
userf equ 32 ;set user number
;
; special fcb flags
rofile equ 9 ;read only file
sysfile equ 10 ;system file flag
;
; special characters
cr equ 13 ;carriage return
lf equ 10 ;line feed
la equ 5fh ;left arrow
eofile equ 1ah ;end of file
;
; utility procedures
printchar:
mov e,a! mvi c,pcharf! jmp bdos
;
printbc:
;print character, but save b,c registers
push b! call printchar! pop b! ret
;
crlf:
mvi a,cr! call printbc
mvi a,lf! jmp printbc
;
blank:
mvi a,' '! jmp printbc
;
print: ;print string starting at b,c until next 00 entry
push b! call crlf! pop h ;now print the string
prin0: mov a,m! ora a! rz ;stop on 00
inx h! push h ;ready for next
call printchar! pop h ;character printed
jmp prin0 ;for another character
;
initialize:
mvi c,initf! jmp bdos
;
select:
mov e,a! mvi c,self! jmp bdos
;
bdos$inr:
call bdos! sta dcnt! inr a! ret
;
open: ;open the file given by d,e
mvi c,openf! jmp bdos$inr
;
openc: ;open comfcb
xra a! sta comrec ;clear next record to read
lxi d,comfcb! jmp open
;
close: ;close the file given by d,e
mvi c,closef! jmp bdos$inr
;
search: ;search for the file given by d,e
mvi c,searf! jmp bdos$inr
;
searchn:
;search for the next occurrence of the file given by d,e
mvi c,searnf! jmp bdos$inr
;
searchcom:
;search for comfcb file
lxi d,comfcb! jmp search
;
delete: ;delete the file given by d,e
mvi c,delf! jmp bdos
;
bdos$cond:
call bdos! ora a! ret
;
diskread:
;read the next record from the file given by d,e
mvi c,dreadf! jmp bdos$cond
;
diskreadc:
;read the comfcb file
lxi d,comfcb! jmp diskread
;
diskwrite:
;write the next record to the file given by d,e
mvi c,dwritf! jmp bdos$cond
;
make: ;create the file given by d,e
mvi c,makef! jmp bdos$inr
;
renam: ;rename the file given by d,e
mvi c,renf! jmp bdos
;
getuser:
;return current user code in a
mvi e,0ffh ;drop through to setuser
;
setuser:
mvi c,userf! jmp bdos ;sets user number
;
saveuser:
;save user#/disk# before possible ^c or transient
call getuser ;code to a
add a! add a! add a! add a ;rot left
lxi h,cdisk! ora m ;4b=user, 4b=disk
sta diska ;stored away in memory for later
ret
;
setdiska:
lda cdisk! sta diska ;user/disk
ret
;
translate:
;translate character in register A to upper case
cpi 61h! rc ;return if below lower case a
cpi 7bh! rnc ;return if above lower case z
ani 5fh! ret ;translated to upper case
;
readcom:
;read the next command into the command buffer
;check for submit file
lda submit! ora a! jz nosub
;scanning a submit file
;change drives to open and read the file
lda cdisk! ora a! mvi a,0! cnz select
;have to open again in case xsub present
lxi d,subfcb! call open! jz nosub ;skip if no sub
lda subrc! dcr a ;read last record(s) first
sta subcr ;current record to read
lxi d,subfcb! call diskread ;end of file if last record
jnz nosub
;disk read is ok, transfer to combuf
lxi d,comlen! lxi h,buff! mvi b,128! call move0
;line is transferred, close the file with a
;deleted record
lxi h,submod! mvi m,0 ;clear fwflag
inx h! dcr m ;one less record
lxi d,subfcb! call close! jz nosub
;close went ok, return to original drive
lda cdisk! ora a! cnz select
;print to the 00
lxi h,combuf! call prin0
call break$key! jz noread
call del$sub! jmp ccp ;break key depressed
;
nosub: ;no submit file! call del$sub
;translate to upper case, store zero at end
call saveuser ;user # save in case control c
mvi c,rbuff! lxi d,maxlen! call bdos
call setdiska ;no control c, so restore diska
noread: ;enter here from submit file
;set the last character to zero for later scans
lxi h,comlen! mov b,m ;length is in b
readcom0: inx h! mov a,b! ora a ;end of scan?
jz readcom1! mov a,m ;get character and translate
call translate! mov m,a! dcr b! jmp readcom0
;
readcom1: ;end of scan, h,l address end of command
mov m,a ;store a zero
lxi h,combuf! shld comaddr ;ready to scan to zero
ret
;
break$key:
;check for a character ready at the console
mvi c,breakf! call bdos
ora a! rz
mvi c,rcharf! call bdos ;character cleared
ora a! ret
;
cselect:
;get the currently selected drive number to reg-A
mvi c,cself! jmp bdos
;
setdmabuff:
;set default buffer dma address
lxi d,buff ;(drop through)
;
setdma:
;set dma address to d,e
mvi c,dmaf! jmp bdos
;
del$sub:
;delete the submit file, and set submit flag to false
lxi h,submit! mov a,m! ora a! rz ;return if no sub file
mvi m,0 ;submit flag is set to false
xra a! call select ;on drive a to erase file
lxi d,subfcb! call delete
lda cdisk! jmp select ;back to original drive
;
serialize:
;check serialization
lxi d,serial! lxi h,bdosl! mvi b,6 ;check six bytes
ser0: ldax d! cmp m! jnz badserial
inx d! inx h! dcr b! jnz ser0
ret ;serial number is ok
;
comerr:
;error in command string starting at position
;'staddr' and ending with first delimiter
call crlf ;space to next line
lhld staddr ;h,l address first to print
comerr0: ;print characters until blank or zero
mov a,m! cpi ' '! jz comerr1; not blank
ora a! jz comerr1; not zero, so print it
push h! call printchar! pop h! inx h
jmp comerr0; for another character
comerr1: ;print question mark,and delete sub file
mvi a,'?'! call printchar
call crlf! call del$sub
jmp ccp ;restart with next command
;
; fcb scan and fill subroutine (entry is at fillfcb below)
;fill the comfcb, indexed by A (0 or 16)
;subroutines
delim: ;look for a delimiter
ldax d! ora a! rz ;not the last element
cpi ' '! jc comerr ;non graphic
rz ;treat blank as delimiter
cpi '='! rz
cpi la! rz ;left arrow
cpi '.'! rz
cpi ':'! rz
cpi ';'! rz
cpi '<'! rz
cpi '>'! rz
ret ;delimiter not found
;
deblank: ;deblank the input line
ldax d! ora a! rz ;treat end of line as blank
cpi ' '! rnz! inx d! jmp deblank
;
addh: ;add a to h,l
add l! mov l,a! rnc
inr h! ret
;
fillfcb0:
;equivalent to fillfcb(0)
mvi a,0
;
fillfcb:
lxi h,comfcb! call addh! push h! push h ;fcb rescanned at end
xra a! sta sdisk ;clear selected disk (in case A:...)
lhld comaddr! xchg ;command address in d,e
call deblank ;to first non-blank character
xchg! shld staddr ;in case of errors
xchg! pop h ;d,e has command, h,l has fcb address
;look for preceding file name A: B: ...
ldax d! ora a! jz setcur0 ;use current disk if empty command
sbi 'A'-1! mov b,a ;disk name held in b if : follows
inx d! ldax d! cpi ':'! jz setdsk ;set disk name if :
;
setcur: ;set current disk
dcx d ;back to first character of command
setcur0:
lda cdisk! mov m,a! jmp setname
;
setdsk: ;set disk to name in register b
mov a,b! sta sdisk ;mark as disk selected
mov m,b! inx d ;past the :
;
setname: ;set the file name field
mvi b,8 ;file name length (max)
setnam0: call delim! jz padname ;not a delimiter
inx h! cpi '*'! jnz setnam1 ;must be ?'s
mvi m,'?'! jmp setnam2 ;to dec count
;
setnam1: mov m,a ;store character to fcb! inx d
setnam2: dcr b ;count down length! jnz setnam0
;
;end of name, truncate remainder
trname: call delim! jz setty ;set type field if delimiter
inx d! jmp trname
;
padname: inx h! mvi m,' '! dcr b! jnz padname
;
setty: ;set the type field
mvi b,3! cpi '.'! jnz padty ;skip the type field if no .
inx d ;past the ., to the file type field
setty0: ;set the field from the command buffer
call delim! jz padty! inx h! cpi '*'! jnz setty1
mvi m,'?' ;since * specified! jmp setty2
;
setty1: ;not a *, so copy to type field
mov m,a! inx d
setty2: ;decrement count and go again
dcr b! jnz setty0
;
;end of type field, truncate
trtyp: ;truncate type field
call delim! jz efill! inx d! jmp trtyp
;
padty: ;pad the type field with blanks
inx h! mvi m,' '! dcr b! jnz padty
;
efill: ;end of the filename/filetype fill, save command address
;fill the remaining fields for the fcb
mvi b,3
efill0: inx h! mvi m,0! dcr b! jnz efill0
xchg! shld comaddr ;set new starting point
;
;recover the start address of the fcb and count ?'s
pop h! lxi b,11 ;b=0, c=8+3
scnq: inx h! mov a,m! cpi '?'! jnz scnq0
;? found, count it in b! inr b
scnq0: dcr c! jnz scnq
;
;number of ?'s in c, move to a and return with flags set
mov a,b! ora a! ret
;
intvec:
;intrinsic function names (all are four characters)
db 'DIR '
db 'ERA '
db 'TYPE'
db 'SAVE'
db 'REN '
db 'USER'
intlen equ ($-intvec)/4 ;intrinsic function length
serial: db 0,0,0,0,0,0
;
;
intrinsic:
;look for intrinsic functions (comfcb has been filled)
lxi h,intvec! mvi c,0 ;c counts intrinsics as scanned
intrin0: mov a,c! cpi intlen ;done with scan?! rnc
;no, more to scan
lxi d,comfcb+1 ;beginning of name
mvi b,4 ;length of match is in b
intrin1: ldax d! cmp m ;match?
jnz intrin2 ;skip if no match
inx d! inx h! dcr b
jnz intrin1 ;loop while matching
;
;complete match on name, check for blank in fcb
ldax d! cpi ' '! jnz intrin3 ;otherwise matched
mov a,c! ret ;with intrinsic number in a
;
intrin2: ;mismatch, move to end of intrinsic
inx h! dcr b! jnz intrin2
;
intrin3: ;try next intrinsic
inr c ;to next intrinsic number
jmp intrin0 ;for another round
;
ccpclear:
;clear the command buffer
xra a
sta comlen
;drop through to start ccp
ccpstart:
;enter here from boot loader
lxi sp,stack! push b ;save initial disk number
;(high order 4bits=user code, low 4bits=disk#)
mov a,c! rar! rar! rar! rar! ani 0fh ;user code
mov e,a! call setuser ;user code selected
;initialize for this user, get $ flag
call initialize ;0ffh in accum if $ file present
sta submit ;submit flag set if $ file present
pop b ;recall user code and disk number
mov a,c! ani 0fh ;disk number in accumulator
sta diska ;clears low memory user code nibble
call select ;proper disk is selected, now check sub files
;check for initial command
lda comlen! ora a! jnz ccp0 ;assume typed already
;
ccp:
;enter here on each command or error condition
lxi sp,stack
call crlf ;print d> prompt, where d is disk name
call cselect ;get current disk number
adi 'A'! call printchar
mvi a,'>'! call printchar
call readcom ;command buffer filled
ccp0: ;(enter here from initialization with command full)
lxi d,buff! call setdma ;default dma address at buff
call cselect! sta cdisk ;current disk number saved
call fillfcb0 ;command fcb filled
cnz comerr ;the name cannot be an ambiguous reference
lda sdisk! ora a! jnz userfunc
;check for an intrinsic function
call intrinsic
lxi h,jmptab ;index is in the accumulator
mov e,a! mvi d,0! dad d! dad d ;index in d,e
mov a,m! inx h! mov h,m! mov l,a! pchl
;pc changes to the proper intrinsic or user function
jmptab:
dw direct ;directory search
dw erase ;file erase
dw type ;type file
dw save ;save memory image
dw rename ;file rename
dw user ;user number
dw userfunc;user-defined function
badserial:
lxi h,di or (hlt shl 8)
shld ccploc! lxi h,ccploc! pchl
;
;
;utility subroutines for intrinsic handlers
readerr:
;print the read error message
lxi b,rdmsg! jmp print
rdmsg: db 'READ ERROR',0
;
nofile:
;print no file message
lxi b,nofmsg! jmp print
nofmsg: db 'NO FILE',0
;
getnumber: ;read a number from the command line
call fillfcb0 ;should be number
lda sdisk! ora a! jnz comerr ;cannot be prefixed
;convert the byte value in comfcb to binary
lxi h,comfcb+1! lxi b,11 ;(b=0, c=11)
;value accumulated in b, c counts name length to zero
conv0: mov a,m! cpi ' '! jz conv1
;more to scan, convert char to binary and add
inx h! sui '0'! cpi 10! jnc comerr ;valid?
mov d,a ;save value! mov a,b ;mult by 10
ani 1110$0000b! jnz comerr
mov a,b ;recover value
rlc! rlc! rlc ;*8
add b! jc comerr
add b! jc comerr ;*8+*2 = *10
add d! jc comerr ;+digit
mov b,a! dcr c! jnz conv0 ;for another digit
ret
conv1: ;end of digits, check for all blanks
mov a,m! cpi ' '! jnz comerr ;blanks?
inx h! dcr c! jnz conv1
mov a,b ;recover value! ret
;
movename:
;move 3 characters from h,l to d,e addresses
mvi b,3
move0: mov a,m! stax d! inx h! inx d
dcr b! jnz move0
ret
;
addhcf: ;buff + a + c to h,l followed by fetch
lxi h,buff! add c! call addh! mov a,m! ret
;
setdisk:
;change disks for this command, if requested
xra a! sta comfcb ;clear disk name from fcb
lda sdisk! ora a! rz ;no action if not specified
dcr a! lxi h,cdisk! cmp m! rz ;already selected
jmp select
;
resetdisk:
;return to original disk after command
lda sdisk! ora a! rz ;no action if not selected
dcr a! lxi h,cdisk! cmp m! rz ;same disk
lda cdisk! jmp select
;
;individual intrinsics follow
direct:
;directory search
call fillfcb0 ;comfcb gets file name
call setdisk ;change disk drives if requested
lxi h,comfcb+1! mov a,m ;may be empty request
cpi ' '! jnz dir1 ;skip fill of ??? if not blank
;set comfcb to all ??? for current disk
mvi b,11 ;length of fill ????????.???
dir0: mvi m,'?'! inx h! dcr b! jnz dir0
;not a blank request, must be in comfcb
dir1: mvi e,0! push d ;E counts directory entries
call searchcom ;first one has been found
cz nofile ;not found message
dir2: jz endir
;found, but may be system file
lda dcnt ;get the location of the element
rrc! rrc! rrc! ani 110$0000b! mov c,a
;c contains base index into buff for dir entry
mvi a,sysfile! call addhcf ;value to A
ral! jc dir6 ;skip if system file
;c holds index into buffer
;another fcb found, new line?
pop d! mov a,e! inr e! push d
;e=0,1,2,3,...new line if mod 4 = 0
ani 11b! push psw ;and save the test
jnz dirhdr0 ;header on current line
call crlf
push b! call cselect! pop b
;current disk in A
adi 'A'! call printbc
mvi a,':'! call printbc
jmp dirhdr1 ;skip current line hdr
dirhdr0:call blank ;after last one
mvi a,':'! call printbc
dirhdr1:
call blank
;compute position of name in buffer
mvi b,1 ;start with first character of name
dir3: mov a,b! call addhcf ;buff+a+c fetched
ani 7fh ;mask flags
;may delete trailing blanks
cpi ' '! jnz dir4 ;check for blank type
pop psw! push psw ;may be 3rd item
cpi 3! jnz dirb ;place blank at end if not
mvi a,9! call addhcf ;first char of type
ani 7fh! cpi ' '! jz dir5
;not a blank in the file type field
dirb: mvi a,' ' ;restore trailing filename chr
dir4:
call printbc ;char printed
inr b! mov a,b! cpi 12! jnc dir5
;check for break between names
cpi 9! jnz dir3 ;for another char
;print a blank between names
call blank! jmp dir3
;
dir5: ;end of current entry
pop psw ;discard the directory counter (mod 4)
dir6: call break$key ;check for interrupt at keyboard
jnz endir ;abort directory search
call searchn! jmp dir2 ;for another entry
endir: ;end of directory scan
pop d ;discard directory counter
jmp retcom
;
;
erase:
call fillfcb0 ;cannot be all ???'s
cpi 11
jnz erasefile
;erasing all of the disk
lxi b,ermsg! call print!
call readcom
lxi h,comlen! dcr m! jnz ccp ;bad input
inx h! mov a,m! cpi 'Y'! jnz ccp
;ok, erase the entire diskette
inx h! shld comaddr ;otherwise error at retcom
erasefile:
call setdisk
lxi d,comfcb! call delete
inr a ;255 returned if not found
cz nofile ;no file message if so
jmp retcom
;
ermsg: db 'ALL (Y/N)?',0
;
type:
call fillfcb0! jnz comerr ;don't allow ?'s in file name
call setdisk! call openc ;open the file
jz typerr ;zero flag indicates not found
;file opened, read 'til eof
call crlf! lxi h,bptr! mvi m,255 ;read first buffer
type0: ;loop on bptr
lxi h,bptr! mov a,m! cpi 128 ;end buffer
jc type1! push h ;carry if 0,1,...,127
;read another buffer full
call diskreadc! pop h ;recover address of bptr
jnz typeof ;hard end of file
xra a! mov m,a ;bptr = 0
type1: ;read character at bptr and print
inr m ;bptr = bptr + 1
lxi h,buff! call addh ;h,l addresses char
mov a,m! cpi eofile! jz retcom
call printchar
call break$key! jnz retcom ;abort if break
jmp type0 ;for another character
;
typeof: ;end of file, check for errors
dcr a! jz retcom
call readerr
typerr: call resetdisk! jmp comerr
;
save:
call getnumber; value to register a
push psw ;save it for later
;
;should be followed by a file to save the memory image
call fillfcb0
jnz comerr ;cannot be ambiguous
call setdisk ;may be a disk change
lxi d,comfcb! push d! call delete ;existing file removed
pop d! call make ;create a new file on disk
jz saverr ;no directory space
xra a! sta comrec; clear next record field
pop psw ;#pages to write is in a, change to #sectors
mov l,a! mvi h,0! dad h!
lxi d,tran ;h,l is sector count, d,e is load address
save0: ;check for sector count zero
mov a,h! ora l! jz save1 ;may be completed
dcx h ;sector count = sector count - 1
push h ;save it for next time around
lxi h,128! dad d! push h ;next dma address saved
call setdma ;current dma address set
lxi d,comfcb! call diskwrite
pop d! pop h ;dma address, sector count
jnz saverr ;may be disk full case
jmp save0 ;for another sector
;
save1: ;end of dump, close the file
lxi d,comfcb! call close
inr a; 255 becomes 00 if error
jnz retsave ;for another command
saverr: ;must be full or read only disk
lxi b,fullmsg! call print
retsave:
;reset dma buffer
call setdmabuff
jmp retcom
fullmsg: db 'NO SPACE',0
;
;
rename:
;rename a file on a specific disk
call fillfcb0! jnz comerr ;must be unambiguous
lda sdisk! push psw ;save for later compare
call setdisk ;disk selected
call searchcom ;is new name already there?
jnz renerr3
;file doesn't exist, move to second half of fcb
lxi h,comfcb! lxi d,comfcb+16! mvi b,16! call move0
;check for = or left arrow
lhld comaddr! xchg! call deblank
cpi '='! jz ren1 ;ok if =
cpi la! jnz renerr2
ren1: xchg! inx h! shld comaddr ;past delimiter
;proper delimiter found
call fillfcb0! jnz renerr2
;check for drive conflict
pop psw! mov b,a ;previous drive number
lxi h,sdisk! mov a,m! ora a! jz ren2
;drive name was specified. same one?
cmp b! mov m,b! jnz renerr2
ren2: mov m,b ;store the name in case drives switched
xra a! sta comfcb! call searchcom ;is old file there?
jz renerr1
;
;everything is ok, rename the file
lxi d,comfcb! call renam
jmp retcom
;
renerr1:; no file on disk
call nofile! jmp retcom
renerr2:; ambigous reference/name conflict
call resetdisk! jmp comerr
renerr3:; file already exists
lxi b,renmsg! call print! jmp retcom
renmsg: db 'FILE EXISTS',0
;
user:
;set user number
call getnumber; leaves the value in the accumulator
cpi 16! jnc comerr; must be between 0 and 15
mov e,a ;save for setuser call
lda comfcb+1! cpi ' '! jz comerr
call setuser ;new user number set
jmp endcom
;
userfunc:
call serialize ;check serialization
;load user function and set up for execution
lda comfcb+1! cpi ' '! jnz user0
;no file name, but may be disk switch
lda sdisk! ora a! jz endcom ;no disk name if 0
dcr a! sta cdisk! call setdiska ;set user/disk
call select! jmp endcom
user0: ;file name is present
lxi d,comfcb+9! ldax d! cpi ' '! jnz comerr ;type ' '
push d! call setdisk! pop d! lxi h,comtype ;.com
call movename ;file type is set to .com
call openc! jz userer
;file opened properly, read it into memory
lxi h,tran ;transient program base
load0: push h ;save dma address
xchg! call setdma
lxi d,comfcb! call diskread! jnz load1
;sector loaded, set new dma address and compare
pop h! lxi d,128! dad d
lxi d,tranm ;has the load overflowed?
mov a,l! sub e! mov a,h! sbb d! jnc loaderr
jmp load0 ;for another sector
;
load1: pop h! dcr a! jnz loaderr ;end file is 1
call resetdisk ;back to original disk
call fillfcb0! lxi h,sdisk! push h
mov a,m! sta comfcb ;drive number set
mvi a,16! call fillfcb ;move entire fcb to memory
pop h! mov a,m! sta comfcb+16
xra a! sta comrec ;record number set to zero
lxi d,fcb! lxi h,comfcb! mvi b,33! call move0
;move command line to buff
lxi h,combuf
bmove0: mov a,m! ora a! jz bmove1! cpi ' '! jz bmove1
inx h! jmp bmove0 ;for another scan
;first blank position found
bmove1: mvi b,0! lxi d,buff+1! ;ready for the move
bmove2: mov a,m! stax d! ora a! jz bmove3
;more to move
inr b! inx h! inx d! jmp bmove2
bmove3: ;b has character count
mov a,b! sta buff
call crlf
;now go to the loaded program
call setdmabuff ;default dma
call saveuser ;user code saved
;low memory diska contains user code
call tran ;gone to the loaded program
lxi sp,stack ;may come back here
call setdiska! call select
jmp ccp
;
userer: ;arrive here on command error
call resetdisk! jmp comerr
;
loaderr:;cannot load the program
lxi b,loadmsg! call print
jmp retcom
loadmsg: db 'BAD LOAD',0
comtype: db 'COM' ;for com files
;
;
retcom: ;reset disk before end of command check
call resetdisk
;
endcom: ;end of intrinsic command
call fillfcb0 ;to check for garbage at end of line
lda comfcb+1! sui ' '! lxi h,sdisk! ora m
;0 in accumulator if no disk selected, and blank fcb
jnz comerr
jmp ccp
;
;
;
; data areas
ds 16 ;8 level stack
stack:
;
; 'submit' file control block
submit: db 0 ;00 if no submit file, ff if submitting
subfcb: db 0,'$$$ ' ;file name is $$$
db 'SUB',0,0 ;file type is sub
submod: db 0 ;module number
subrc: ds 1 ;record count filed
ds 16 ;disk map
subcr: ds 1 ;current record to read
;
; command file control block
comfcb: ds 32 ;fields filled in later
comrec: ds 1 ;current record to read/write
dcnt: ds 1 ;disk directory count (used for error codes)
cdisk: ds 1 ;current disk
sdisk: ds 1 ;selected disk for current operation
;none=0, a=1, b=2 ...
bptr: ds 1 ;buffer pointer
end ccploc


File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,505 @@
; MDS-800 I/O Drivers for CP/M 2.0
; (four drive single density version)
;
; Version 2.0 August, 1979
;
vers equ 20 ;version 2.0
;
; Copyright (c) 1979
; Digital Research
; Box 579, Pacific Grove
; California, 93950
;
;
true equ 0ffffh ;value of "true"
false equ not true ;"false"
test equ false ;true if test bios
;
if test
bias equ 03400h ;base of CCP in test system
endif
if not test
bias equ 0000h ;generate relocatable cp/m system
endif
;
patch equ 1600h
;
org patch
cpmb equ $-patch ;base of cpm console processor
bdos equ 806h+cpmb ;basic dos (resident portion)
cpml equ $-cpmb ;length (in bytes) of cpm system
nsects equ cpml/128 ;number of sectors to load
offset equ 2 ;number of disk tracks used by cp/m
cdisk equ 0004h ;address of last logged disk on warm start
buff equ 0080h ;default buffer address
retry equ 10 ;max retries on disk i/o before error
;
; perform following functions
; boot cold start
; wboot warm start (save i/o byte)
; (boot and wboot are the same for mds)
; const console status
; reg-a = 00 if no character ready
; reg-a = ff if character ready
; conin console character in (result in reg-a)
; conout console character out (char in reg-c)
; list list out (char in reg-c)
; punch punch out (char in reg-c)
; reader paper tape reader in (result to reg-a)
; home move to track 00
;
; (the following calls set-up the io parameter block for the
; mds, which is used to perform subsequent reads and writes)
; seldsk select disk given by reg-c (0,1,2...)
; settrk set track address (0,...76) for subsequent read/write
; setsec set sector address (1,...,26) for subsequent read/write
; setdma set subsequent dma address (initially 80h)
;
; (read and write assume previous calls to set up the io parameters)
; read read track/sector to preset dma address
; write write track/sector from preset dma address
;
; jump vector for indiviual routines
jmp boot
wboote: jmp wboot
jmp const
jmp conin
jmp conout
jmp list
jmp punch
jmp reader
jmp home
jmp seldsk
jmp settrk
jmp setsec
jmp setdma
jmp read
jmp write
jmp listst ;list status
jmp sectran
;
maclib diskdef ;load the disk definition library
disks 4 ;four disks
diskdef 0,1,26,6,1024,243,64,64,offset
diskdef 1,0
diskdef 2,0
diskdef 3,0
; endef occurs at end of assembly
;
; end of controller - independent code, the remaining subroutines
; are tailored to the particular operating environment, and must
; be altered for any system which differs from the intel mds.
;
; the following code assumes the mds monitor exists at 0f800h
; and uses the i/o subroutines within the monitor
;
; we also assume the mds system has four disk drives
revrt equ 0fdh ;interrupt revert port
intc equ 0fch ;interrupt mask port
icon equ 0f3h ;interrupt control port
inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor)
;
; mds monitor equates
mon80 equ 0f800h ;mds monitor
rmon80 equ 0ff0fh ;restart mon80 (boot error)
ci equ 0f803h ;console character to reg-a
ri equ 0f806h ;reader in to reg-a
co equ 0f809h ;console char from c to console out
po equ 0f80ch ;punch char from c to punch device
lo equ 0f80fh ;list from c to list device
csts equ 0f812h ;console status 00/ff to register a
;
; disk ports and commands
base equ 78h ;base of disk command io ports
dstat equ base ;disk status (input)
rtype equ base+1 ;result type (input)
rbyte equ base+3 ;result byte (input)
;
ilow equ base+1 ;iopb low address (output)
ihigh equ base+2 ;iopb high address (output)
;
readf equ 4h ;read function
writf equ 6h ;write function
recal equ 3h ;recalibrate drive
iordy equ 4h ;i/o finished mask
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;
signon: ;signon message: xxk cp/m vers y.y
db cr,lf,lf
if test
db '32' ;32k example bios
endif
if not test
db '00' ;memory size filled by relocator
endif
db 'k CP/M vers '
db vers/10+'0','.',vers mod 10+'0'
db cr,lf,0
;
boot: ;print signon message and go to ccp
; (note: mds boot initialized iobyte at 0003h)
lxi sp,buff+80h
lxi h,signon
call prmsg ;print message
xra a ;clear accumulator
sta cdisk ;set initially to disk a
jmp gocpm ;go to cp/m
;
;
wboot:; loader on track 0, sector 1, which will be skipped for warm
; read cp/m from disk - assuming there is a 128 byte cold start
; start.
;
lxi sp,buff ;using dma - thus 80 thru ff available for stack
;
mvi c,retry ;max retries
push b
wboot0: ;enter here on error retries
lxi b,cpmb ;set dma address to start of disk system
call setdma
mvi c,0 ;boot from drive 0
call seldsk
mvi c,0
call settrk ;start with track 0
mvi c,2 ;start reading sector 2
call setsec
;
; read sectors, count nsects to zero
pop b ;10-error count
mvi b,nsects
rdsec: ;read next sector
push b ;save sector count
call read
jnz booterr ;retry if errors occur
lhld iod ;increment dma address
lxi d,128 ;sector size
dad d ;incremented dma address in hl
mov b,h
mov c,l ;ready for call to set dma
call setdma
lda ios ;sector number just read
cpi 26 ;read last sector?
jc rd1
; must be sector 26, zero and go to next track
lda iot ;get track to register a
inr a
mov c,a ;ready for call
call settrk
xra a ;clear sector number
rd1: inr a ;to next sector
mov c,a ;ready for call
call setsec
pop b ;recall sector count
dcr b ;done?
jnz rdsec
;
; done with the load, reset default buffer address
gocpm: ;(enter here from cold start boot)
; enable rst0 and rst7
di
mvi a,12h ;initialize command
out revrt
xra a
out intc ;cleared
mvi a,inte ;rst0 and rst7 bits on
out intc
xra a
out icon ;interrupt control
;
; set default buffer address to 80h
lxi b,buff
call setdma
;
; reset monitor entry points
mvi a,jmp
sta 0
lxi h,wboote
shld 1 ;jmp wboot at location 00
sta 5
lxi h,bdos
shld 6 ;jmp bdos at location 5
if not test
sta 7*8 ;jmp to mon80 (may have been changed by ddt)
lxi h,mon80
shld 7*8+1
endif
; leave iobyte set
; previously selected disk was b, send parameter to cpm
lda cdisk ;last logged disk number
mov c,a ;send to ccp to log it in
ei
jmp cpmb
;
; error condition occurred, print message and retry
booterr:
pop b ;recall counts
dcr c
jz booter0
; try again
push b
jmp wboot0
;
booter0:
; otherwise too many retries
lxi h,bootmsg
call prmsg
jmp rmon80 ;mds hardware monitor
;
bootmsg:
db '?boot',0
;
;
const: ;console status to reg-a
; (exactly the same as mds call)
jmp csts
;
conin: ;console character to reg-a
call ci
ani 7fh ;remove parity bit
ret
;
conout: ;console character from c to console out
jmp co
;
list: ;list device out
; (exactly the same as mds call)
jmp lo
;
listst:
;return list status
xra a
ret ;always not ready
;
punch: ;punch device out
; (exactly the same as mds call)
jmp po
;
reader: ;reader character in to reg-a
; (exactly the same as mds call)
jmp ri
;
home: ;move to home position
; treat as track 00 seek
mvi c,0
jmp settrk
;
seldsk: ;select disk given by register c
lxi h,0000h ;return 0000 if error
mov a,c
cpi ndisks ;too large?
rnc ;leave HL = 0000
;
ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3
sta dbank ;to select drive bank
mov a,c ;00, 01, 10, 11
ani 1b ;mds has 0,1 at 78, 2,3 at 88
ora a ;result 00?
jz setdrive
mvi a,00110000b ;selects drive 1 in bank
setdrive:
mov b,a ;save the function
lxi h,iof ;io function
mov a,m
ani 11001111b ;mask out disk number
ora b ;mask in new disk number
mov m,a ;save it in iopb
mov l,c
mvi h,0 ;HL=disk number
dad h ;*2
dad h ;*4
dad h ;*8
dad h ;*16
lxi d,dpbase
dad d ;HL=disk header table address
ret
;
;
settrk: ;set track address given by c
lxi h,iot
mov m,c
ret
;
setsec: ;set sector number given by c
lxi h,ios
mov m,c
ret
sectran:
;translate sector bc using table at de
mvi b,0 ;double precision sector number in BC
xchg ;translate table address to HL
dad b ;translate(sector) address
mov a,m ;translated sector number to A
sta ios
mov l,a ;return sector number in L
ret
;
setdma: ;set dma address given by regs b,c
mov l,c
mov h,b
shld iod
ret
;
read: ;read next disk record (assuming disk/trk/sec/dma set)
mvi c,readf ;set to read function
call setfunc
call waitio ;perform read function
ret ;may have error set in reg-a
;
;
write: ;disk write function
mvi c,writf
call setfunc ;set to write function
call waitio
ret ;may have error set
;
;
; utility subroutines
prmsg: ;print message at h,l to 0
mov a,m
ora a ;zero?
rz
; more to print
push h
mov c,a
call conout
pop h
inx h
jmp prmsg
;
setfunc:
; set function for next i/o (command in reg-c)
lxi h,iof ;io function address
mov a,m ;get it to accumulator for masking
ani 11111000b ;remove previous command
ora c ;set to new command
mov m,a ;replaced in iopb
; the mds-800 controller requires disk bank bit in sector byte
; mask the bit from the current i/o function
ani 00100000b ;mask the disk select bit
lxi h,ios ;address the sector select byte
ora m ;select proper disk bank
mov m,a ;set disk select bit on/off
ret
;
waitio:
mvi c,retry ;max retries before perm error
rewait:
; start the i/o function and wait for completion
call intype ;in rtype
call inbyte ;clears the controller
;
lda dbank ;set bank flags
ora a ;zero if drive 0,1 and nz if 2,3
mvi a,iopb and 0ffh ;low address for iopb
mvi b,iopb shr 8 ;high address for iopb
jnz iodr1 ;drive bank 1?
out ilow ;low address to controller
mov a,b
out ihigh ;high address
jmp wait0 ;to wait for complete
;
iodr1: ;drive bank 1
out ilow+10h ;88 for drive bank 10
mov a,b
out ihigh+10h
;
wait0: call instat ;wait for completion
ani iordy ;ready?
jz wait0
;
; check io completion ok
call intype ;must be io complete (00) unlinked
; 00 unlinked i/o complete, 01 linked i/o complete (not used)
; 10 disk status changed 11 (not used)
cpi 10b ;ready status change?
jz wready
;
; must be 00 in the accumulator
ora a
jnz werror ;some other condition, retry
;
; check i/o error bits
call inbyte
ral
jc wready ;unit not ready
rar
ani 11111110b ;any other errors? (deleted data ok)
jnz werror
;
; read or write is ok, accumulator contains zero
ret
;
wready: ;not ready, treat as error for now
call inbyte ;clear result byte
jmp trycount
;
werror: ;return hardware malfunction (crc, track, seek, etc.)
; the mds controller has returned a bit in each position
; of the accumulator, corresponding to the conditions:
; 0 - deleted data (accepted as ok above)
; 1 - crc error
; 2 - seek error
; 3 - address error (hardware malfunction)
; 4 - data over/under flow (hardware malfunction)
; 5 - write protect (treated as not ready)
; 6 - write error (hardware malfunction)
; 7 - not ready
; (accumulator bits are numbered 7 6 5 4 3 2 1 0)
;
; it may be useful to filter out the various conditions,
; but we will get a permanent error message if it is not
; recoverable. in any case, the not ready condition is
; treated as a separate condition for later improvement
trycount:
; register c contains retry count, decrement 'til zero
dcr c
jnz rewait ;for another try
;
; cannot recover from error
mvi a,1 ;error code
ret
;
; intype, inbyte, instat read drive bank 00 or 10
intype: lda dbank
ora a
jnz intyp1 ;skip to bank 10
in rtype
ret
intyp1: in rtype+10h ;78 for 0,1 88 for 2,3
ret
;
inbyte: lda dbank
ora a
jnz inbyt1
in rbyte
ret
inbyt1: in rbyte+10h
ret
;
instat: lda dbank
ora a
jnz insta1
in dstat
ret
insta1: in dstat+10h
ret
;
;
;
; data areas (must be in ram)
dbank: db 0 ;disk bank 00 if drive 0,1
; 10 if drive 2,3
iopb: ;io parameter block
db 80h ;normal i/o operation
iof: db readf ;io function, initial read
ion: db 1 ;number of sectors to read
iot: db offset ;track number
ios: db 1 ;sector number
iod: dw buff ;io address
;
;
; define ram areas for bdos operation
endef
end


View File

@@ -0,0 +1,15 @@
; PIP INTERFACE TO BDOS (CAN BE USED FOR OTHER TRANSIENTS)
PUBLIC BOOT,IOBYTE,BDISK,BDOS,MON1,MON2,MON3
PUBLIC MAXB,FCB,BUFF
BOOT EQU 0000H ;WARM START
IOBYTE EQU 0003H ;IO BYTE
BDISK EQU 0004H ;BOOT DISK #
BDOS EQU 0005H ;BDOS ENTRY
MON1 EQU 0005H ;BDOS ENTRY
MON2 EQU 0005H ;BDOS ENTRY
MON3 EQU 0005H ;BDOS ENTRY
MAXB EQU 0006H ;MAX MEM BASE
FCB EQU 005CH ;DEFAULT FCB
BUFF EQU 0080H ;DEFAULT BUFFER
END


View File

@@ -0,0 +1,220 @@
0000 PIP#
0000 PIPMOD#
07E6 14 07EA 16 07F2 17 07F3 18 07F3 19
07FB 20 07FF 21 07FF 22 07FF 23 0804 24
0809 25 080A 42 080A 43 0813 44 0813 45
0813 46 081C 47 081C 49 0820 51 082D 52
082E 53 082E 54 0833 55 0838 56 0839 57
083F 59 0842 60 084B 61 084C 63 084C 64
0855 65 0855 66 0855 67 085D 68 085E 69
0862 71 086D 72 086E 73 0874 75 0880 76
0881 77 0887 79 0893 80 0894 81 089A 83
08A6 84 08A7 85 08A7 86 08B2 87 08B3 88
08B9 90 08C2 91 08C3 92 08C9 94 08D3 95
08D3 96 08D9 98 08E3 99 08E3 100 08E9 102
08F5 103 08F6 104 08FC 106 0905 107 0906 109
090C 111 0915 112 0916 113 0916 114 091F 115
091F 116 0923 118 092E 119 092F 120 092F 121
0936 122 0937 123 0937 124 093E 125 093F 126
0945 128 094F 129 094F 130 0955 132 095F 133
095F 134 0965 136 096E 137 096F 140 096F 141
0974 142 097C 143 097D 145 097D 146 0986 147
0986 149 098C 151 0995 152 0996 153 0996 155
099A 156 099E 157 09A7 158 09AA 159 09AF 160
09AF 162 09B5 164 09B8 165 09C0 166 09C5 167
09CA 168 09DA 169 09E4 170 09F1 171 09F8 172
09FD 173 0A03 174 0A0B 175 0A11 176 0A14 177
0A17 178 0A18 179 0A27 182 0A33 183 0A3D 184
0A44 185 0A4B 186 0A4E 187 0A4F 188 0A4F 190
0A55 191 0A5C 192 0A5F 193 0A6E 194 0A7B 195
0A89 197 0A91 198 0A97 199 0A9D 200 0AA4 201
0AAA 202 0AAD 203 0AB7 204 0ABE 205 0AC4 206
0AC7 207 0AC8 208 0AC8 212 0ADA 213 0ADB 214
0AE1 215 0AE8 216 0AEE 217 0AFD 218 0B07 219
0B0F 220 0B1A 221 0B20 222 0B2A 223 0B31 224
0B38 226 0B3E 227 0B44 228 0B53 229 0B61 230
0B68 231 0B6D 232 0B7B 233 0B9B 234 0B9F 235
0BA2 236 0BAC 237 0BB3 238 0BB9 239 0BC0 240
0BC9 241 0BC9 242 0BCF 243 0BD0 244 0BD4 246
0BDC 248 0BE0 249 0BE9 251 0BF3 252 0BF4 253
0BF4 254 0BF4 255 0BFA 256 0C0A 257 0C0A 258
0C16 259 0C19 260 0C24 261 0C2B 262 0C2E 263
0C31 264 0C34 265 0C37 266 0C3A 267 0C3D 268
0C46 269 0C50 270 0C50 271 0C55 272 0C58 273
0C5B 274 0C5B 275 0C60 276 0C63 277 0C66 278
0C66 279 0C6B 280 0C6E 281 0C71 282 0C7F 283
0C7F 284 0C84 285 0C87 286 0C8A 287 0C8A 288
0C8F 289 0C92 290 0C95 291 0C95 292 0C9A 293
0C9D 294 0CA0 295 0CAE 296 0CAE 297 0CB3 298
0CB6 299 0CB9 300 0CB9 301 0CBE 302 0CC1 303
0CC4 304 0CC4 305 0CC9 306 0CCC 307 0CCF 308
0CDD 309 0D05 310 0D0B 311 0D0C 312 0D10 314
0D18 315 0D22 316 0D2A 317 0D34 319 0D3A 320
0D44 321 0D4E 322 0D51 323 0D59 324 0D62 325
0D66 326 0D6B 327 0D6E 328 0D6E 329 0D76 330
0D7B 331 0D7C 332 0D80 334 0D91 335 0D99 336
0DA2 337 0DA3 338 0DA7 340 0DB4 341 0DBD 342
0DBE 343 0DBE 345 0DC3 346 0DCE 347 0DD6 348
0DDF 349 0DE8 350 0DEF 351 0DF6 352 0DFD 353
0E05 355 0E0A 356 0E0F 357 0E12 358 0E17 359
0E18 360 0E18 363 0E21 364 0E2A 365 0E2D 366
0E3C 367 0E44 368 0E45 369 0E49 371 0E50 373
0E58 374 0E59 375 0E59 376 0E60 378 0E68 380
0E73 382 0E7B 383 0E80 384 0E8E 386 0E93 387
0E98 388 0E98 389 0E98 390 0EA1 391 0EA4 392
0EA9 393 0EA9 394 0EA9 395 0EB0 397 0EC8 399
0ECB 400 0ECC 401 0ECC 402 0ECC 403 0ED4 404
0ED9 405 0EE0 406 0EE8 407 0EED 408 0EEE 409
0EF2 411 0F09 412 0F11 413 0F15 414 0F15 415
0F19 417 0F30 418 0F38 419 0F3C 420 0F3C 421
0F3C 423 0F47 425 0F59 427 0F61 428 0F64 429
0F6A 430 0F6D 431 0F6D 432 0F6D 433 0F72 434
0F78 435 0F88 436 0F88 437 0F94 438 0F97 439
0FA3 440 0FAA 441 0FAD 442 0FB6 443 0FBF 444
0FBF 445 0FC4 446 0FC7 447 0FCA 448 0FCA 449
0FCF 450 0FD2 451 0FD5 452 0FD5 453 0FDA 454
0FDD 455 0FE0 456 0FF0 457 0FF3 458 0FF6 459
0FF9 460 0FFC 461 0FFF 462 1002 463 1005 464
1008 465 1008 466 100E 467 1011 468 1011 469
1016 470 1019 471 101C 472 101C 473 1021 474
1024 475 1027 476 1027 477 102C 478 102F 479
1032 480 1032 481 1037 482 1042 483 1045 484
106D 485 1073 486 107A 488 1080 489 1085 490
108C 491 1092 492 1092 493 1099 495 10A0 496
10B2 497 10BD 498 10C4 500 10CB 502 10D3 503
10D6 504 10DC 505 10DC 506 10DC 507 10DC 508
10E3 509 10EB 510 10F2 511 10FA 512 1101 513
1109 514 110D 515 110D 516 11AD 518 11B1 520
11C9 522 11D6 523 11D9 524 11D9 525 11E3 526
11EA 527 11EF 528 11F2 529 110D 530 1116 532
1122 533 1125 534 1128 535 1128 536 1128 537
1131 539 1135 540 1141 541 1145 542 1146 543
1146 544 1151 545 1154 546 115D 548 1168 550
116E 551 1173 552 117A 553 117A 554 117D 555
1186 557 1191 559 1196 560 119B 561 119E 562
119E 563 11A2 564 11A5 565 11A9 566 11AC 567
11F2 569 11F2 570 1200 571 1203 572 1211 573
1211 574 1211 575 121C 576 121F 577 1220 578
1438 581 143C 584 144A 585 145A 586 145D 587
1464 588 1467 589 1467 590 1467 591 1479 592
1481 593 1486 594 1487 595 148B 597 1490 598
149A 599 149D 600 14A0 601 14A1 602 14A5 604
14B1 605 14B1 606 14B1 608 14B6 609 14BC 610
14C2 611 14DA 612 14E9 614 14F1 615 14FA 616
1500 617 1503 619 151B 621 1522 622 153D 623
1540 624 1546 625 1549 626 155B 627 1563 628
1575 629 158A 630 158D 631 159A 632 15A2 634
15AB 635 15B1 636 15B7 637 15B7 638 15B7 639
15BA 640 15C0 641 15C1 642 15C1 643 15C9 644
15CE 645 1226 646 122B 647 1230 648 1233 649
1238 650 1240 651 1248 652 124D 653 1250 654
1253 655 1256 656 125C 657 1267 659 126A 660
126F 661 1270 662 1270 663 1275 664 1283 665
128E 666 1295 667 129A 668 12A5 669 12A5 670
12AA 671 12B5 672 12BD 673 12BE 674 12C6 675
12CE 676 12D1 677 12D7 678 12DA 679 12E2 681
12EA 682 12EB 683 12F3 685 1305 686 1306 687
1309 688 1314 690 131C 691 131F 692 1323 693
1328 694 1329 695 1329 696 132C 697 1334 698
1335 701 133A 702 1346 703 134B 704 137B 705
137E 706 1386 708 138B 709 1393 710 1396 711
139A 712 13A0 713 13A1 714 13A1 715 13A9 716
13B0 717 13B1 718 13B1 719 13B9 720 13BC 721
13BF 723 13C7 724 13C8 725 13CD 726 13D5 727
13E3 728 13EB 729 13EC 730 13F4 731 13FC 732
13FF 733 1402 734 140A 735 140D 736 1411 737
1416 738 141E 739 1425 740 1433 741 1434 742
1434 743 1437 744 15CF 745 15CF 747 15DD 748
15E2 749 15E9 750 15EA 752 15F0 754 15FC 755
15FD 756 1607 758 1610 759 1623 760 1626 761
162D 762 1634 763 1637 764 163A 765 163A 766
163A 767 1640 768 1647 769 1653 770 165C 771
165C 772 1713 775 1719 777 1720 779 1725 780
172D 781 172D 782 172E 783 172E 784 1735 786
173A 787 173D 788 173D 789 173E 790 173E 792
1745 794 1750 795 1755 796 1758 797 1765 798
1771 799 1777 800 177B 801 177B 802 177E 803
177E 805 177E 807 178D 808 1793 809 179F 810
17A5 811 17AD 812 17AD 813 17AD 814 17BC 815
17BC 816 17BC 817 17C5 818 17C5 819 17C5 820
17DB 821 165C 822 1661 823 1666 824 1671 825
1676 826 167E 828 1684 829 168C 830 168F 831
1694 832 1694 833 1697 834 169A 835 169F 836
16AA 838 16B5 839 16B8 840 16BB 841 16C2 842
16C5 843 16C8 844 16C8 845 16CE 846 16D4 847
16E4 848 16E8 849 16EE 850 16F1 851 16FD 852
1703 853 1706 854 170D 855 1710 856 1713 857
17DB 858 17DB 860 17DB 861 17E8 862 17F8 863
1807 864 1816 865 181D 866 1822 867 1827 868
182F 869 1830 870 1833 871 1836 872 1841 873
1847 874 184D 875 1850 876 1858 877 1859 878
185C 879 185D 880 185D 881 1863 882 1864 883
1864 884 186B 885 1877 886 1883 887 188B 888
1893 889 1899 890 189F 891 18A5 892 18AD 893
18B3 894 18BE 895 18BF 896 18BF 897 18C5 898
18C8 899 18CF 900 18D5 901 18D8 902 18E8 903
18ED 904 18F5 905 18FB 906 1900 907 190C 908
1912 909 1913 910 1913 911 191C 912 1922 913
192B 914 1931 915 1932 916 1936 918 193D 919
1946 920 194B 921 1956 922 195A 923 195F 924
1962 925 1965 926 1968 927 196F 928 1975 929
197D 930 1983 931 1989 932 198F 933 1997 935
199F 937 19A6 939 19AC 940 19B8 942 19BE 943
19C1 944 19C7 945 19CD 946 19CE 947 19CE 948
19D1 949 19D1 950 19D9 951 19DF 952 19DF 953
19E5 954 19E5 955 19F1 956 19F7 957 19FD 958
19FE 959 19FE 960 1A11 961 1A12 962 1A12 963
1A18 964 1A24 965 1A2D 966 1A38 967 1A3B 968
1A3C 969 1A3C 970 1A52 971 1A64 972 1A67 973
1A68 974 1A68 976 1A7B 977 1A7E 978 1A89 979
1A8F 980 1A96 981 1A9D 982 1AA0 983 1AA7 985
1AAA 986 1AAD 987 1AAD 988 1AAE 989 1B42 991
1B42 992 1B50 993 1AAE 994 1AB1 995 1AB7 996
1ABA 997 1ABD 998 1AC2 999 1ACE 1000 1ADD 1002
1AF5 1003 1AFA 1004 1AFA 1005 1B01 1006 1B08 1008
1B0B 1009 1B12 1010 1B15 1011 1B1C 1012 1B25 1013
1B2B 1014 1B2E 1015 1B31 1016 1B34 1017 1B37 1018
1B3A 1019 1B41 1020 1B50 1021 1C0F 1023 1C0F 1025
1C12 1026 1C20 1027 1C32 1029 1C3A 1030 1C3F 1031
1C46 1032 1C46 1033 1C4D 1034 1B50 1035 1B5A 1036
1B5A 1037 1B5D 1038 1B64 1039 1B6A 1040 1B70 1041
1B75 1042 1B8D 1043 1B91 1044 1B94 1045 1B97 1046
1B9A 1047 1BA2 1049 1BAA 1050 1BB0 1051 1BB3 1052
1BB4 1053 1BB4 1054 1BBB 1055 1BD5 1056 1BE1 1057
1BE6 1058 1BF3 1060 1BFF 1061 1C05 1062 1C08 1063
1C0B 1064 1C0B 1065 1C0E 1066 1C4E 1067 1C4E 1068
1C57 1069 1C61 1070 1C67 1071 1C68 1072 1C68 1073
1C6F 1074 1C72 1075 1C7B 1076 1C85 1077 1C8B 1078
1C8C 1079 1C8C 1080 1C96 1081 1C97 1082 1CA1 1083
1CA4 1084 1CA5 1085 1CA5 1086 1CA8 1087 1CB0 1088
1CB3 1089 1CB4 1090 1CBA 1092 1CBD 1093 1CC0 1094
1CCE 1095 1CD1 1096 1CD2 1097 1CD2 1098 1CD8 1099
1CF0 1100 1CF3 1101 1CF9 1102 04CE 1103 04DD 1104
04E8 1105 04F4 1107 04FA 1108 04FD 1109 04FD 1110
0503 1111 050E 1112 0517 1113 051A 1114 051A 1115
0525 1116 052A 1117 0532 1118 0535 1119 053C 1121
0541 1122 0544 1123 0547 1124 0547 1125 054C 1126
0554 1128 055B 1129 055E 1130 055E 1131 0570 1132
0576 1133 057E 1134 0581 1135 0589 1137 0590 1138
0593 1139 0599 1140 05A1 1141 05A4 1142 05AB 1144
05B1 1145 05B4 1146 05B7 1148 05BD 1149 05C0 1150
05C0 1151 05C3 1152 05C3 1153 05D3 1154 05D6 1155
05D9 1156 05DC 1157 05E2 1158 05EA 1160 05ED 1161
05F0 1162 05FC 1163 05FF 1164 0602 1165 0605 1166
0605 1167 060D 1169 0610 1170 0618 1171 061B 1172
061E 1173 0621 1174 0624 1175 0624 1176 0629 1177
062F 1178 063D 1179 0643 1180 0648 1181 0650 1183
0653 1184 0656 1185 065B 1186 065E 1187 0675 1188
067B 1189 0687 1190 068A 1191 0690 1192 06A8 1193
06AE 1194 06B3 1195 06BA 1196 06C0 1197 06C6 1198
06CB 1199 06DF 1201 06E2 1202 06E5 1203 06EA 1204
06ED 1205 070D 1206 0713 1207 071B 1208 0722 1209
072A 1210 0730 1211 0738 1212 0740 1214 074E 1215
0753 1216 075B 1218 0760 1219 0768 1220 076D 1221
0775 1222 077A 1223 077A 1224 077D 1225 077D 1226
0780 1227 0786 1228 07AA 1229 07B0 1230 07BB 1231
07BE 1232 07C6 1234 07CB 1235 07CE 1236 07CE 1237
07D6 1238 07DB 1239 07E1 1240 07E4 1241
0000 MODULE#


File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
; pip patch for cp/m 2.0 operation 10/4/79
;
; this patch fixes two errors which occur when
; pip operates under the cp/m 2.0 release:
; (1) the operation pip x=x,x previously
; resulted in a duplicate file when the
; final file size exceeded 16k bytes,
; (2) the sequence of operations
; user 5
; pip b:=*.*
; resulted in a BDOS disk select error
;
;
; pl/m source level changes:
; 0931.1 dest(freel) = 0;
; 1055.1 dest(0) = 0;
; 1057.0 (deleted)
;
; assembly language field patch:
;
org 01f0h ;patch area in pip
dest equ 1dd8h ;location of "dest"
freel equ 12 ;constant offset
open equ 086eh ;local open subroutine
;
p1: ;patch #1 for line 931.1
lxi h,freel
dad b ;hl=.dest(freel)
mvi m,0 ;dest(freel)=0
jmp open ;open file
;
p2: ;patch #2 for line 1055.1
lxi b,dest
xra a ;zero to accum
stax b ;dest(0)=0
ret
;
; code overlays
org 198ch ;line 931.1
call p1 ;patch #1
;
org 1bd5h ;line 1055.1
call p2 ;patch #2
end


View File

@@ -0,0 +1 @@
CP/M 2.0 sources in PL/M and Assembly language. Includes BIOS for the MDS-800.

View File

@@ -0,0 +1,117 @@
0000 STAT#
0000 STAT#
0433 16 0490 20 0494 22 049F 23 04A0 24
04A0 25 04A5 26 04AA 27 04AB 28 04AB 29
04B0 30 04B1 31 04B7 34 04C0 35 04C7 36
04CE 37 04D1 38 04D2 39 04D8 41 04DB 42
04E3 43 04E4 44 04E4 45 04ED 46 04ED 48
04ED 49 04F6 50 04F6 51 04FA 53 0505 54
0506 55 050C 57 0518 58 0519 59 051F 61
052B 62 052C 63 052C 64 0537 65 0538 66
0538 67 0541 68 0541 69 0547 71 0550 72
0551 73 0551 74 055A 75 055A 76 055A 77
0563 78 0563 79 0563 80 056B 81 056C 82
056C 83 0575 84 0575 85 0575 86 057D 87
057E 88 057E 89 0589 90 058A 91 058A 92
0593 93 0593 94 0597 96 05A2 97 05A3 98
05A9 100 05B2 101 05B3 105 05B3 106 05B6 107
05CB 108 05CC 109 05D0 111 05D7 112 05DA 113
05DB 114 05E1 116 05FE 117 05FE 119 0604 123
0612 124 062C 125 062F 126 0636 127 0639 128
0639 129 06EB 131 06EF 133 06FC 134 0700 135
0639 136 0648 137 064C 138 064F 139 0654 140
065C 141 0670 142 067A 143 067F 144 06D1 145
06DF 146 06E3 147 06E6 148 06EA 149 0701 150
070B 152 0710 153 071C 154 072A 155 0734 156
0740 157 075B 158 0761 160 0766 161 076F 162
076F 163 0772 164 0773 165 077D 169 078C 170
0799 171 07A8 172 07B3 173 07B6 174 07B7 175
07BB 178 07C4 179 07C8 180 07DF 181 07E6 182
07F1 183 07F8 184 0801 185 080E 186 0812 187
0812 188 0812 189 0818 190 0819 191 0819 195
081F 196 082B 197 0831 198 083F 199 084A 200
0851 201 0857 202 085D 203 0865 204 087F 205
088D 206 0890 207 0893 208 08A1 209 08AF 210
08BB 211 08C2 212 08C3 213 09C0 215 09C6 217
09C9 218 09D4 219 09D9 220 09DC 221 08C3 222
08C9 223 08D2 224 08D7 225 08DD 226 08EC 227
091C 228 0925 229 092D 230 0933 231 093D 232
0943 233 0951 234 0957 235 0969 236 096F 237
0986 238 098C 239 0994 240 099A 241 09A3 242
09A9 243 09B6 244 09BC 245 09BF 246 09DD 247
09DD 249 09E3 250 09E8 251 09F4 252 09FC 254
0A03 255 0A06 256 0A06 257 0A13 258 0A15 259
0A18 260 0A19 261 0A21 264 0A2B 265 0A37 266
0A3C 267 0A4A 268 0A64 269 0A69 270 0A6D 271
0A72 272 0A79 273 0A7D 274 0A84 275 0A87 276
0A87 278 0C69 281 0C6F 283 0C78 284 0C7F 285
0C86 286 0C89 287 0C8E 288 0A87 289 0A8C 290
0A8C 291 0A8F 292 0A9F 293 0AA8 294 0AAC 295
0AB4 297 0ABA 298 0ABF 299 0ACB 300 0ADC 301
0AE2 302 0AF9 303 0B01 304 0B0B 305 0B0E 306
0B15 307 0B18 308 0B20 310 0B26 311 0B2C 312
0B32 313 0B38 314 0B3E 315 0B4C 316 0B4F 317
0B60 318 0B66 319 0B85 320 0B8A 321 0BA1 322
0BA4 323 0BAB 324 0BAE 325 0BB6 327 0BB9 328
0BBC 329 0BBF 330 0BC7 331 0BCD 333 0BDB 334
0BDE 335 0BE6 337 0BEC 338 0BEF 339 0BEF 340
0BF2 341 0C0B 343 0C11 344 0C14 345 0C14 346
0C19 347 0C25 348 0C2D 349 0C35 350 0C38 351
0C46 352 0C46 353 0C49 354 0C51 355 0C54 356
0C5C 358 0C62 359 0C65 360 0C65 361 0C68 362
0C8F 363 0C95 365 0C9B 366 0CA0 367 0CAC 368
0CBA 369 0CC4 370 0CD0 371 0CEB 373 0CF0 374
0CF9 375 0CF9 376 0CFC 377 0D01 378 0D04 379
0D05 380 0D05 381 0D0B 382 0D14 383 0D1A 384
0D1B 385 0D1B 386 0D25 387 0D26 388 0D26 389
0D2C 390 0D2F 391 0D32 392 0D33 393 0D33 396
0D39 397 0D3F 398 0D44 399 0D50 400 0D58 402
0D5F 403 0D62 404 0D68 405 0D70 406 0D78 407
0D7D 408 0D83 409 0D86 410 0D86 411 0D93 412
0DA0 413 0DA2 414 0DA5 415 0DA8 416 0DA9 417
0DA9 418 0DB1 419 0DB9 420 0DBA 421 135D 425
135D 426 136B 427 136C 430 136C 432 1374 433
1377 434 1387 435 139F 436 13A7 437 13B7 438
13BD 439 13C0 440 13C0 441 13C0 443 13CE 444
13E3 446 13EB 447 13F0 448 13F7 449 13F7 450
1401 451 0DBA 452 0DBD 453 0DC0 454 0DC5 455
0DCA 456 0DD1 458 0DD9 459 0DDA 460 0DE1 461
0DE4 462 0DEC 464 0DEF 465 0DF0 466 0DF0 467
0DFA 468 0E04 469 0E0A 470 0E12 471 0E24 472
0E29 473 0E2F 474 0E45 475 0E48 476 0E56 477
0E71 478 0E79 479 0E84 480 0E8E 481 0E95 482
0E98 483 0E9F 484 0EA9 486 0EB3 487 0EB6 488
0ED8 490 0EDE 491 0EE4 492 0EEA 493 0EED 494
0EED 495 0EFE 496 0F0C 497 0F24 498 0F2E 499
0F60 500 0F60 501 0F79 502 0FB9 503 0FBE 504
0FCD 505 0FD2 506 0FF1 507 0FFF 508 1007 509
101C 510 1024 511 103A 512 103D 513 1040 514
1043 515 104F 516 1058 517 1060 519 106B 521
1071 522 107C 523 1082 524 1097 525 10A6 526
10A9 527 10AF 528 10BE 529 10C1 530 10CF 531
10F3 533 1102 534 111B 535 112C 536 1133 537
1138 538 113B 539 1145 540 114A 541 1154 542
1161 543 1164 544 1164 545 116B 546 1174 547
1177 548 117D 549 1183 550 118F 551 119E 552
11A1 553 11A4 554 11B8 555 11BD 556 11C4 558
11CA 559 11D2 560 11DB 561 11E6 562 11E9 563
11E9 564 11FA 565 11FD 566 120E 567 1213 568
1216 569 1227 570 122A 571 122F 572 1234 573
1241 574 1249 575 124E 576 1251 577 125A 578
125F 579 126F 580 1274 581 1277 582 127E 583
1283 584 128A 585 128D 586 1290 587 1293 588
1293 589 1299 590 12A5 591 12AC 593 12AF 594
12B0 595 12B0 596 12B6 597 12B9 598 12BC 599
12BF 600 12CF 601 12E1 602 12F3 603 1305 604
1317 605 131F 606 1333 607 1338 608 133B 609
1341 610 1352 611 1359 612 135C 613 135C 614
1402 615 1402 616 1405 617 1408 618 1410 620
1413 621 141D 623 1420 624 1423 625 1426 626
142C 627 142F 629 1432 630 143F 631 1445 632
1448 633 1448 634 0433 635 043A 636 043E 637
0446 638 044F 640 0454 641 046C 642 0472 644
047A 645 0480 647 0488 648 048B 649 048B 650
048B 651 048B 652 048F 653
0000 MODULE#


View File

@@ -0,0 +1,894 @@
stat:
do;
declare
cpmversion literally '20h'; /* requires 2.0 cp/m */
/* c p / m s t a t u s c o m m a n d (s t a t) */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/*
copyright(c) 1975, 1976, 1977, 1978, 1979
digital research
box 579
pacific grove, ca
93950
*/
/* modified 10/30/78 to fix the space computation */
/* modified 01/28/79 to remove despool dependencies */
/* modified 07/26/79 to operate under cp/m 2.0 */
declare jump byte data(0c3h),
jadr address data (.status);
/* jump to status */
/* function call 32 returns the address of the disk parameter
block for the currently selected disk, which consists of:
scptrk (2 by) number of sectors per track
blkshf (1 by) log2 of blocksize (2**blkshf=blksize)
blkmsk (1 by) 2**blkshf-1
extmsk (1 by) logical/physical extents
maxall (2 by) max alloc number
dirmax (2 by) size of directory-1
dirblk (2 by) reservation bits for directory
chksiz (2 by) size of checksum vector
offset (2 by) offset for operating system
*/
declare
/* fixed locations for cp/m */
bdosa literally '0006h', /* bdos base */
buffa literally '0080h', /* default buffer */
fcba literally '005ch', /* default file control block */
dolla literally '006dh', /* dollar sign position */
parma literally '006eh', /* parameter, if sent */
rreca literally '007dh', /* random record 7d,7e,7f */
rreco literally '007fh', /* high byte of random overflow */
ioba literally '0003h', /* iobyte address */
sectorlen literally '128', /* sector length */
memsize address at(bdosa), /* end of memory */
rrec address at(rreca), /* random record address */
rovf byte at(rreco), /* overflow on getfile */
doll byte at(dolla), /* dollar parameter */
parm byte at(parma), /* parameter */
sizeset byte, /* true if displaying size field */
dpba address, /* disk parameter block address */
dpb based dpba structure
(spt address, bls byte, bms byte, exm byte, mxa address,
dmx address, dbl address, cks address, ofs address),
scptrk literally 'dpb.spt',
blkshf literally 'dpb.bls',
blkmsk literally 'dpb.bms',
extmsk literally 'dpb.exm',
maxall literally 'dpb.mxa',
dirmax literally 'dpb.dmx',
dirblk literally 'dpb.dbl',
chksiz literally 'dpb.cks',
offset literally 'dpb.ofs';
boot: procedure external;
/* reboot */
end boot;
mon1: procedure(f,a) external;
declare f byte, a address;
end mon1;
mon2: procedure(f,a) byte external;
declare f byte, a address;
end mon2;
mon3: procedure(f,a) address external;
declare f byte, a address;
end mon3;
status: procedure;
declare copyright(*) byte data (
' Copyright (c) 1979, Digital Research');
/* dummy outer procedure 'status' will start at 100h */
/* determine status of currently selected disk */
declare alloca address,
/* alloca is the address of the disk allocation vector */
alloc based alloca (1024) byte; /* allocation vector */
declare
true literally '1',
false literally '0',
forever literally 'while true',
cr literally '13',
lf literally '10';
printchar: procedure(char);
declare char byte;
call mon1(2,char);
end printchar;
crlf: procedure;
call printchar(cr);
call printchar(lf);
end crlf;
printb: procedure;
/* print blank character */
call printchar(' ');
end printb;
printx: procedure(a);
declare a address;
declare s based a byte;
do while s <> 0;
call printchar(s);
a = a + 1;
end;
end printx;
print: procedure(a);
declare a address;
/* print the string starting at address a until the
next 0 is encountered */
call crlf;
call printx(a);
end print;
break: procedure byte;
return mon2(11,0); /* console ready */
end break;
declare dcnt byte;
version: procedure byte;
/* returns current cp/m version # */
return mon2(12,0);
end version;
select: procedure(d);
declare d byte;
call mon1(14,d);
end select;
open: procedure(fcb);
declare fcb address;
dcnt = mon2(15,fcb);
end open;
search: procedure(fcb);
declare fcb address;
dcnt = mon2(17,fcb);
end search;
searchn: procedure;
dcnt = mon2(18,0);
end searchn;
cselect: procedure byte;
/* return current disk number */
return mon2(25,0);
end cselect;
setdma: procedure(dma);
declare dma address;
call mon1(26,dma);
end setdma;
getalloca: procedure address;
/* get base address of alloc vector */
return mon3(27,0);
end getalloca;
getlogin: procedure address;
/* get the login vector */
return mon3(24,0);
end getlogin;
writeprot: procedure;
/* write protect the current disk */
call mon1(28,0);
end writeprot;
getrodisk: procedure address;
/* get the read-only disk vector */
return mon3(29,0);
end getrodisk;
setind: procedure;
/* set file indicators for current fcb */
call mon1(30,fcba);
end setind;
set$dpb: procedure;
/* set disk parameter block values */
dpba = mon3(31,0); /* base of dpb */
end set$dpb;
getuser: procedure byte;
/* return current user number */
return mon2(32,0ffh);
end getuser;
setuser: procedure(user);
declare user byte;
call mon1(32,user);
end setuser;
getfilesize: procedure(fcb);
declare fcb address;
call mon1(35,fcb);
end getfilesize;
declare oldsp address, /* sp on entry */
stack(16) address; /* this program's stack */
declare
fcbmax literally '512', /* max fcb count */
fcbs literally 'memory',/* remainder of memory */
fcb(33) byte at (fcba), /* default file control block */
buff(128) byte at (buffa), /* default buffer */
ioval byte at (ioba); /* io byte */
declare bpb address; /* bytes per block */
set$bpb: procedure;
call set$dpb; /* disk parameters set */
bpb = shl(double(1),blkshf) * sectorlen;
end set$bpb;
select$disk: procedure(d);
declare d byte;
/* select disk and set bpb */
call select(d);
call set$bpb; /* bytes per block */
end select$disk;
getalloc: procedure(i) byte;
/* return the ith bit of the alloc vector */
declare i address;
return
rol(alloc(shr(i,3)), (i and 111b) + 1);
end getalloc;
declare
accum(4) byte, /* accumulator */
ibp byte; /* input buffer pointer */
compare: procedure(a) byte;
/* compare accumulator with four bytes addressed by a */
declare a address;
declare (s based a) (4) byte;
declare i byte;
do i = 0 to 3;
if s(i) <> accum(i) then return false;
end;
return true;
end compare;
scan: procedure;
/* fill accum with next input value */
declare (i,b) byte;
setacc: procedure(b);
declare b byte;
accum(i) = b; i = i + 1;
end setacc;
/* deblank input */
do while buff(ibp) = ' '; ibp=ibp+1;
end;
/* initialize accum length */
i = 0;
do while i < 4;
if (b := buff(ibp)) > 1 then /* valid */
call setacc(b); else /* blank fill */
call setacc(' ');
if b <= 1 or b = ',' or b = ':' or
b = '*' or b = '.' or b = '>' or
b = '<' or b = '=' then buff(ibp) = 1;
else
ibp = ibp + 1;
end;
ibp = ibp + 1;
end scan;
pdecimal: procedure(v,prec);
/* print value v with precision prec (10,100,1000)
with leading zero suppression */
declare
v address, /* value to print */
prec address, /* precision */
zerosup byte, /* zero suppression flag */
d byte; /* current decimal digit */
zerosup = true;
do while prec <> 0;
d = v / prec ; /* get next digit */
v = v mod prec;/* get remainder back to v */
prec = prec / 10; /* ready for next digit */
if prec <> 0 and zerosup and d = 0 then call printb; else
do; zerosup = false; call printchar('0'+d);
end;
end;
end pdecimal;
add$block: procedure(ak,ab);
declare (ak, ab) address;
/* add one block to the kilobyte accumulator */
declare kaccum based ak address; /* kilobyte accum */
declare baccum based ab address; /* byte accum */
baccum = baccum + bpb;
do while baccum >= 1024;
baccum = baccum - 1024;
kaccum = kaccum + 1;
end;
end add$block;
count: procedure(mode) address;
declare mode byte; /* true if counting 0's */
/* count kb remaining, kaccum set upon exit */
declare
ka address, /* kb accumulator */
ba address, /* byte accumulator */
i address, /* local index */
bit byte; /* always 1 if mode = false */
ka, ba = 0;
bit = 0;
do i = 0 to maxall;
if mode then bit = getalloc(i);
if not bit then call add$block(.ka,.ba);
end;
return ka;
end count;
abortmsg: procedure;
call print(.('** Aborted **',0));
end abortmsg;
userstatus: procedure;
/* display active user numbers */
declare i byte;
declare user(32) byte;
declare ufcb(*) byte data ('????????????',0,0,0);
call print(.('Active User :',0));
call pdecimal(getuser,10);
call print(.('Active Files:',0));
do i = 0 to last(user);
user(i) = false;
end;
call setdma(.fcbs);
call search(.ufcb);
do while dcnt <> 255;
if (i := fcbs(shl(dcnt and 11b,5))) <> 0e5h then
user(i and 1fh) = true;
call searchn;
end;
do i = 0 to last(user);
if user(i) then call pdecimal(i,10);
end;
end userstatus;
drivestatus: procedure;
declare
rpb address,
rpd address;
pv: procedure(v);
declare v address;
call crlf;
call pdecimal(v,10000);
call printchar(':');
call printb;
end pv;
/* print the characteristics of the currently selected drive */
call print(.(' ',0));
call printchar(cselect+'A');
call printchar(':');
call printx(.(' Drive Characteristics',0));
rpb = shl(double(1),blkshf); /* records/block=2**blkshf */
if (rpd := (maxall+1) * rpb) = 0 and (rpb <> 0) then
call print(.('65536: ',0)); else
call pv(rpd);
call printx(.('128 Byte Record Capacity',0));
call pv(count(false));
call printx(.('Kilobyte Drive Capacity',0));
call pv(dirmax+1);
call printx(.('32 Byte Directory Entries',0));
call pv(shl(chksiz,2));
call printx(.('Checked Directory Entries',0));
call pv((extmsk+1) * 128);
call printx(.('Records/ Extent',0));
call pv(rpb);
call printx(.('Records/ Block',0));
call pv(scptrk);
call printx(.('Sectors/ Track',0));
call pv(offset);
call printx(.('Reserved Tracks',0));
call crlf;
end drivestatus;
diskstatus: procedure;
/* display disk status */
declare login address, d byte;
login = getlogin; /* login vector set */
d = 0;
do while login <> 0;
if low(login) then
do; call select$disk(d);
call drivestatus;
end;
login = shr(login,1);
d = d + 1;
end;
end diskstatus;
match: procedure(va,vl) byte;
/* return index+1 to vector at va if match */
declare va address,
v based va (16) byte,
vl byte;
declare (i,j,match,sync) byte;
j,sync = 0;
do sync = 1 to vl;
match = true;
do i = 0 to 3;
if v(j) <> accum(i) then match=false;
j = j + 1;
end;
if match then return sync;
end;
return 0; /* no match */
end match;
declare devl(*) byte data
('CON:RDR:PUN:LST:DEV:VAL:USR:DSK:');
devreq: procedure byte;
/* process device request, return true if found */
/* device tables */
declare
devr(*) byte data
(/* console */ 'TTY:CRT:BAT:UC1:',
/* reader */ 'TTY:PTR:UR1:UR2:',
/* punch */ 'TTY:PTP:UP1:UP2:',
/* listing */ 'TTY:CRT:LPT:UL1:');
declare
(i,j,iobyte,items) byte;
prname: procedure(a);
declare a address,
x based a byte;
/* print device name at a */
do while x <> ':';
call printchar(x); a=a+1;
end;
call printchar(':');
end prname;
items = 0;
do forever;
call scan;
if (i:=match(.devl,8)) = 0 then return items<>0;
items = items+1; /* found first/next item */
if i = 5 then /* device status request */
do;
iobyte = ioval; j = 0;
do i = 0 to 3;
call prname(.devl(shl(i,2)));
call printx(.(' is ',0));
call prname(.devr(shl(iobyte and 11b,2)+j));
j = j + 16; iobyte = shr(iobyte,2);
call crlf;
end;
end; else /* not dev: */
if i = 6 then /* list possible assignment */
do;
call print(.('Temp R/O Disk: d:=R/O',0));
call print(.('Set Indicator: d:filename.typ ',
'$R/O $R/W $SYS $DIR',0));
call print(.('Disk Status : DSK: d:DSK:',0));
call print(.('User Status : USR:',0));
call print(.('Iobyte Assign:',0));
do i = 0 to 3; /* each line shows one device */
call crlf;
call prname(.devl(shl(i,2)));
call printx(.(' =',0));
do j = 0 to 12 by 4;
call printchar(' ');
call prname(.devr(shl(i,4)+j));
end;
end;
end; else
if i = 7 then /* list user status values */
do; call userstatus;
return true;
end; else
if i = 8 then /* show the disk device status */
call diskstatus; else
/* scan item i-1 in device table */
do; /* find base of destination */
j = shl(i:=i-1,4);
call scan;
if accum(0) <> '=' then
do; call print(.('Bad Delimiter',0));
return true;
end;
call scan;
if (j:=match(.devr(j),4)-1) = 255 then
do; call print(.('Invalid Assignment',0));
return true;
end;
iobyte = 1111$1100b; /* construct mask */
do while (i:=i-1) <> 255;
iobyte = rol(iobyte,2);
j = shl(j,2);
end;
ioval = (ioval and iobyte) or j;
end;
/* end of current item, look for more */
call scan;
if accum(0) = ' ' then return true;
if accum(0) <> ',' then
do; call print(.('Bad Delimiter',0));
return true;
end;
end; /* of do forever */
end devreq;
pvalue: procedure(v);
declare (d,zero) byte,
(k,v) address;
k = 10000;
zero = false;
do while k <> 0;
d = low(v/k); v = v mod k;
k = k / 10;
if zero or k = 0 or d <> 0 then
do; zero = true; call printchar('0'+d);
end;
end;
call printchar('k');
call crlf;
end pvalue;
comp$alloc: procedure;
alloca = getalloca;
call printchar(cselect+'A');
call printx(.(': ',0));
end comp$alloc;
prcount: procedure;
/* print the actual byte count */
call pvalue(count(true));
end prcount;
pralloc: procedure;
/* print allocation for current disk */
call print (.('Bytes Remaining On ',0));
call comp$alloc;
call prcount;
end pralloc;
prstatus: procedure;
/* print the status of the disk system */
declare (login, rodisk) address;
declare d byte;
login = getlogin; /* login vector set */
rodisk = getrodisk; /* read only disk vector set */
d = 0;
do while login <> 0;
if low(login) then
do; call select$disk(d);
call comp$alloc;
call printx(.('R/',0));
if low(rodisk) then
call printchar('O'); else
call printchar('W');
call printx(.(', Space: ',0));
call prcount;
end;
login = shr(login,1); rodisk = shr(rodisk,1);
d = d + 1;
end;
call crlf;
end prstatus;
setdisk: procedure;
if fcb(0) <> 0 then call select$disk(fcb(0)-1);
end setdisk;
getfile: procedure;
/* process file request */
declare
fnam literally '11', fext literally '12',
fmod literally '14',
frc literally '15', fln literally '15',
fdm literally '16', fdl literally '31',
ftyp literally '9',
rofile literally '9', /* read/only file */
infile literally '10'; /* invisible file */
declare
fcbn address, /* number of fcb's collected so far */
finx(fcbmax) address, /* index vector used during sort */
fcbe(fcbmax) address, /* extent counts */
fcbb(fcbmax) address, /* byte count (mod kb) */
fcbk(fcbmax) address, /* kilobyte count */
fcbr(fcbmax) address, /* record count */
bfcba address, /* index into directory buffer */
fcbsa address, /* index into fcbs */
bfcb based bfcba (32) byte, /* template over directory */
fcbv based fcbsa (16) byte; /* template over fcbs entry */
declare
i address, /* fcb counter during collection and display */
l address, /* used during sort and display */
k address, /* " */
m address, /* " */
kb byte, /* byte counter */
lb byte, /* byte counter */
mb byte, /* byte counter */
(b,f) byte, /* counters */
matched byte; /* used during fcbs search */
multi16: procedure;
/* utility to compute fcbs address from i */
fcbsa = shl(i,4) + .fcbs;
end multi16;
declare
scase byte; /* status case # */
declare
fstatlist(*) byte data('R/O',0,'R/W',0,'SYS',0,'DIR',0);
setfilestatus: procedure byte;
/* eventually, scase set r/o=0,r/w=1,dat=2,sys=3 */
declare
fstat(*) byte data('R/O R/W SYS DIR ');
if doll = ' ' then return false;
call move(4,.parm,.accum); /* $???? */
if accum(0) = 'S' and accum(1) = ' ' then
return not (sizeset := true);
/* must be a parameter */
if (scase := match(.fstat,4)) = 0 then
call print(.('Invalid File Indicator',0));
return true;
end setfilestatus;
printfn: procedure;
declare (k, lb) byte;
/* print file name */
do k = 1 to fnam;
if (lb := fcbv(k) and 7fh) <> ' ' then
do; if k = ftyp then call printchar('.');
call printchar(lb);
end;
end;
end printfn;
call set$bpb; /* in case default disk */
call setdisk;
sizeset = false;
scase = 255;
if setfilestatus then
do; if scase = 0 then return;
scase = scase - 1;
end; else
if fcb(1) = ' ' then /* no file named */
do; call pralloc;
return;
end;
/* read the directory, collect all common file names */
fcbn,fcb(0) = 0;
fcb(fext),fcb(fmod) = '?'; /* question mark matches all */
call search(fcba); /* fill directory buffer */
collect: /* label for debug */
do while dcnt <> 255;
/* another item found, compare it for common entry */
bfcba = shl(dcnt and 11b,5)+buffa; /* dcnt mod 4 * 32 */
matched = false; i = 0;
do while not matched and i < fcbn;
/* compare current entry */
call multi16;
do kb = 1 to fnam;
if bfcb(kb) <> fcbv(kb) then kb = fnam; else
/* complete match if at end */
matched = kb = fnam;
end;
i = i + 1;
end;
checkmatched: /* label for debug */
if matched then i = i - 1; else
do; /* copy to new position in fcbs */
fcbn = (i := fcbn) + 1;
call multi16;
/* fcbsa set to next to fill */
if (fcbn > fcbmax) or (fcbsa + 16) >= memsize then
do; call print(.('** Too Many Files **',0));
i = 0; fcbn = 1;
call multi16;
end;
/* save index to element for later sort */
finx(i) = i;
do kb = 0 to fnam;
fcbv(kb) = bfcb(kb);
end;
fcbe(i),fcbb(i),fcbk(i),fcbr(i) = 0;
end;
/* entry is at, or was placed at location i in fcbs */
fcbe(i) = fcbe(i) + 1; /* extent incremented */
/* record count */
fcbr(i) = fcbr(i) + bfcb(frc)
+ (bfcb(fext) and extmsk) * 128;
/* count kilobytes */
countbytes: /* label for debug */
lb = 1;
if maxall > 255 then lb = 2; /* double precision inx */
do kb = fdm to fdl by lb;
mb = bfcb(kb);
if lb = 2 then /* double precision inx */
mb = mb or bfcb(kb+1);
if mb <> 0 then /* allocated */
call add$block(.fcbk(i),.fcbb(i));
end;
call searchn; /* to next entry in directory */
end; /* of do while dcnt <> 255 */
display: /* label for debug */
/* now display the collected data */
if fcbn = 0 then call print(.('File Not Found',0)); else
if scase = 255 then /* display collected data */
do;
/* sort the file names in ascending order */
if fcbn > 1 then /* requires at least two to sort */
do; l = 1;
do while l > 0; /* bubble sort */
l = 0;
do m = 0 to fcbn - 2;
i = finx(m+1); call multi16; bfcba = fcbsa; i = finx(m);
call multi16; /* sets fcbsa, basing fcbv */
do kb = 1 to fnam; /* compare for less or equal */
if (b:=bfcb(kb)) < (f:=fcbv(kb)) then /* switch */
do; k = finx(m); finx(m) = finx(m + 1);
finx(m + 1) = k; l = l + 1; kb = fnam;
end;
else if b > f then kb = fnam; /* stop compare */
end;
end;
end;
end;
if sizeset then
call print(.(' Size ',0)); else
call crlf;
call printx(.(' Recs Bytes Ext Acc',0));
l = 0;
do while l < fcbn;
i = finx(l); /* i is the index to next in order */
call multi16; call crlf;
/* print the file length */
call move(16,.fcbv(0),fcba);
fcb(0) = 0;
if sizeset then
do; call getfilesize(fcba);
if rovf <> 0 then call printx(.('65536',0)); else
call pdecimal(rrec,10000);
call printb;
end;
call pdecimal(fcbr(i),10000); /* rrrrr */
call printb; /* blank */
call pdecimal(fcbk(i),10000); /* bbbbbk */
call printchar('k'); call printb;
call pdecimal(fcbe(i),1000); /* eeee */
call printb;
call printchar('R');
call printchar('/');
if rol(fcbv(rofile),1) then
call printchar('O'); else
call printchar('W');
call printb;
call printchar('A'+cselect); call printchar(':');
/* print filename.typ */
if (mb:=rol(fcbv(infile),1)) then call printchar('(');
call printfn;
if mb then call printchar(')');
l = l + 1;
end;
call pralloc;
end; else
setfileatt: /* label for debug */
/* set file attributes */
do;
l = 0;
do while l < fcbn;
if break then
do; call abortmsg; return;
end;
i = l;
call multi16;
call crlf;
call printfn;
do case scase;
/* set to r/o */
fcbv(rofile) = fcbv(rofile) or 80h;
/* set to r/w */
fcbv(rofile) = fcbv(rofile) and 7fh;
/* set to sys */
fcbv(infile) = fcbv(infile) or 80h;
/* set to dir */
fcbv(infile) = fcbv(infile) and 7fh;
end;
/* place name into default fcb location */
call move(16,fcbsa,fcba);
fcb(0) = 0; /* in case matched user# > 0 */
call setind; /* indicators set */
call printx(.(' set to ',0));
call printx(.fstatlist(shl(scase,2)));
l = l + 1;
end;
end;
end getfile;
setdrivestatus: procedure;
/* handle possible drive status assignment */
call scan; /* remove drive name */
call scan; /* check for = */
if accum(0) = '=' then
do; call scan; /* get assignment */
if compare(.('R/O ')) then
do; call setdisk; /* a: ... */
call writeprot;
end; else
call print(.('Invalid Disk Assignment',0));
end;
else /* not a disk assignment */
do; call setdisk;
if match(.devl,8) = 8 then call drive$status; else
call getfile;
end;
end setdrivestatus;
/* save stack pointer and reset */
oldsp = stackptr;
stackptr = .stack(length(stack));
/* process request */
if version < cpmversion then
call print(.('Wrong CP/M Version (Requires 2.0)',0));
else
do;
/* size display if $S set in command */
ibp = 1; /* initialize buffer pointer */
if fcb(0) = 0 and fcb(1) = ' ' then /* stat only */
call prstatus; else
do;
if fcb(0) <> 0 then
call setdrivestatus; else
do;
if not devreq then /* must be file name */
call getfile;
end;
end;
end;
/* restore old stack before exit */
stackptr = oldsp;
end status;
end;


View File

@@ -0,0 +1,36 @@
0000 SUBMIT#
0000 SUB#
01DF 15 01F7 18 01FD 20 0206 21 0207 23
020D 25 0219 26 021A 27 0220 29 022C 30
022D 31 0233 33 023C 34 023D 35 0243 37
024D 38 024D 39 0253 41 025D 42 025D 43
0263 45 026F 46 0270 47 027F 50 028B 51
0295 52 029C 53 02A3 54 02A6 55 02A7 57
02AD 59 02B3 60 02B9 61 02BF 62 02C7 63
02CB 64 02CC 66 02CC 67 02D8 68 02E3 69
02EF 70 02F5 71 02FD 72 0303 73 0308 74
0309 75 0309 77 0312 79 031D 80 0320 81
0325 82 0325 83 033D 85 034B 87 0350 88
035B 90 0360 91 0362 92 0362 93 0362 94
0362 95 036C 96 0374 97 0378 98 0378 99
0378 100 0383 101 0389 102 038A 104 0481 106
0481 107 04A3 109 04A7 110 04AA 111 04AA 112
04AD 113 04AD 114 04AD 115 04BC 116 04C0 117
04C3 118 04C4 119 04C8 121 04D8 122 04DE 123
04E9 124 04F7 125 04FD 126 038A 128 0395 129
039A 130 03A1 131 03A6 132 03C1 133 03C9 135
03D1 137 03DC 138 03E6 139 03F5 140 03FE 142
0403 143 0406 144 040E 145 0412 146 0419 147
041C 148 041F 149 0422 150 0429 151 0430 152
0433 153 0433 154 0436 155 043E 157 044D 158
0456 159 045E 160 0461 161 0468 162 0468 163
046B 164 0476 165 047D 166 0480 167 04FE 168
057A 170 057A 171 0587 172 04FE 173 0504 174
0509 175 050F 176 0517 177 051D 178 0528 179
052E 180 0537 181 0542 182 054B 183 0558 184
055C 185 055F 186 0562 187 0565 188 056B 189
0573 190 0579 191 01DF 193 01E6 194 01EA 195
01ED 196 01F0 197 01F3 198 01F6 199
0000 MODULE#


View File

@@ -0,0 +1,294 @@
sub:
do;
/* modified 7/26/79 to work with cpm 2.0, module number not zero */
declare
wboot literally '0000h', /* warm start entry point */
bdos literally '0005h', /* jmp bdos */
dfcba literally '005ch', /* default fcb address */
dbuff literally '0080h'; /* default buffer address */
declare jump byte data(0c3h); /* c3 = jmp */
declare jadr address data(.submit);
/* jmp to submit is placed at the beginning of the module */
boot: procedure external;
/* system reboot */
end boot;
mon1: procedure(f,a) external;
declare f byte, a address;
/* bdos interface, no returned value */
end mon1;
mon2: procedure(f,a) byte external;
declare f byte, a address;
/* bdos interface, return byte value */
end mon2;
declare
copyright(*) byte data
(' copyright(c) 1977, digital research ');
declare
ln(5) byte initial('001 $'),
ln1 byte at(.ln(0)),
ln2 byte at(.ln(1)),
ln3 byte at(.ln(2)),
dfcb(33) byte initial(0,'$$$ SUB',0,0,0),
drec byte at(.dfcb(32)), /* current record */
buff(128) byte at(dbuff), /* default buffer */
sfcb(33) byte at(dfcba); /* default fcb */
submit: procedure;
/* t h e c p / m 's u b m i t' f u n c t i o n
copyright (c) 1976, 1977, 1978
digital research
box 579
pacific grove, ca.
93950
*/
declare lit literally 'literally',
dcl lit 'declare',
proc lit 'procedure',
addr lit 'address',
ctll lit '0ch',
lca lit '110$0001b', /* lower case a */
lcz lit '111$1010b', /* lower case z */
endfile lit '1ah'; /* cp/m end of file */
declare
true literally '1',
false literally '0',
forever literally 'while true',
cr literally '13',
lf literally '10',
what literally '63';
print: procedure(a);
declare a address;
/* print the string starting at address a until the
next dollar sign is encountered */
call mon1(9,a);
end print;
declare dcnt byte;
open: procedure(fcb);
declare fcb address;
dcnt = mon2(15,fcb);
end open;
close: procedure(fcb);
declare fcb address;
dcnt = mon2(16,fcb);
end close;
delete: procedure(fcb);
declare fcb address;
call mon1(19,fcb);
end delete;
diskread: procedure(fcb) byte;
declare fcb address;
return mon2(20,fcb);
end diskread;
diskwrite: procedure(fcb) byte;
declare fcb address;
return mon2(21,fcb);
end diskwrite;
make: procedure(fcb);
declare fcb address;
dcnt = mon2(22,fcb);
end make;
move: procedure(s,d,n);
declare (s,d) address, n byte;
declare a based s byte, b based d byte;
do while (n := n - 1) <> 255;
b = a; s = s + 1; d = d + 1;
end;
end move;
declare oldsp address; /* calling program's stack pointer */
error: procedure(a);
declare a address;
call print(.(cr,lf,'$'));
call print(.('Error On Line $'));
call print(.ln1);
call print(a);
stackptr = oldsp;
/* return to ccp */
end error;
declare sstring(128) byte, /* substitute string */
sbp byte; /* source buffer pointer (0-128) */
setup: procedure;
/* move buffer to substitute string */
call move(.buff(1),.sstring(0),127);
sstring(buff(0))=0; /* mark end of string */
call move(.('SUB'),.sfcb(9),3); /* set file type to sub */
call open(.sfcb(0));
if dcnt = 255 then
call error(.('No ''SUB'' File Present$'));
/* otherwise file is open - read subsequent data */
sbp = 128; /* causes read below */
end setup;
getsource: procedure byte;
/* read the next source character */
declare b byte;
if sbp > 127 then
do; if diskread(.sfcb(0)) <> 0 then
return endfile;
sbp = 0;
end;
if (b := buff((sbp:=sbp+1)-1)) = cr then
do; /* increment line */
if (ln3 := ln3 + 1) > '9' then
do; ln3 = '0';
if (ln2 := ln2 + 1) > '9' then
do; ln2 = '0';
ln1 = ln1 + 1;
end;
end;
end;
/* translate to upper case */
if (b-61h) < 26 then /* lower case alpha */
b = b and 5fh; /* change to upper case */
return b;
end getsource;
writebuff: procedure;
/* write the contents of the buffer to disk */
if diskwrite(.dfcb) <> 0 then /* error */
call error(.('Disk Write Error$'));
end writebuff;
declare rbuff(2048) byte, /* jcl buffer */
rbp address, /* jcl buffer pointer */
rlen byte; /* length of current command */
fillrbuff: procedure;
declare (s,ssbp) byte; /* sub string buffer pointer */
notend: procedure byte;
/* look at next character in sstring, return
true if not at the end of the string - char passed
back in 's' */
if not ((s := sstring(ssbp)) = ' ' or s = 0) then
do;
ssbp = ssbp + 1;
return true;
end;
return false;
end notend;
deblankparm: procedure;
/* clear to next non blank substitute string */
do while sstring(ssbp) = ' ';
ssbp = ssbp + 1;
end;
end deblankparm;
putrbuff: procedure(b);
declare b byte;
if (rbp := rbp + 1) > last(rbuff) then
call error(.('Command Buffer Overflow$'));
rbuff(rbp) = b;
/* len: c1 ... c125 :00:$ = 128 chars */
if (rlen := rlen + 1) > 125 then
call error(.('Command Too Long$'));
end putrbuff;
declare (reading,b) byte;
/* fill the jcl buffer */
rbuff(0),rbp = 0;
reading = true;
do while reading;
rlen = 0; /* reset command length */
do while (b:=getsource) <> endfile and b <> cr;
if b <> lf then
do; if b = '$' then /* copy substitute string */
do; if (b:=getsource) = '$' then
/* $$ replaced by $ */
call putrbuff(b); else
if (b := b - '0') > 9 then
call error(.('Parameter Error$')); else
do; /* find string 'b' in sstring */
ssbp = 0; call deblankparm; /* ready to scan sstring */
do while b <> 0; b = b - 1;
/* clear next parameter */
do while notend;
end;
call deblankparm;
end;
/* ready to copy substitute string from position ssbp */
do while notend;
call putrbuff(s);
end;
end;
end; else /* not a '$' */
if b = '^' then /* control character */
do; /* must be ^a ... ^z */
if (b:=getsource - 'a') > 25 then
call error(.('Invalid Control Character$'));
else
call putrbuff(b+1);
end; else /* not $ or ^ */
call putrbuff(b);
end;
end; /* of line or input file - compute length */
reading = b = cr;
call putrbuff(rlen); /* store length */
end;
/* entire file has been read and processed */
end fillrbuff;
makefile: procedure;
/* write resulting command file */
declare i byte;
getrbuff: procedure byte;
return rbuff(rbp := rbp - 1);
end getrbuff;
call delete(.dfcb);
drec = 0; /* zero the next record to write */
call make(.dfcb);
if dcnt = 255 then call error(.('Directory Full$'));
do while (i := getrbuff) <> 0;
/* copy i characters to buffer */
/* 00 $ at end of line gives 1.3 & 1.4 compatibility */
buff(0) = i; buff(i+1) = 00; buff(i+2) = '$';
do while i > 0;
buff(i) = getrbuff; i=i-1;
end;
/* buffer filled to $ */
call writebuff;
end;
call close(.dfcb);
if dcnt = 255 then call error(.('Cannot Close, Read/Only?$'));
end makefile;
/* enter here from the ccp with the fcb set */
declare stack(10) address; /* working stack */
oldsp = stackptr;
stackptr = .stack(length(stack));
call setup;
call fillrbuff;
call makefile;
call boot; /* reboot causes commands to be executed */
end submit;
end;


View File

@@ -0,0 +1,440 @@
TITLE 'SYSGEN - SYSTEM GENERATION PROGRAM 8/79'
; SYSTEM GENERATION PROGRAM, VERSION FOR MDS
VERS EQU 20 ;X.X
;
; COPYRIGHT (C) DIGITAL RESEARCH
; 1976, 1977, 1978, 1979
;
NSECTS EQU 26 ;NO. OF SECTORS PER TRACK
NTRKS EQU 2 ;NO. OF OPERATING SYSTEM TRACKS
NDISKS EQU 4 ;NUMBER OF DISK DRIVES
SECSIZ EQU 128 ;SIZE OF EACH SECTOR
LOG2SEC EQU 7 ;LOG 2 SECSIZ
SKEW EQU 1 ;SECTOR SKEW FACTOR
;
FCB EQU 005CH ;DEFAULT FCB LOCATION
FCBCR EQU FCB+32 ;CURRENT RECORD LOCATION
TPA EQU 0100H ;TRANSIENT PROGRAM AREA
LOADP EQU 900H ;LOAD POINT FOR SYSTEM DURING LOAD/STORE
BDOS EQU 5H ;DOS ENTRY POINT
BOOT EQU 0 ;JMP TO 'BOOT' TO REBOOT SYSTEM
CONI EQU 1 ;CONSOLE INPUT FUNCTION
CONO EQU 2 ;CONSOLE OUTPUT FUNCTION
SELF EQU 14 ;SELECT DISK
OPENF EQU 15 ;DISK OPEN FUNCTION
DREADF EQU 20 ;DISK READ FUNCTION
;
MAXTRY EQU 10 ;MAXIMUM NUMBER OF RETRIES ON EACH READ/WRITE
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
STACKSIZE EQU 16 ;SIZE OF LOCAL STACK
;
WBOOT EQU 1 ;ADDRESS OF WARM BOOT (OTHER PATCH ENTRY
; POINTS ARE COMPUTED RELATIVE TO WBOOT)
SELDSK EQU 24 ;WBOOT+24 FOR DISK SELECT
SETTRK EQU 27 ;WBOOT+27 FOR SET TRACK FUNCTION
SETSEC EQU 30 ;WBOOT+30 FOR SET SECTOR FUNCTION
SETDMA EQU 33 ;WBOOT+33 FOR SET DMA ADDRESS
READF EQU 36 ;WBOOT+36 FOR READ FUNCTION
WRITF EQU 39 ;WBOOT+39 FOR WRITE FUNCTION
;
ORG TPA ;TRANSIENT PROGRAM AREA
JMP START
DB 'COPYRIGHT (C) 1978, DIGITAL RESEARCH '
;
; TRANSLATE TABLE - SECTOR NUMBERS ARE TRANSLATED
; HERE TO DECREASE THE SYSGEN TIME FOR MISSED SECTORS
; WHEN SLOW CONTROLLERS ARE INVOLVED. TRANSLATION TAKES
; PLACE ACCORDING TO THE "SKEW" FACTOR SET ABOVE.
;
OST: DB NTRKS ;OPERATING SYSTEM TRACKS
SPT: DB NSECTS ;SECTORS PER TRACK (CAN BE PATCHED)
TRAN: ;BASE OF TRANSLATE TABLE
TRELT SET 1 ;FIRST/NEXT TRAN ELEMENT
TRBASE SET 1 ;BASE FOR WRAPAROUND
REPT NSECTS ;ONCE FOR EACH SECTOR ON A TRACK
DB TRELT ;GENERATE FIRST/NEXT SECTOR
TRELT SET TRELT+SKEW
IF TRELT GT NSECTS
TRBASE SET TRBASE+1
TRELT SET TRBASE
ENDIF
ENDM
;
; NOW LEAVE SPACE FOR EXTENSIONS TO TRANSLATE TABLE
IF NSECTS LT 64
REPT 64-NSECTS
DB 0
ENDM
;
;
;
;
; UTILITY SUBROUTINES
MULTSEC:
;MULTIPLY THE SECTOR NUMBER IN A BY THE SECTOR SIZE
MOV L,A! MVI H,0 ;SECTOR NUMBER IN HL
REPT LOG2SEC ;LOG 2 OF SECTOR SIZE
DAD H
ENDM
RET ;WITH HL = SECTOR * SECTOR SIZE
;
GETCHAR:
; READ CONSOLE CHARACTER TO REGISTER A
MVI C,CONI! CALL BDOS!
; CONVERT TO UPPER CASE BEFORE RETURN
CPI 'A' OR 20H ! RC ;RETURN IF BELOW LOWER CASE A
CPI ('Z' OR 20H) + 1
RNC ;RETURN IF ABOVE LOWER CASE Z
ANI 5FH! RET
;
PUTCHAR:
; WRITE CHARACTER FROM A TO CONSOLE
MOV E,A! MVI C,CONO! CALL BDOS! RET
;
CRLF: ;SEND CARRIAGE RETURN, LINE FEED
MVI A,CR
CALL PUTCHAR
MVI A,LF
CALL PUTCHAR
RET
;
CRMSG: ;PRINT MESSAGE ADDRESSED BY H,L TIL ZERO
;WITH LEADING CRLF
PUSH H! CALL CRLF! POP H ;DROP THRU TO OUTMSG0
OUTMSG:
MOV A,M! ORA A! RZ
; MESSAGE NOT YET COMPLETED
PUSH H! CALL PUTCHAR! POP H! INX H
JMP OUTMSG
;
SEL:
; SELECT DISK GIVEN BY REGISTER A
MOV C,A! LHLD WBOOT! LXI D,SELDSK! DAD D! PCHL
;
TRK: ;SET UP TRACK
LHLD WBOOT ;ADDRESS OF BOOT ENTRY
LXI D,SETTRK ;OFFSET FOR SETTRK ENTRY
DAD D
PCHL ;GONE TO SETTRK
;
SEC: ;SET UP SECTOR NUMBER
LHLD WBOOT
LXI D,SETSEC
DAD D
PCHL
;
DMA: ;SET DMA ADDRESS TO VALUE OF B,C
LHLD WBOOT
LXI D,SETDMA
DAD D
PCHL
;
READ: ;PERFORM READ OPERATION
LHLD WBOOT
LXI D,READF
DAD D
PCHL
;
WRITE: ;PERFORM WRITE OPERATON
LHLD WBOOT
LXI D,WRITF
DAD D
PCHL
;
DREAD: ;DISK READ FUNCTION
MVI C,DREADF
JMP BDOS
;
OPEN: ;FILE OPEN FUNCTION
MVI C,OPENF ! JMP BDOS
;
GETPUT:
; GET OR PUT CP/M (RW=0 FOR READ, 1 FOR WRITE)
; DISK IS ALREADY SELECTED
;
LXI H,LOADP ;LOAD POINT IN RAM FOR CP/M DURING SYSGEN
SHLD DMADDR
;
; CLEAR TRACK TO 00
MVI A,-1 ;START WITH TRACK EQUAL -1
STA TRACK
;
RWTRK: ;READ OR WRITE NEXT TRACK
LXI H,TRACK
INR M ;TRACK = TRACK + 1
LDA OST ;NUMBER OF OPERATING SYSTEM TRACKS
CMP M ;= TRACK NUMBER ?
JZ ENDRW ;END OF READ OR WRITE
;
; OTHERWISE NOTDONE, GO TO NEXT TRACK
MOV C,M ;TRACK NUMBER
CALL TRK ;TO SET TRACK
MVI A,-1 ;COUNTS 0, 1, 2, . . . 25
STA SECTOR ;SECTOR INCREMENTED BEFORE READ OR WRITE
;
RWSEC: ;READ OR WRITE SECTOR
LDA SPT ;SECTORS PER TRACK
LXI H,SECTOR
INR M ;TO NEXT SECTOR
CMP M ;A=26 AND M=0 1 2...25 (USUALLY)
JZ ENDTRK ;
;
; READ OR WRITE SECTOR TO OR FROM CURRENT DMA ADDR
LXI H,SECTOR
MOV E,M ;SECTOR NUMBER
MVI D,0 ;TO DE
LXI H,TRAN
MOV B,M ;TRAN(0) IN B
DAD D ;SECTOR TRANSLATED
MOV C,M ;VALUE TO C READY FOR SELECT
PUSH B ;SAVE TRAN(0),TRAN(SECTOR)
CALL SEC ;SET UP SECTOR NUMBER
POP B ;RECALL TRAN(0),TRAN(SECTOR)
MOV A,C ;TRAN(SECTOR)
SUB B ;-TRAN(0)
CALL MULTSEC ;*SECTOR SIZE
XCHG ;TO DE
LHLD DMADDR ;BASE DMA ADDRESS FOR THIS TRACK
DAD D ;+(TRAN(SECTOR)-TRAN(0))*SECSIZ
MOV B,H
MOV C,L ;TO BC FOR SEC CALL
CALL DMA ;DMA ADDRESS SET FROM B,C
; DMA ADDRESS SET, CLEAR RETRY COUNT
XRA A
STA RETRY ;SET TO ZERO RETRIES
;
TRYSEC: ;TRY TO READ OR WRITE CURRENT SECTOR
LDA RETRY
CPI MAXTRY ;TOO MANY RETRIES?
JC TRYOK
;
; PAST MAXTRIES, MESSAGE AND IGNORE
LXI H,ERRMSG
CALL OUTMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
;
; TYPED A CR, OK TO IGNORE
CALL CRLF
JMP RWSEC
;
TRYOK:
; OK TO TRY READ OR WRITE
INR A
STA RETRY ;RETRY=RETRY+1
LDA RW ;READ OR WRITE?
ORA A
JZ TRYREAD
;
; MUST BE WRITE
CALL WRITE
JMP CHKRW ;CHECK FOR ERROR RETURNS
TRYREAD:
CALL READ
CHKRW:
ORA A
JZ RWSEC ;ZERO FLAG IF R/W OK
;
; ERROR, RETRY OPERATION
JMP TRYSEC
;
; END OF TRACK
ENDTRK:
LDA SPT ;SECTORS PER TRACK
CALL MULTSEC ;*SECSIZ
XCHG ;TO DE
LHLD DMADDR ;BASE DMA FOR THIS TRACK
DAD D ;+SPT*SECSIZ
SHLD DMADDR ;READY FOR NEXT TRACK
JMP RWTRK ;FOR ANOTHER TRACK
;
ENDRW: ;END OF READ OR WRITE, RETURN TO CALLER
RET
;
;
START:
;
LXI SP,STACK ;SET LOCAL STACK POINTER
LXI H,SIGNON
CALL OUTMSG
;
; CHECK FOR DEFAULT FILE LOAD INSTEAD OF GET
;
LDA FCB+1 ;BLANK IF NO FILE
CPI ' '
JZ GETSYS ;SKIP TO GET SYSTEM MESSAGE IF BLANK
LXI D,FCB ;TRY TO OPEN IT
CALL OPEN ;
INR A ;255 BECOMES 00
JNZ RDOK ;OK TO READ IF NOT 255
;
; FILE NOT PRESENT, ERROR AND REBOOT
;
LXI H,NOFILE
CALL CRMSG
JMP REBOOT
;
; FILE PRESENT
; READ TO LOAD POINT
;
RDOK:
XRA A
STA FCBCR ;CURRENT RECORD = 0
;
; PRE-READ AREA FROM TPA TO LOADP
;
MVI C,(LOADP-TPA)/SECSIZ
; PRE-READ FILE
PRERD:
PUSH B ;SAVE COUNT
LXI D,FCB ;INPUT FILE CONTROL COUNT
CALL DREAD ;ASSUME SET TO DEFAULT BUFFER
POP B ;RESTORE COUNT
ORA A
JNZ BADRD ;CANNOT ENCOUNTER END-OF FILE
DCR C ;COUNT DOWN
JNZ PRERD ;FOR ANOTHER SECTOR
;
; SECTORS SKIPPED AT BEGINNING OF FILE
;
LXI H,LOADP
RDINP:
PUSH H
MOV B,H
MOV C,L ;READY FOR DMA
CALL DMA ;DMA ADDRESS SET
LXI D,FCB ;READY FOR READ
CALL DREAD ;
POP H ;RECALL DMA ADDRESS
ORA A ;00 IF READ OK
JNZ PUTSYS ;ASSUME EOF IF NOT.
; MORE TO READ, CONTINUE
LXI D,SECSIZ
DAD D ;HL IS NEW LOAD ADDRESS
JMP RDINP
;
BADRD: ;EOF ENCOUNTERED IN INPUT FILE
LXI H,BADFILE
CALL CRMSG
JMP REBOOT
;
;
GETSYS:
LXI H,ASKGET ;GET SYSTEM?
CALL CRMSG
CALL GETCHAR
CPI CR
JZ PUTSYS ;SKIP IF CR ONLY
;
SUI 'A' ;NORMALIZE DRIVE NUMBER
CPI NDISKS ;VALID DRIVE?
JC GETC ;SKIP TO GETC IF SO
;
; INVALID DRIVE NUMBER
CALL BADDISK
JMP GETSYS ;TO TRY AGAIN
;
GETC:
; SELECT DISK GIVEN BY REGISTER A
ADI 'A'
STA GDISK ;TO SET MESSAGE
SUI 'A'
CALL SEL ;TO SELECT THE DRIVE
; GETSYS, SET RW TO READ AND GET THE SYSTEM
CALL CRLF
LXI H,GETMSG
CALL OUTMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
CALL CRLF
;
XRA A
STA RW
CALL GETPUT
LXI H,DONE
CALL OUTMSG
;
; PUT SYSTEM
PUTSYS:
LXI H,ASKPUT
CALL CRMSG
CALL GETCHAR
CPI CR
JZ REBOOT
SUI 'A'
CPI NDISKS
JC PUTC
;
; INVALID DRIVE NAME
CALL BADDISK
JMP PUTSYS ;TO TRY AGAIN
;
PUTC:
; SET DISK FROM REGISTER C
ADI 'A'
STA PDISK ;MESSAGE SET
SUI 'A'
CALL SEL ;SELECT DEST DRIVE
; PUT SYSTEM, SET RW TO WRITE
LXI H,PUTMSG
CALL CRMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
CALL CRLF
;
LXI H,RW
MVI M,1
CALL GETPUT ;TO PUT SYSTEM BACK ON DISKETTE
LXI H,DONE
CALL OUTMSG
JMP PUTSYS ;FOR ANOTHER PUT OPERATION
;
REBOOT:
MVI A,0
CALL SEL
CALL CRLF
JMP BOOT
BADDISK:
;BAD DISK NAME
LXI H,QDISK
CALL CRMSG
RET
;
;
;
; DATA AREAS
; MESSAGES
SIGNON: DB 'SYSGEN VER '
DB VERS/10+'0','.',VERS MOD 10+'0'
DB 0
ASKGET: DB 'SOURCE DRIVE NAME (OR RETURN TO SKIP)',0
GETMSG: DB 'SOURCE ON '
GDISK: DS 1 ;FILLED IN AT GET FUNCTION
DB ', THEN TYPE RETURN',0
ASKPUT: DB 'DESTINATION DRIVE NAME (OR RETURN TO REBOOT)',0
PUTMSG: DB 'DESTINATION ON '
PDISK: DS 1 ;FILLED IN AT PUT FUNCTION
DB ', THEN TYPE RETURN',0
ERRMSG: DB 'PERMANENT ERROR, TYPE RETURN TO IGNORE',0
DONE: DB 'FUNCTION COMPLETE',0
QDISK: DB 'INVALID DRIVE NAME (USE A, B, C, OR D)',0
NOFILE: DB 'NO SOURCE FILE ON DISK',0
BADFILE:
DB 'SOURCE FILE INCOMPLETE',0
;
; VARIABLES
SDISK: DS 1 ;SELECTED DISK FOR CURRENT OPERATION
TRACK: DS 1 ;CURRENT TRACK
SECTOR: DS 1 ;CURRENT SECTOR
RW: DS 1 ;READ IF 0, WRITE IF 1
DMADDR: DS 2 ;CURRENT DMA ADDRESS
RETRY: DS 1 ;NUMBER OF TRIES ON THIS SECTOR
DS STACKSIZE*2
STACK:
END


View File

@@ -0,0 +1,117 @@
version equ 20h
; xsub relocator program, included with the module
; to perform the move from 200h to the destination address
;
; copyright (c) 1979
; digital research
; box 579
; pacific grove, ca.
; 93950
;
org 100h
db (lxi or (b shl 3)) ;lxi b,module size
org $+2 ;skip address field
jmp start
db ' Extended Submit Vers '
db version/16+'0','.',version mod 16+'0'
db ', Copyright (c) 1979, Digital Research '
nogo: db 'Extended Submit Already Present$'
badver: db 'Requires CP/M Version 2.0 or later$'
;
bdos equ 0005h ;bdos entry point
print equ 9 ;bdos print function
vers equ 12 ;get version number
ccplen equ 0800h ;size of ccp
module equ 200h ;module address
;
start:
; ccp's stack used throughout
push b ;save the module's length
lda bdos+1 ;xsub already present?
cpi 06h ;low address must be 06h
jz continue
;
; bdos is not lowest module in memory, return to ccp
mvi c,print
lxi d,nogo ;already present message
call bdos ;to print the message
pop b ;recall length
ret ;to the ccp
;
continue:
mvi c,vers
call bdos ;version number?
cpi version ;2.0 or greater
jnc versok
;
; wrong version
mvi c,print
lxi d,badver
call bdos
pop b
ret ;to ccp
;
versok:
lxi h,bdos+2;address field of jump to bdos (top memory)
mov a,m ;a has high order address of memory top
dcr a ;page directly below bdos
sui (ccplen shr 8) ;-ccp pages
pop b ;recall length of module
push b ;and save it again
sub b ;a has high order address of reloc area
mov d,a
mvi e,0 ;d,e addresses base of reloc area
push d ;save for relocation below
;
lxi h,module;ready for the move
move: mov a,b ;bc=0?
ora c
jz reloc
dcx b ;count module size down to zero
mov a,m ;get next absolute location
stax d ;place it into the reloc area
inx d
inx h
jmp move
;
reloc: ;storage moved, ready for relocation
; hl addresses beginning of the bit map for relocation
pop d ;recall base of relocation area
pop b ;recall module length
push h ;save bit map base in stack
mov h,d ;relocation bias is in d
;
rel0: mov a,b ;bc=0?
ora c
jz endrel
;
; not end of the relocation, may be into next byte of bit map
dcx b ;count length down
mov a,e
ani 111b ;0 causes fetch of next byte
jnz rel1
; fetch bit map from stacked address
xthl
mov a,m ;next 8 bits of map
inx h
xthl ;base address goes back to stack
mov l,a ;l holds the map as we process 8 locations
rel1: mov a,l
ral ;cy set to 1 if relocation necessary
mov l,a ;back to l for next time around
jnc rel2 ;skip relocation if cy=0
;
; current address requires relocation
ldax d
add h ;apply bias in h
stax d
rel2: inx d ;to next address
jmp rel0 ;for another byte to relocate
;
endrel: ;end of relocation
pop d ;clear stacked address
; h has the high order 8-bits of relocated module address
mvi l,0
pchl ;go to relocated program
end


View File

@@ -0,0 +1,176 @@
; xsub loads below ccp, and feeds command lines to
; programs which read buffered input
;
bias equ 0000h ;bias for relocation
base equ 0ffffh ;no intercepts below here
wboot equ 0000h
bdos equ 0005h
bdosl equ bdos+1
dbuff equ 0080h
;
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
modnum equ 14 ;module number position
pbuff equ 9 ;print buffer
rbuff equ 10 ;read buffer
openf equ 15 ;open file
closef equ 16 ;close file
delf equ 19 ;delete file
dreadf equ 20 ;disk read
dmaf equ 26 ;set dma function
;
;
org 0000h+bias
; initialize jmps to include xsub module
lxi h,wstart
shld wboot+1
lhld bdosl
shld rbdos+1 ;real bdos entry
lxi h,trap ;address to fill
shld bdosl ;jmp @0005 leads to trap
pop h ;ccp return address
shld ccpret
pchl ;back to ccp
;
rbdos: jmp 0000h ;filled in at initialization
;
wstart:
lxi sp,stack
mvi c,pbuff ;print message
lxi d,actmsg
call rbdos
lxi h,dbuff ;restore default buffer
shld udma
lxi h,trap
shld bdosl ;fixup low jump address
lhld ccpret ;back to ccp
pchl
actmsg: db cr,lf,'(xsub active)$'
;
trap: ;arrive here at each bdos call
pop h ;return address
push h ;back to stack
mov a,h ;high address
cpi base shr 8
jnc rbdos ;skip calls on bdos above here
mov a,c ;function number
cpi rbuff
jz rnbuff ;read next buffer
cpi dmaf ;set dma address?
jnz rbdos ;skip if not
xchg ;dma to hl
shld udma ;save it
xchg
jmp rbdos
;
setdma:
mvi c,dmaf
lxi d,combuf
call rbdos
ret
;
rsetdma:
mvi c,dmaf
lhld udma
xchg
call rbdos
ret
;
fbdos:
push b
push d
call setdma
pop d
pop b
call rbdos
push psw
call rsetdma
pop psw
ret
;
cksub: ;check for sub file present
mvi c,openf
lxi d,subfcb
call fbdos ;submit file present?
inr a ;00 if not present
ret
;
rnbuff:
push d ;command address
call cksub ;sub file present?
pop d
mvi c,rbuff
jz rbdos ;no sub file now
;
push d
lda subrc ;length of file
ora a ;zero?
jz rbdos ;skip if so
dcr a ;length - 1
sta subcr ;next to read
mvi c,dreadf
lxi d,subfcb
call fbdos ;read record
; now print the buffer with cr,lf
lxi h,combuf
mov e,m ;length
mvi d,0 ;high order 00
dad d ;to last character position
inx h
mvi m,cr
inx h
mvi m,lf
inx h
mvi m,'$'
mvi c,pbuff
lxi d,combuf+1
call rbdos ;to print it
pop h ;.max length
lxi d,combuf
ldax d ;how long?
cmp m ;cy if ok
jc movlin
mov a,m ;max length
stax d ;truncate length
movlin:
mov c,a ;length to c
inr c ;+1
inx h ;to length of line
rdloop:
ldax d ;next char
mov m,a
inx h
inx d
dcr c
jnz rdloop ;loop til copied
mvi c,closef
lxi d,subfcb
lxi h,modnum
dad d ;hl=fcb(modnum)
mvi m,0 ;=0 so acts as if written
lda subcr ;length of file
dcr a ;incremented by read op
sta subrc ;decrease file length
ora a ;at zero?
jnz fileop
mvi c,delf ;delete if at end
fileop: call fbdos
ret
;
subfcb:
db 1 ;a:
db '$$$ '
db 'SUB'
db 0,0,0
subrc:
ds 1
ds 16 ;map
subcr: ds 1
;
combuf: ds 131
udma: dw dbuff
ccpret: ds 2 ;ccp return address
ds 32 ;16 level stack
stack:
end


File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
This file contains a fully commented disassembly of the Digital Research
ASM assembler. I've provided it in two forms:
1) asm.asm -> using Intel 8080 ops. It can be assembled with the MAC or ASM
assemblers.
2) asm.z80 -> using Zilog Z80 ops. It can be assembled with the Z80MR or
compatible assembler.
I would welcome your comments or suggestions.
Larry A. Greene
greenela@clear.lakes.com

View File

@@ -0,0 +1,19 @@
This is the CP/M 2.2 assembler ASM. It has been disassembled, and presented in both 8080, and Z80, mnemonics.
/ASMREAD.ME
This file contains a fully commented disassembly of the Digital Research
ASM assembler. I've provided it in two forms:
1) asm.asm -> using Intel 8080 ops. It can be assembled with the MAC or ASM
assemblers.
2) asm.z80 -> using Zilog Z80 ops. It can be assembled with the Z80MR or
compatible assembler.
I would welcome your comments or suggestions.
Larry A. Greene
greenela@clear.lakes.com

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
The two files in this ZIP file are disassembled CP/M 2.2.
CPM22.ASM : CP/M 2.2 in 8080 mnemonics
CPM22.Z80 : CP/M 2.2 in Z80 mnemonics
Both files claim to implement a fix that affects operation in a sector
deblocking environment. The Z80 version does not look to have been optimized
for the Z80, it just uses Z80 mnemonics.

View File

@@ -0,0 +1,14 @@
This folder contains a disassembled source for CP/M 2.2 in both 8080, and Z80, mnemonics. This source is highly commented and claims to implement a fix for a problem with deblocking algorithms.
/READ.ME
The two files in this ZIP file are disassembled CP/M 2.2.
CPM22.ASM : CP/M 2.2 in 8080 mnemonics
CPM22.Z80 : CP/M 2.2 in Z80 mnemonics
Both files claim to implement a fix that affects operation in a sector
deblocking environment. The Z80 version does not look to have been optimized
for the Z80, it just uses Z80 mnemonics.

View File

@@ -0,0 +1,45 @@
TITLE 'ASM COMMON DATA AREA'
;
; COPYRIGHT (C) 1977, 1978
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE
; CALIFORNIA, 93950
;
; COMMON DATA FOR CP/M ASSEMBLER MODULE
ORG 100H
ENDA EQU 20F0H ;END OF ASSEMBLER PROGRAM
BDOS EQU 5H ;ENTRY TO DOS, USED TO COMPUTE END MEMORY
LXI SP,ENDMOD
LHLD BDOS+1
SHLD SYMAX ;COMPUTE END OF MEMORY
JMP ENDMOD
COPY: DB ' COPYRIGHT(C) 1978, DIGITAL RESEARCH '
ORG COPY
;
; PRINT BUFFER AND PRINT BUFFER POINTER
PBMAX EQU 120 ;MAX PRINT BUFFER
PBUFF: DS PBMAX
PBP: DS 1 ;PRINT BUFFER POINTER
;
; SCANNER PARAMETERS
TOKEN: DS 1 ;CURRENT TOKEN
VALUE: DS 2 ;BINARY VALUE FOR NUMBERS
ACCLEN: DS 1 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;LENGTH OF ACCUMULATOR
ACCUM: DS ACMAX ;ACCUMULATOR (MUST FOLLLOW ACCLEN)
;
; OPERAND EXPRESSION EVALUATOR PARAMETERS
EVALUE: DS 2 ;VALUE OF EXPRESSION AFTER EVALUATION
;
; SYMBOL TABLE MODULE PARAMETERS
SYTOP: DW ENDA ;FIRST LOCATION AVAILABLE FOR SYMBOL TABLE
SYMAX: DS 2 ;LAST AVAILABLE LOCATION FOR SYMBOL TABLE
;
; MISCELLANEOUS DATA AREAS
PASS: DS 1 ;PASS # 0,1
FPC: DS 2 ;FILL ADDRESS FOR NEXT HEX RECORD
ASPC: DS 2 ;ASSEMBLER'S PSEUDO PC
SYBAS: DW ENDA ;SYMBOL TABLE BASE
SYADR: DS 2 ;CURRENT SYMBOL BASE
ENDMOD EQU ($ AND 0FF00H)+100H
END

View File

@@ -0,0 +1,726 @@
TITLE 'ASM IO MODULE'
; I/O MODULE FOR CP/M ASSEMBLER
;
ORG 200H
BOOT EQU 000H ;REBOOT LOCATION
; I/O MODULE ENTRY POINTS
JMP INIT ;INITIALIZE, START ASSEMBLER
JMP SETUP ;FILE SETUP
JMP GNC ;GET NEXT CHARACTER
JMP PNC ;PUT NEXT OUTPUT CHARACTER
JMP PNB ;PUT NEXT HEX BYTE
JMP PCHAR ;PRINT CONSOLE CHARACTER
JMP PCON ;PRINT CONSOLE BUFFER TO CRLF
JMP WOBUFF ;WRITE OUTBUFFER
JMP PERR ;PLACE ERROR CHARACTER INTO PBUFF
JMP DHEX ;PLACE HEX BYTE INTO OUTPUT BUFFER
JMP EOR ;END OF ASSEMBLY
; DATA FOR I/O MODULE
BPC: DS 2 ;BASE PC FOR CURRENT HEX RECORD
DBL: DS 1 ;HEX BUFFER LENGTH
DBUFF: DS 16 ;HEX BUFFER
;
; DISK NAMES
CDISK: DS 1 ;CURRENTLY SELECTED DISK
ADISK: DS 1 ;.ASM DISK
PDISK: DS 1 ;.PRN DISK
HDISK: DS 1 ;.HEX DISK
;
;
;
; COMMON EQUATES
QBMAX EQU 120 ;MAX PRINT SIZE
QBUFF EQU 10CH ;PRINT BUFFER
QBP EQU QBUFF+QBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU QBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR DHEX ROUTINE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
EOF EQU 1AH ;END OF FILE MARK
;
;
; DOS ENTRY POINTS
BDOS EQU 5H ;DOS ENTRY POINT
READC EQU 1 ;READ CONSOLE DEVICE
WRITC EQU 2 ;WRITE CONSOLE DEVICE
REDYC EQU 11 ;CONSOLE CHARACTER READY
SELECT EQU 14 ;SELECT DISK SPECIFIED BY REGISTER E
OPENF EQU 15 ;OPEN FILE
CLOSF EQU 16 ;CLOSE FILE
DELEF EQU 19 ;DELETE FILE
READF EQU 20 ;READ FILE
WRITF EQU 21 ;WRITE FILE
MAKEF EQU 22 ;MAKE A FILE
CSEL EQU 25 ;RETURN CURRENTLY SELECTED DISK
SETDM EQU 26 ;SET DMA ADDRESS
;
; FILE AND BUFFERING PARAMETERS
NSB EQU 8 ;NUMBER OF SOURCE BUFFERS
NPB EQU 6 ;NUMBER OF PRINT BUFFERS
NHB EQU 6 ;NUMBER OF HEX BUFFERS
;
SSIZE EQU NSB*128
PSIZE EQU NPB*128
HSIZE EQU NHB*128
;
; FILE CONTROL BLOCKS
SCB: DS 9 ;FILE NAME
DB 'ASM' ;FILE TYPE
SCBR: DS 1 ;REEL NUMBER (ZEROED IN SETUP)
DS 19 ;MISC AND DISK MAP
SCBCR: DS 1 ;CURRENT RECORD (ZEROED IN SETUP)
;
PCB: DS 9
DB 'PRN',0
DS 19
DB 0 ;RECORD TO WRITE NEXT
;
HCB: DS 9
DB 'HEX',0
DS 19
DB 0
;
; POINTERS AND BUFFERS
SBP: DW SSIZE ;NEXT CHARACTER POSITION TO READ
SBUFF: DS SSIZE
;
PBP: DW 0
PBUFF: DS PSIZE
;
HBP: DW 0
HBUFF: DS HSIZE
FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS
FNM EQU 1 ;POSITION OF FILE NAME
FLN EQU 9 ;FILE NAME LENGTH
BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS
;
SEL: ;SELECT DISK IN REG-A
LXI H,CDISK
CMP M ;SAME?
RZ
MOV M,A ;CHANGE CURRENT DISK
MOV E,A
MVI C,SELECT
CALL BDOS
RET
;
SCNP: ;SCAN THE NEXT PARAMETER
INX H
MOV A,M
CPI ' '
JZ SCNP0
SBI 'A' ;NORMALIZE
RET
SCNP0: LDA CDISK
RET
;
PCON: ;PRINT MESSAGE AT H,L TO CONSOLE DEVICE
MOV A,M
CALL PCHAR
MOV A,M
INX H
CPI CR
JNZ PCON
MVI A,LF
CALL PCHAR
RET
;
FNAME: ;FILL NAME FROM DEFAULT FILE CONTROL BLOCK
LXI D,FCB
MVI B,FLN
FNAM0: LDAX D ;GET NEXT FILE CHARACTER
CPI '?'
JZ FNERR ;FILE NAME ERROR
MOV M,A ;STORE TO FILE CNTRL BLOCK
INX H
INX D
DCR B
JNZ FNAM0 ;FOR NEXT CHARACTER
RET
;
INIT: ;SET UP STACK AND FILES, START ASSEMBLER
LXI H,TITL
CALL PCON
JMP SET0
;
OPEN: ;OPEN FILE ADDRESSED BY D,E
MVI C,OPENF
CALL BDOS
CPI 255
RNZ
; OPEN ERROR
LXI H,ERROP
CALL PCON
JMP BOOT
;
CLOSE: ;CLOSE FILE ADDRESSED BY D,E
MVI C,CLOSF
CALL BDOS
CPI 255
RNZ ;CLOSE OK
LXI H,ERRCL
CALL PCON
JMP BOOT
;
DELETE: ;DELETE FILE ADDRESSED BY D,E
MVI C,DELEF
JMP BDOS
;
MAKE: ;MAKE FILE ADDRESSED BY D,E
MVI C,MAKEF
CALL BDOS
CPI 255
RNZ
; MAKE ERROR
LXI H,ERRMA
CALL PCON
JMP BOOT
;
SELA: LDA ADISK
CALL SEL
RET
;
NPR: ;RETURN ZERO FLAG IF NO PRINT FILE
LDA PDISK
CPI 'Z'-'A'
RZ
CPI 'X'-'A' ;CONSOLE
RET
;
SELP: LDA PDISK
CALL SEL
RET
;
SELH: LDA HDISK
CALL SEL
RET
;
SET0: ;SET UP FILES FOR INPUT AND OUTPUT
LDA FCB ;GET FIRST CHARACTER
CPI ' ' ;MAY HAVE FORGOTTEN NAME
JZ FNERR ;FILE NAME ERROR
MVI C,CSEL ;CURRENT DISK?
CALL BDOS ;GET IT TO REG-A
STA CDISK
;
; SCAN PARAMETERS
LXI H,FCB+FLN-1
CALL SCNP
STA ADISK
CALL SCNP
STA HDISK
CALL SCNP
STA PDISK
;
LXI H,SCB ;ADDRESS SOURCE FILE CONTROL BLOCK
CALL FNAME ;FILE NAME OBTAINED FROM DEFAULT FCB
;
CALL NPR ;Z OR X?
JZ NOPR
LXI H,PCB ;ADDRESS PRINT FILE CONTROL BLOCK
PUSH H ;SAVE A COPY FOR OPEN
PUSH H ;SAVE A COPY FOR DELETE
CALL FNAME ;FILL PCB
CALL SELP
POP D ;FCB ADDRESS
CALL DELETE
POP D ;FCB ADDRESS
CALL MAKE
;
NOPR: ;TEST FOR HEX FILE
LDA HDISK
CPI 'Z'-'A'
JZ NOHEX
LXI H,HCB
PUSH H
PUSH H
CALL FNAME
CALL SELH
POP D
CALL DELETE
POP D
CALL MAKE
;
; FILES SET UP, CALL ASSEMBLER
NOHEX: JMP ENDMOD
;
SETUP: ;SETUP INPUT FILE FOR SOURCE PROGRAM
LXI H,SSIZE
SHLD SBP ;CAUSE IMMEDIATE READ
XRA A ;ZERO VALUE
STA SCBR ;CLEAR REEL NUMBER
STA SCBCR ;CLEAR CURRENT RECORD
STA DBL ;CLEAR HEX BUFFER LENGTH
CALL SELA
LXI D,SCB
CALL OPEN
;
RET
;
FNERR: ;FILE NAME ERROR
LXI H,ERRFN
CALL PCON
JMP BOOT
;
;
GCOMP: ;COMPARE D,E AGAINS H,L
MOV A,D
CMP H
RNZ
MOV A,E
CMP L
RET
;
GNC: ;GET NEXT CHARACTER FROM SOURCE BUFFER
PUSH B
PUSH D
PUSH H ;ENVIRONMENT SAVED
LHLD SBP
LXI D,SSIZE
CALL GCOMP
JNZ GNC2
;
; READ ANOTHER BUFFER
CALL SELA
LXI H,0
SHLD SBP
MVI B,NSB ;NUMBER OF SOURCE BUFFERS
LXI H,SBUFF
GNC0: ;READ 128 BYTES
PUSH B ;SAVE COUNT
PUSH H ;SAVE BUFFER ADDRESS
MVI C,READF
LXI D,SCB
CALL BDOS ;PERFORM THE READ
POP H ;RESTORE BUFFER ADDRESS
POP B ;RESTORE BUFFER COUNT
ORA A ;SET FLAGS
MVI C,128
JNZ GNC1
; NORMAL READ OCCURRED
LXI D,BUFF ;SOURCE BUFFER ADDRESS
MVI C,128
MOV0: LDAX D ;GET CHARACTER
MOV M,A ;STORE CHARACTER
INX D
INX H
DCR C
JNZ MOV0
; BUFFER LOADED, TRY NEXT BUFFER
;
DCR B
JNZ GNC0
JMP GNC2
;
GNC1: ;EOF OR ERROR
CPI 3 ;ALLOW 0,1,2
JNC FRERR ;FILE READ ERROR
GNCE: MVI M,EOF ;STORE AND END OF FILE CHARACTER
INX H
DCR C
JNZ GNCE ;FILL CURRENT BUFFER WITH EOF'S
;
GNC2: ;GET CHARACTER TO ACCUMULATOR AND RETURN
LXI D,SBUFF
LHLD SBP
PUSH H ;SAVE CURRENT SBP
INX H ;READY FOR NEXT READ
SHLD SBP
POP H ;RESTORE PREVIOUS SBP
DAD D ;ABSOLUTE ADDRESS OF CHARACTER
MOV A,M ;GET IT
POP H
POP D
POP B
RET
;
FRERR: LXI H,ERRFR
CALL PCON ;PRINT READ ERROR MESSAGE
JMP BOOT
;
PNC: ;SAME AT PNCF, BUT ENVIRONMENT IS SAVED FIRST
PUSH B
; CHECK FOR CONSOLE OUTPUT / NO OUTPUT
MOV B,A ;SAVE CHARACTER
LDA PDISK ;Z OR X?
CPI 'Z'-'A' ;Z NO OUTPUT
JZ PNRET
;
CPI 'X'-'A'
MOV A,B ;RECOVER CHAR FOR CON OUT
JNZ PNGO
CALL PCHAR
JMP PNRET
;
; NOT X OR Z, SO PRINT IT
PNGO: PUSH D
PUSH H
CALL PNCF
POP H
POP D
PNRET: POP B
RET
;
PNCF: ;PRINT NEXT CHARACTER
LHLD PBP
XCHG
LXI H,PBUFF
DAD D
MOV M,A ;CHARACTER STORED AT PBP IN PBUFF
XCHG ;PBP TO H,L
INX H ;POINT TO NEXT CHARACTER
SHLD PBP ;REPLACE IT
XCHG
LXI H,PSIZE
CALL GCOMP ;AT END OF BUFFER?
RNZ ;RETURN IF NOT
;
; OVERFLOW, WRITE BUFFER
CALL SELP
LXI H,0
SHLD PBP
LXI H,PBUFF
LXI D,PCB ;D,E ADDRESS FILE CONTROL BLOCK
MVI B,NPB ;NUMBER OF BUFFERS TO B
; (DROP THROUGH TO WBUFF)
;
WBUFF: ;WRITE BUFFERS STARTING AT H,L FOR B BUFFERS
; CHECK FOR EOF'S
MOV A,M
CPI EOF
RZ ;DON'T DO THE WRITE
;
PUSH B ;SAVE NUMBER OF BUFFERS
PUSH D ;SAVE FCB ADDRESS
MVI C,128 ;READY FOR MOVE
LXI D,BUFF
WBUF0: ;MOVE TO BUFFER
MOV A,M ;GET CHARACTER
STAX D ;PUT CHARACTER
INX H
INX D
DCR C
JNZ WBUF0
;
; WRITE BUFFER
POP D ;RECOVER FCB ADDRESS
PUSH D ;SAVE IT AGAIN FOR LATER
PUSH H ;SAVE BUFFER ADDRESS
MVI C,WRITF ;DOS WRITE FUNCTION
CALL BDOS
POP H ;RECOVER BUFFER ADDRESS
POP D ;RECOVER FCB ADDRESS
POP B ;RECOVER BUFFER COUNT
ORA A ;SET ERROR RETURN FLAGS
JNZ FWERR
;
; WRITE OK
DCR B
RZ ;RETURN IF NO MORE BUFFERS TO WRITE
JMP WBUFF
;
FWERR: ;ERROR IN WRITE
LXI H,ERRFW
CALL PCON ;ERROR MESSAGE OUT
JMP EORC ;TO CLOSE AND REBOOT
;
;
PNB: ;PUT NEXT HEX BYTE
PUSH B
PUSH D
PUSH H
CALL PNBF
POP H
POP D
POP B
RET
;
PNBF: ;PUT NEXT BYTE
; (SIMILAR TO THE PNCF SUBROUTINE)
LHLD HBP
XCHG
LXI H,HBUFF
DAD D
MOV M,A ;CHARACTER STORED AT HBP IN HBUFF
XCHG
INX H ;HBP INCREMENTED
SHLD HBP
XCHG ;BACK TO D,E
LXI H,HSIZE
CALL GCOMP ;EQUAL?
RNZ
;
; OVERFLOW, WRITE BUFFERS
CALL SELH
LXI H,0
SHLD HBP
LXI H,HBUFF
LXI D,HCB ;FILE CONTROL BLOCK FOR HEX FILE
MVI B,NHB
JMP WBUFF ;WRITE BUFFERS
;
PCHAR: ;PRINT CHARACTER IN REGISTER A
PUSH B
PUSH D
PUSH H
MVI C,WRITC
MOV E,A
CALL BDOS
POP H
POP D
POP B
RET
;
WOCHAR: ;WRITE CHARACTER IN REG-A WITH REFLECT AT CONSOLE IF ERROR
MOV C,A ;SAVE THE CHAR
CALL PNC ;PRINT CHAR
LDA QBUFF
CPI ' '
RZ
; ERROR IN LINE
LDA PDISK
CPI 'X'-'A'
RZ ;ALREADY PRINTED IF 'X'
;
MOV A,C ;RECOVER CHARACTER
CALL PCHAR ;PRINT IT
RET
;
WOBUFF: ;WRITE THE OUTPUT BUFFER TO THE PRINT FILE
LDA QBP ;GET CHARACTER COUNT
LXI H,QBUFF ;BASE OF BUFFER
WOB0: ORA A ;ZERO COUNT?
JZ WOBE
; NOT END, SAVE COUNT AND GET CHARACTER
MOV B,A ;SAVE COUNT
MOV A,M
CALL WOCHAR ;WRITE CHARACTER
INX H ;ADDRESS NEXT CHARACTER OF BUFFER
MOV A,B ;GET COUNT
DCR A
JMP WOB0
;
WOBE: ;END OF PRINT - ZERO QBP
STA QBP
; FOLLOW BY CR LF
MVI A,CR
CALL WOCHAR
MVI A,LF
CALL WOCHAR
LXI H,QBUFF
MVI A,QBMAX ;READY TO BLANK OUT
WOB2: MVI M,' '
INX H
DCR A
JNZ WOB2
RET
;
;
PERR: ;FILL QBUFF ERROR MESSAGE POSITION
MOV B,A ;SAVE CHARACTER
LXI H,QBUFF
MOV A,M
CPI ' '
RNZ ;DON'T CHANGE IT IF ALREADY SET
MOV M,B ;STORE ERROR CHARACTER
RET
;
EOR: ;END OF ASSEMBLER
CALL NPR ;Z OR A?
JZ EOPR
; FILL OUTPUT FILES WITH EOF'S
EOR2: LHLD PBP
MOV A,L
ORA H ;VALUE ZERO?
JZ EOPR
MVI A,EOF ;CTL-Z IS END OF FILE
CALL PNC ;PUT ENDFILES IN PRINT BUFFER
JMP EOR2 ;EVENTUALLY BUFFER IS WRITTEN
;
EOPR: ;END OF PRINT FILE, CHECK HEX
LDA HDISK
CPI 'Z'-'A'
JZ EORC
EOR0: ;WRITE TERMINATING RECORD INTO HEX FILE
LDA DBL ;MAY BE ZERO ALREADY
ORA A
CNZ WHEX ;WRITE HEX BUFFER IF NOT ZERO
LHLD FPC ;GET CURRENT FPC AS LAST ADDRESS
SHLD BPC ;RECORD LENGTH ZERO, BASE ADDRESS 0000
CALL WHEX ;WRITE HEX BUFFER
;
; NOW CLEAR OUTPUT BUFFER FOR HEX FILE
EOR1: LHLD HBP
MOV A,L
ORA H
JZ EORC
MVI A,EOF
CALL PNB
JMP EOR1
;
; CLOSE FILES AND TERMINATE
EORC:
CALL NPR
JZ EORPC
CALL SELP
LXI D,PCB
CALL CLOSE
EORPC:
LDA HDISK
CPI 'Z'-'A'
JZ EORHC
CALL SELH
LXI D,HCB
CALL CLOSE
;
EORHC:
LXI H,ENDA
CALL PCON
JMP BOOT
;
TITL: DB 'CP/M ASSEMBLER - VER 1.4',CR
ERROP: DB 'NO SOURCE FILE PRESENT',CR
ERRMA: DB 'NO DIRECTORY SPACE',CR
ERRFN: DB 'SOURCE FILE NAME ERROR',CR
ERRFR: DB 'SOURCE FILE READ ERROR',CR
ERRFW: DB 'OUTPUT FILE WRITE ERROR',CR
ERRCL: DB 'CANNOT CLOSE FILES',CR
ENDA: DB 'END OF ASSEMBLY',CR
;
DHEX: ;DATA TO HEX BUFFER (BYTE IN REG-A)
PUSH B
MOV B,A ;HOLD CHARACTER FOR 'Z' TEST
LDA HDISK
CPI 'Z'-'A'
MOV A,B ;RECOVER CHARACTER
JZ DHRET
PUSH D ;ENVIRONMENT SAVED
PUSH PSW ;SAVE DATA BYTE
LXI H,DBL ;CURRENT LENGTH
MOV A,M ;TO ACCUM
ORA A ;ZERO?
JZ DHEX3
;
; LENGTH NOT ZERO, MAY BE FULL BUFFER
CPI 16
JC DHEX1 ;BR IF LESS THAN 16 BYTES
; BUFFER FULL, DUMP IT
CALL WHEX ;DBL = 0 UPON RETURN
JMP DHEX3 ;SET BPC AND DATA BYTE
;
DHEX1: ;PARTIAL BUFFER IN PROGRESS, CHECK FOR SEQUENTIAL BYTE LOAD
LHLD FPC
XCHG
LHLD BPC ;BASE PC IN H,L
MOV C,A ;CURRENT LENGTH OF BUFFER
MVI B,0 ;IS IN B,C
DAD B ;BPC+DBL TO H,L
MOV A,E ;READY FOR COMPARE
CMP L ;EQUAL?
JNZ DHEX2 ;BR IF NOT
MOV A,D ;CHECK HO BYTE
CMP H
JZ DHEX4 ;BR IF SAME ADDRESS
;
DHEX2: ;NON SEQUENTIAL ADDRESS, DUMP AND CHANGE BASE ADDRESS
CALL WHEX
DHEX3: ;SET NEW BASE
LHLD FPC
SHLD BPC
;
DHEX4: ;STORE DATA BYTE AND INC DBL
LXI H,DBL
MOV E,M ;LENGTH TO REG-E
INR M ;DBL=DBL+1
MVI D,0 ;HIGH ORDER ZERO FOR DOUBLE ADD
LXI H,DBUFF
DAD D ;DBUFF+DBL TO H,L
POP PSW ;RESTORE DATA BYTE
MOV M,A ;INTO DATA BUFFER
POP D
DHRET: POP B ;ENVIRONMENT RESTORED
RET
;
WRC: ;WRITE CHARACTER WITH CHECK SUM IN D
PUSH PSW
RRC
RRC
RRC
RRC
ANI 0FH
CALL HEXC ;OUTPUT HEX CHARACTER
POP PSW ;RESTORE BYTE
PUSH PSW ;SAVE A VERSION
ANI 0FH
CALL HEXC ;WRITE LOW NIBBLE
POP PSW ;RESTORE BYTE
ADD D ;COMPUTE CHECKSUM
MOV D,A ;SAVE CS
RET
;
HEXC: ;WRITE CHARACTER
ADI 90H
DAA
ACI 40H
DAA
JMP PNB ;PUT BYTE
;
WHEX: ;WRITE CURRENT HEX BUFFER
MVI A,':' ;RECORD HEADER
CALL PNB ;PUT BYTE
LXI H,DBL ;RECORD LENGTH ADDRESS
MOV E,M ;LENGTH TO REG-E
XRA A ;ZERO TO REG-A
MOV D,A ;CLEAR CHECKSUM
MOV M,A ;LENGTH IS ZEROED FOR NEXT WRITE
LHLD BPC ;BASE ADDRESS FOR RECORD
MOV A,E ;LENGTH TO A
CALL WRC ;WRITE HEX VALUE
MOV A,H ;HIGH ORDER BASE ADDR
CALL WRC ;WRITE HO BYTE
MOV A,L ;LOW ORDER BASE ADDR
CALL WRC ;WRITE LO BYTE
XRA A ;ZERO TO A
CALL WRC ;WRITE RECORD TYPE 00
MOV A,E ;CHECK FOR LENGTH 0
ORA A
JZ WHEX1
;
; NON - ZERO, WRITE DATA BYTES
LXI H,DBUFF
WHEX0: MOV A,M ;GET BYTE
INX H
CALL WRC ;WRITE DATA BYTE
DCR E ;END OF BUFFER?
JNZ WHEX0
;
; END OF DATA BYTES, WRITE CHECK SUM
WHEX1: XRA A
SUB D ;COMPUTE CHECKSUM
CALL WRC
;
; SEND CRLF AT END OF RECORD
MVI A,CR
CALL PNB
MVI A,LF
CALL PNB
RET
;
;
;
ENDMOD EQU ($ AND 0FFE0H)+20H
END

View File

@@ -0,0 +1,404 @@
TITLE 'ASM SCANNER MODULE'
ORG 1100H
JMP ENDMOD ;END OF THIS MODULE
JMP INITS ;INITIALIZE THE SCANNER
JMP SCAN ;CALL THE SCANNER
;
;
; ENTRY POINTS IN I/O MODULE
IOMOD EQU 200H
GNCF EQU IOMOD+6H
WOBUFF EQU IOMOD+15H
PERR EQU IOMOD+18H
;
LASTC: DS 1 ;LAST CHAR SCANNED
NEXTC: DS 1 ;LOOK AHEAD CHAR
STYPE: DS 1 ;RADIX INDICATOR
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
BINV EQU 2
OCTV EQU 8
DECV EQU 10
HEXV EQU 16
CR EQU 0DH
LF EQU 0AH
EOF EQU 1AH
TAB EQU 09H ;TAB CHARACTER
;
;
; UTILITY SUBROUTINES
GNC: ;GET NEXT CHARACTER AND ECHO TO PRINT FILE
CALL GNCF
PUSH PSW
CPI CR
JZ GNC0
CPI LF ;IF LF THEN DUMP CURRENT BUFFER
JZ GNC0
;
;NOT A CR OR LF, PLACE INTO BUFFER IF THERE IS ENOUGH ROOM
LDA PBP
CPI PBMAX
JNC GNC0
; ENOUGH ROOM, PLACE INTO BUFFER
MOV E,A
MVI D,0 ;DOUBLE PRECISION PBP IN D,E
INR A
STA PBP ;INCREMENTED PBP IN MEMORY
LXI H,PBUFF
DAD D ;PBUFF(PBP)
POP PSW
MOV M,A ;PBUFF(PBP) = CHAR
RET
GNC0: ;CHAR NOT PLACED INTO BUFFER
POP PSW
RET
;
INITS: ;INITIALIZE THE SCANNER
CALL ZERO
STA NEXTC ;CLEAR NEXT CHARACTER
STA PBP
MVI A,LF ;SET LAST CHAR TO LF
STA LASTC
CALL WOBUFF ;CLEAR BUFFER
MVI A,16 ;START OF PRINT LINE
STA PBP
RET
;
ZERO: XRA A
STA ACCLEN
STA STYPE
RET
;
SAVER: ;STORE THE NEXT CHARACTER INTO THE ACCUMULATOR AND UPDATE ACCLEN
LXI H,ACCLEN
MOV A,M
CPI ACMAX
JC SAV1 ;JUMP IF NOT UP TO LAST POSITION
MVI M,0
CALL ERRO
SAV1: MOV E,M ;D,E WILL HOLD INDEX
MVI D,0
INR M ;ACCLEN INCREMENTED
INX H ;ADDRESS ACCUMULATOR
DAD D ;ADD INDEX TO ACCUMULATOR
LDA NEXTC ;GET CHARACTER
MOV M,A ;INTO ACCUMULATOR
RET
;
TDOLL: ;TEST FOR DOLLAR SIGN, ASSUMING H,L ADDRESS NEXTC
MOV A,M
CPI '$'
RNZ
XRA A ;TO GET A ZERO
MOV M,A ;CLEARS NEXTC
RET ;WITH ZERO FLAG SET
;
NUMERIC: ;CHECK NEXTC FOR NUMERIC, RETURN ZERO FLAG IF NOT NUMERIC
LDA NEXTC
SUI '0'
CPI 10
; CARRY RESET IF NUMERIC
RAL
ANI 1B ;ZERO IF NOT NUMERIC
RET
;
HEX: ;RETURN ZERO FLAG IF NEXTC IS NOT HEXADECIMAL
CALL NUMERIC
RNZ ;RETURNS IF 0-9
LDA NEXTC
SUI 'A'
CPI 6
; CARRY SET IF OUT OF RANGE
RAL
ANI 1B
RET
;
LETTER: ;RETURN ZERO FLAG IF NEXTC IS NOT A LETTER
LDA NEXTC
SUI 'A'
CPI 26
RAL
ANI 1B
RET
;
ALNUM: ;RETURN ZERO FLAG IF NOT ALPHANUMERIC
CALL LETTER
RNZ
CALL NUMERIC
RET
;
TRANS: ;TRANSLATE TO UPPER CASE
LDA NEXTC
CPI 'A' OR 1100000B ;LOWER CASE A
RC ;CARRY IF LESS THAN LOWER A
CPI ('Z' OR 1100000B)+1 ;LOWER CASE Z
RNC ;NO CARRY IF GREATER THAN LOWER Z
ANI 1011111B ;CONVERT TO UPPER CASE
STA NEXTC
RET
;
GNCN: ;GET CHARACTER AND STORE TO NEXTC
CALL GNC
STA NEXTC
CALL TRANS ;TRANSLATE TO UPPER CASE
RET
;
EOLT: ;END OF LINE TEST FOR COMMENT SCAN
CPI CR
RZ
CPI EOF
RZ
CPI '!'
RET
;
SCAN: ;FIND NEXT TOKEN IN INPUT STREAM
XRA A
STA TOKEN
CALL ZERO
;
; DEBLANK
DEBL: LDA NEXTC
CPI TAB ;TAB CHARACTER TREATED AS BLANK OUTSIDE STRING
JZ DEB0
CPI ';' ;MAY BE A COMMENT
JZ DEB1 ;DEBLANK THROUGH COMMENT
CPI '*' ;PROCESSOR TECH COMMENT
JNZ DEB2 ;NOT *
LDA LASTC
CPI LF ;LAST LINE FEED?
JNZ DEB2 ;NOT LF*
; COMMENT FOUND, REMOVE IT
DEB1: CALL GNCN
CALL EOLT ;CR, EOF, OR !
JZ FINDL ;HANDLE END OF LINE
JMP DEB1 ;OTHERWISE CONTINUE SCAN
DEB2: ORI ' ' ;MAY BE ZERO
CPI ' '
JNZ FINDL
DEB0: CALL GNCN ;GET NEXT AND STORE TO NEXTC
JMP DEBL
;
; LINE DEBLANKED, FIND TOKEN TYPE
FINDL: ;LOOK FOR LETTER, DECIMAL DIGIT, OR STRING QUOTE
CALL LETTER
JZ FIND0
MVI A,IDEN
JMP STOKEN
;
FIND0: CALL NUMERIC
JZ FIND1
MVI A,NUMB
JMP STOKEN
;
FIND1: LDA NEXTC
CPI ''''
JNZ FIND2
XRA A
STA NEXTC ;DON'T STORE THE QUOTE
MVI A,STRNG
JMP STOKEN
;
FIND2: ;ASSUME IT IS A SPECIAL CHARACTER
CPI LF ;IF LF THEN DUMP THE BUFFER
JNZ FIND3
; LF FOUND
LDA PASS
ORA A
CNZ WOBUFF
LXI H,PBUFF ;CLEAR ERROR CHAR ON BOTH PASSES
MVI M,' '
MVI A,16
STA PBP ;START NEW LINE
FIND3: MVI A,SPECL
;
STOKEN: STA TOKEN
;
;
; LOOP WHILE CURRENT ITEM IS ACCUMULATING
SCTOK: LDA NEXTC
STA LASTC ;SAVE LAST CHARACTER
ORA A
CNZ SAVER ;STORE CHARACTER INTO ACCUM IF NOT ZERO
CALL GNCN ;GET NEXT TO NEXTC
LDA TOKEN
CPI SPECL
RZ ;RETURN IF SPECIAL CHARACTER
CPI STRNG
CNZ TRANS ;TRANSLATE TO UPPER CASE IF NOT IN STRING
LXI H,NEXTC
LDA TOKEN
;
CPI IDEN
JNZ SCT2
;
; ACCUMULATING AN IDENTIFIER
CALL TDOLL ;$?
JZ SCTOK ;IF SO, SKIP IT
CALL ALNUM ;ALPHA NUMERIC?
RZ ;RETURN IF END
; NOT END OF THE IDENTIFIER
JMP SCTOK
;
SCT2: ;NOT SPECIAL OR IDENT, CHECK NUMBER
CPI NUMB
JNZ SCT3
;
; ACCUMULATING A NUMBER, CHECK FOR $
CALL TDOLL
JZ SCTOK ;SKIP IF FOUND
CALL HEX ;HEX CHARACTER?
JNZ SCTOK ;STORE IT IF FOUND
; END OF NUMBER, LOOK FOR RADIX INDICATOR
;
LDA NEXTC
CPI 'O' ;OCTAL INDICATOR
JZ NOCT
CPI 'Q' ;OCTAL INDICATOR
JNZ NUM2
;
NOCT: ;OCTAL
MVI A,OCTV
JMP SSTYP
;
NUM2: CPI 'H'
JNZ NUM3
MVI A,HEXV
SSTYP: STA STYPE
XRA A
STA NEXTC ;CLEARS THE LOOKAHEAD CHARACTER
JMP NCON
;
; RADIX MUST COME FROM ACCUM
NUM3: LDA LASTC
CPI 'B'
JNZ NUM4
MVI A,BINV
JMP SSTY1
;
NUM4: CPI 'D'
MVI A,DECV
JNZ SSTY2
SSTY1: LXI H,ACCLEN
DCR M ;ACCLEN DECREMENTED TO REMOVE RADIX INDICATOR
SSTY2: STA STYPE
;
NCON: ;NUMERIC CONVERSION OCCURS HERE
LXI H,0
SHLD VALUE ;VALUE ACCUMULATES BINARY EQUIVALENT
LXI H,ACCLEN
MOV C,M ;C=ACCLEN
INX H ;ADDRESSES ACCUM
CLOP: ;NEXT DIGIT IS PROCESSED HERE
MOV A,M
INX H ;READY FOR NEXT LOOP
CPI 'A'
JNC CLOP1 ;NOT HEX A-F
SUI '0' ;NORMALIZE
JMP CLOP2
;
CLOP1: ;HEX A-F
SUI 'A'-10
CLOP2: ;CHECK SIZE AGAINST RADIX
PUSH H ;SAVE ACCUM ADDR
PUSH B ;SAVE CURRENT POSITION
MOV C,A
LXI H,STYPE
CMP M
CNC ERRV ;VALUE ERROR IF DIGIT>=RADIX
MVI B,0 ;DOUBLE PRECISION DIGIT
MOV A,M ;RADIX TO ACCUMULATOR
LHLD VALUE
XCHG ;VALUE TO D,E - ACCUMULATE RESULT IN H,L
LXI H,0 ;ZERO ACCUMULATOR
CLOP3: ;LOOP UNTIL RADIX GOES TO ZERO
ORA A
JZ CLOP4
RAR ;TEST LSB
JNC TTWO ;SKIP SUMMING OPERATION IF LSB=0
DAD D ;ADD IN VALUE
TTWO: ;MULTIPLY VALUE * 2 FOR SHL OPERATION
XCHG
DAD H
XCHG
JMP CLOP3
;
;
CLOP4: ;END OF NUMBER CONVERSION
DAD B ;DIGIT ADDED IN
SHLD VALUE
POP B
POP H
DCR C ;MORE DIGITS?
JNZ CLOP
RET ;DONE WITH THE NUMBER
;
SCT3: ;MUST BE A STRING
LDA NEXTC
CPI CR ;END OF LINE?
JZ ERRO ;AND RETURN
CPI ''''
JNZ SCTOK
CALL GNCN
CPI ''''
RNZ ;RETURN IF SINGLE QUOTE ENCOUNTERED
JMP SCTOK ;OTHERWISE TREAT AS ONE QUOTE
;
; END OF SCANNER
;
; ERROR MESSAGE ROUTINES
ERRV: ;'V' VALUE ERROR
PUSH PSW
MVI A,'V'
JMP ERR
;
ERRO: ;'O' OVERFLOW ERROR
PUSH PSW
MVI A,'O'
JMP ERR
;
ERR: ;PRINT ERROR MESSAGE
PUSH B
PUSH H
CALL PERR
POP H
POP B
POP PSW
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H
END

View File

@@ -0,0 +1,381 @@
TITLE 'ASM SYMBOL TABLE MODULE'
; SYMBOL TABLE MANIPULATION MODULE
;
ORG 1340H
IOMOD EQU 200H ;IO MODULE ENTRY POINT
PCON EQU IOMOD+12H
EOR EQU IOMOD+1EH
;
;
; ENTRY POINTS TO SYMBOL TABLE MODULE
JMP ENDMOD
JMP INISY
JMP LOOKUP
JMP FOUND
JMP ENTER
JMP SETTY
JMP GETTY
JMP SETVAL
JMP GETVAL
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
SYBAS EQU ASPC+2 ;BASE OF SYMBOL TABLE
SYADR EQU SYBAS+2 ;CURRENT SYMBOL BEING ACCESSED
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
CR EQU 0DH
;
; DATA AREAS
; SYMBOL TABLE BEGINS AT THE END OF THIS MODULE
FIXD EQU 5 ;5 BYTES OVERHEAD WITH EACH SYMBOL ENTRY
; 2BY COLLISION, 1BY TYPE/LEN, 2BY VALUE
HSIZE EQU 128 ;HASH TABLE SIZE
HMASK EQU HSIZE-1 ;HASH MASK FOR CODING
HASHT: DS HSIZE*2 ;HASH TABLE
HASHC: DS 1 ;HASH CODE AFTER CALL ON LOOKUP
;
; SYMBOL TABLE ENTRY FORMAT IS
; -----------------
; : HIGH VAL BYTE :
; -----------------
; : LOW VAL BYTE :
; -----------------
; : CHARACTER N :
; -----------------
; : ... :
; -----------------
; : CHARACTER 1 :
; -----------------
; : TYPE : LENG :
; -----------------
; : HIGH COLLISION:
; -----------------
; SYADR= : LOW COLLISION :
; -----------------
;
; WHERE THE LOW/HIGH COLLISION FIELD ADDRESSES ANOTHER ENTRY WITH
; THE SAME HASH CODE (OR ZERO IF THE END OF CHAIN), TYPE DESCRIBES
; THE ENTRY TYPE (GIVEN BELOW), LENG IS THE NUMBER OF CHARACTERS IN
; THE SYMBOL PRINTNAME -1 (I.E., LENG=0 IS A SINGLE CHARACTER PRINT-
; NAME, WHILE LENG=15 INDICATES A 16 CHARACTER NAME). CHARACTER 1
; THROUGH N GIVE THE PRINTNAME CHARACTERS IN ASCII UPPER CASE (ALL
; LOWER CASE NAMES ARE TRANSLATED ON INPUT), AND THE LOW/HIGH VALUE
; GIVE THE PARTICULAR ADDRESS OR CONSTANT VALUE ASSOCIATED WITH THE
; NAME. THE REPRESENTATION OF MACROS DIFFERS IN THE FIELDS WHICH
; FOLLOW THE VALUE FIELD (MACROS ARE NOT CURRENTLY IMPLEMENTED).
;
; THE TYPE FIELD CONSISTS OF FOUR BITS WHICH ARE ASSIGNED AS
; FOLLOWS:
;
; 0000 UNDEFINED SYMBOL
; 0001 LOCAL LABELLED PROGRAM
; 0010 LOCAL LABELLED DATA
; 0011 (UNUSED)
; 0100 EQUATE
; 0101 SET
; 0110 MACRO
; 0111 (UNUSED)
;
; 1000 (UNUSED)
; 1001 EXTERN LABELLED PROGRAM
; 1010 EXTERN LABELLED DATA
; 1011 REFERENCE TO MODULE
; 1100 (UNUSED)
; 1101 GLOBAL UNDEFINED SYMBOL
; 1110 GLOBAL LABELLED PROGRAM
; 1111 (UNUSED)
;
; TYPE DEFINITIONS
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL ATTRIBUTE
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL ATTRIBUTE
;
;
INISY: ;INITIALIZE THE SYMBOL TABLE
LXI H,HASHT ;ZERO THE HASH TABLE
MVI B,HSIZE
XRA A ;CLEAR ACCUM
INI0:
MOV M,A
INX H
MOV M,A ;CLEAR DOUBLE WORD
INX H
DCR B
JNZ INI0
;
; SET SYMBOL TABLE POINTERS
LXI H,0
SHLD SYADR
;
RET
;
CHASH: ;COMPUTE HASH CODE FOR CURRENT ACCUMULATOR
LXI H,ACCLEN
MOV B,M ;GET ACCUM LENGTH
XRA A ;CLEAR ACCUMULATOR
CH0: INX H ;MOVE TO FIRST/NEXT CHARACTER POSITION
ADD M ;ADD WITH OVERFLOW
DCR B
JNZ CH0
ANI HMASK ;MASK BITS FOR MODULO HZISE
STA HASHC ;FILL HASHC WITH RESULT
RET
;
SETLN: ;SET THE LENGTH FIELD OF THE CURRENT SYMBOL
MOV B,A ;SAVE LENGTH IN B
LHLD SYADR
INX H
INX H
MOV A,M ;GET TYPE/LENGTH FIELD
ANI 0F0H ;MASK OUT TYPE FIELD
ORA B ;MASK IN LENGTH
MOV M,A
RET
;
GETLN: ;GET THE LENGTH FIELD TO REG-A
LHLD SYADR
INX H
INX H
MOV A,M
ANI 0FH
INR A ;LENGTH IS STORED AS VALUE - 1
RET
;
FOUND: ;FOUND RETURNS TRUE IF SYADR IS NOT ZERO (TRUE IS NZ FLAG HERE)
LHLD SYADR
MOV A,L
ORA H
RET
;
LOOKUP: ;LOOK FOR SYMBOL IN ACCUMULATOR
CALL CHASH ;COMPUTE HASH CODE
; NORMALIZE IDENTIFIER TO 16 CHARACTERS
LXI H,ACCLEN
MOV A,M
CPI 17
JC LENOK
MVI M,16
LENOK:
; LOOK FOR SYMBOL THROUGH HASH TABLE
LXI H,HASHC
MOV E,M
MVI D,0 ;DOUBLE HASH CODE IN D,E
LXI H,HASHT ;BASE OF HASH TABLE
DAD D
DAD D ;HASHT(HASHC)
MOV E,M ;LOW ORDER ADDRESS
INX H
MOV H,M
MOV L,E ;HEADER TO LIST OF SYMBOLS IS IN H,L
LOOK0: SHLD SYADR
CALL FOUND
RZ ;RETURN IF SYADR BECOMES ZERO
;
; OTHERWISE EXAMINE CHARACTER STRING FOR MATCH
CALL GETLN ;GET LENGTH TO REG-A
LXI H,ACCLEN
CMP M
JNZ LCOMP
;
; LENGTH MATCH, TRY TO MATCH CHARACTERS
MOV B,A ;STRING LENGTH IN B
INX H ;HL ADDRESSES ACCUM
XCHG ;TO D,E
LHLD SYADR
INX H
INX H
INX H ;ADDRESSES CHARACTERS
LOOK1: LDAX D ;NEXT CHARACTER FROM ACCUM
CMP M ;NEXT CHARACTER IN SYMBOL TABLE
JNZ LCOMP
; CHARACTER MATCHED, INCREMENT TO NEXT
INX D
INX H
DCR B
JNZ LOOK1
;
; COMPLETE MATCH AT CURRENT SYMBOL, SYADR IS SET
RET
;
LCOMP: ;NOT FOUND, MOVE SYADR DOWN ONE COLLISION ADDRESS
LHLD SYADR
MOV E,M
INX H
MOV D,M ;COLLISION ADDRESS IN D,E
XCHG
JMP LOOK0
;
;
ENTER: ;ENTER SYMBOL IN ACCUMULATOR
; ENSURE THERE IS ENOUGH SPACE IN THE TABLE
LXI H,ACCLEN
MOV E,M
MVI D,0 ;DOUBLE PRECISION ACCLEN IN D,E
LHLD SYTOP
SHLD SYADR ;NEXT SYMBOL LOCATION
DAD D ;SYTOP+ACCLEN
LXI D,FIXD ;FIXED DATA/SYMBOL
DAD D ;HL HAS NEXT TABLE LOCATION FOR SYMBOL
XCHG ;NEW SYTOP IN D,E
LHLD SYMAX ;MAXIMUM SYMTOP VALUE
MOV A,E
SUB L ;COMPUTE 16-BIT DIFFERENCE
MOV A,D
SBB H
XCHG ;NEW SYTOP IN H,L
JNC OVERER ;OVERFLOW IN TABLE
;
; OTHERWISE NO ERROR
SHLD SYTOP ;SET NEW TABLE TOP
LHLD SYADR ;SET COLLISION FIELD
XCHG ;CURRENT SYMBOL ADDRESS TO D,E
LXI H,HASHC ;HASH CODE FOR CURRENT SYMBOL TO H,L
MOV C,M ;LOW BYTE
MVI B,0 ;DOUBLE PRECISION VALUE IN B,C
LXI H,HASHT ;BASE OF HASH TABLE
DAD B
DAD B ;HASHT(HASHC) IN H,L
; D,E ADDRESSES CURRENT SYMBOL - CHANGE LINKS
MOV C,M ;LOW ORDER OLD HEADER
INX H
MOV B,M ;HIGH ORDER OLD HEADER
MOV M,D ;HIGH ORDER NEW HEADER TO HASH TABLE
DCX H
MOV M,E ;LOW ORDER NEW HEADER TO HASH TABLE
XCHG ;H,L HOLDS SYMBOL TABLE ADDRESS
MOV M,C ;LOW ORDER OLD HEADER TO COLLISION FIELD
INX H
MOV M,B ;HIGH ORDER OLD HEADER TO COLLISION FIELD
;
; HASH CHAIN NOW REPAIRED FOR THIS ENTRY, COPY THE PRINTNAME
LXI D,ACCLEN
LDAX D ;GET SYMBOL LENGTH
CPI 17 ;LARGER THAN 16 SYMBOLS?
JC ENT1
MVI A,16 ;TRUNCATE TO 16 CHARACTERS
; COPY LENGTH FIELD, FOLLOWED BY PRINTNAME CHARACTERS
ENT1: MOV B,A ;COPY LENGTH TO B
DCR A ;1-16 CHANGED TO 0-15
INX H ;FOLLOWING COLLISION FIELD
MOV M,A ;STORE LENGTH WITH UNDEFINED TYPE (0000)
ENT2: INX H
INX D
LDAX D
MOV M,A ;STORE NEXT CHARACTER OF PRINTNAME
DCR B ;LENGTH=LENGTH-1
JNZ ENT2 ;FOR ANOTHER CHARACTER
;
; PRINTNAME COPIED, ZERO THE VALUE FIELD
XRA A ;ZERO A
INX H ;LOW ORDER VALUE
MOV M,A
INX H
MOV M,A ;HIGH ORDER VALUE
RET
;
OVERER: ;OVERFLOW IN SYMBOL TABLE
LXI H,ERRO
CALL PCON
JMP EOR ;END OF EXECUTION
ERRO: DB 'SYMBOL TABLE OVERFLOW',CR
;
SETTY: ;SET CURRENT SYMBOL TYPE TO VALUE IN REG-A
RAL
RAL
RAL
RAL
ANI 0F0H ;TYPE MOVED TO HIGH ORDER 4-BITS
MOV B,A ;SAVE IT IN B
LHLD SYADR ;BASE OF SYMBOL TO ACCESS
INX H
INX H ;ADDRESS OF TYPE/LENGTH FIELD
MOV A,M ;GET IT AND MASK
ANI 0FH ;LEAVE LENGTH
ORA B ;MASK IN TYPE
MOV M,A ;STORE IT
RET
;
GETTY: ;RETURN THE TYPE OF THE VALUE IN CURRENT SYMBOL
LHLD SYADR
INX H
INX H
MOV A,M
RAR
RAR
RAR
RAR
ANI 0FH ;TYPE MOVED TO LOW 4-BITS OF REG-A
RET
;
VALADR: ;GET VALUE FIELD ADDRESS FOR CURRENT SYMBOL
CALL GETLN ;PRINTNAME LENGTH TO ACCUM
LHLD SYADR ;BASE ADDRESS
MOV E,A
MVI D,0
DAD D ;BASE(LEN)
INX H
INX H ;FOR COLLISION FIELD
INX H ;FOR TYPE/LEN FIELD
RET ;WITH H,L ADDRESSING VALUE FIELD
;
SETVAL: ;SET THE VALUE FIELD OF THE CURRENT SYMBOL
; VALUE IS SENT IN H,L
PUSH H ;SAVE VALUE TO SET
CALL VALADR
POP D ;POP VALUE TO SET, HL HAS ADDRESS TO FILL
MOV M,E
INX H
MOV M,D ;FIELD SET
RET
;
GETVAL: ;GET THE VALUE FIELD OF THE CURRENT SYMBOL TO H,L
CALL VALADR ;ADDRESS OF VALUE FIELD TO H,L
MOV E,M
INX H
MOV D,M
XCHG
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H
END

View File

@@ -0,0 +1,414 @@
TITLE 'ASM TABLE SEARCH MODULE'
ORG 15A0H
JMP ENDMOD ;TO NEXT MODULE
JMP BSEAR
JMP BGET
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
CR EQU 0DH ;CARRIAGE RETURN
;
;
; TABLE DEFINITIONS
;
; TYPES
XBASE EQU 0 ;START OF OPERATORS
; O1 THROUGH O15 DENOTE OPERATIONS
RT EQU 16
PT EQU RT+1 ;RT IS REGISTER TYPE, PT IS PSEUDO OPERATION
OBASE EQU PT+1
O1 EQU OBASE+1 ;SIMPLE
O2 EQU OBASE+2 ;LXI
O3 EQU OBASE+3 ;DAD
O4 EQU OBASE+4 ;PUSH/POP
O5 EQU OBASE+5 ;JMP/CALL
O6 EQU OBASE+6 ;MOV
O7 EQU OBASE+7 ;MVI
O8 EQU OBASE+8 ;ACC IMMEDIATE
O9 EQU OBASE+9 ;LDAX/STAX
O10 EQU OBASE+10 ;LHLD/SHLD/LDA/STA
O11 EQU OBASE+11 ;ACCUM REGISTER
O12 EQU OBASE+12 ;INC/DEC
O13 EQU OBASE+13 ;INX/DCX
O14 EQU OBASE+14 ;RST
O15 EQU OBASE+15 ;IN/OUT
;
; X1 THROUGH X15 DENOTE OPERATORS
X1 EQU XBASE ;*
X2 EQU XBASE+1 ;/
X3 EQU XBASE+2 ;MOD
X4 EQU XBASE+3 ;SHL
X5 EQU XBASE+4 ;SHR
X6 EQU XBASE+5 ;+
X7 EQU XBASE+6 ;-
X8 EQU XBASE+7 ;UNARY -
X9 EQU XBASE+8 ;NOT
X10 EQU XBASE+9 ;AND
X11 EQU XBASE+10;OR
X12 EQU XBASE+11;XOR
X13 EQU XBASE+12;(
X14 EQU XBASE+13;)
X15 EQU XBASE+14;,
X16 EQU XBASE+15;CR
;
;
;
;
; RESERVED WORD TABLES
;
; BASE ADDRESS VECTOR FOR CHARACTERS
CINX: DW CHAR1 ;LENGTH 1 BASE
DW CHAR2 ;LENGTH 2 BASE
DW CHAR3 ;LENGTH 3 BASE
DW CHAR4 ;LENGTH 4 BASE
DW CHAR5 ;LENGTH 5 BASE
DW CHAR6 ;LENGTH 6 BASE
;
CMAX EQU ($-CINX)/2-1 ;LARGEST STRING TO MATCH
;
CLEN: ;LENGTH VECTOR GIVES THE NUMBER OF ITEMS IN EACH TABLE
DB CHAR2-CHAR1
DB (CHAR3-CHAR2)/2
DB (CHAR4-CHAR3)/3
DB (CHAR5-CHAR4)/4
DB (CHAR6-CHAR5)/5
;
TVINX: ;TABLE OF TYPE,VALUE PAIRS FOR EACH RESERVED SYMBOL
DW TV1
DW TV2
DW TV3
DW TV4
DW TV5
;
; CHARACTER VECTORS FOR 1,2,3,4, AND 5 CHARACTER NAMES
CHAR1: DB CR,'()*'
DB '+'
DB ',-/A'
DB 'BCDE'
DB 'HLM'
;
CHAR2: DB 'DBDIDSDW'
DB 'EIIFINOR'
DB 'SP'
;
CHAR3: DB 'ACIADCADDADI'
DB 'ANAANDANICMA'
DB 'CMCCMPCPIDAA'
DB 'DADDCRDCXEND'
DB 'EQUHLTINRINX'
DB 'JMPLDALXIMOD'
DB 'MOVMVINOPNOT'
DB 'ORAORGORIOUT'
DB 'POPPSWRALRAR'
DB 'RETRLCRRCRST'
DB 'SBBSBISETSHL'
DB 'SHRSTASTCSUB'
DB 'SUIXORXRAXRI'
;
CHAR4: DB 'CALLENDMLDAXLHLDPCHL'
DB 'PUSHSHLDSPHLSTAX'
DB 'XCHGXTHL'
;
CHAR5: DB 'ENDIFMACROTITLE'
;
CHAR6: ;END OF CHARACTER VECTOR
;
TV1: ;TYPE,VALUE PAIRS FOR CHAR1 VECTOR
DB X16,10, X13,20 ;CR (
DB X14,30, X1,80 ;) *
DB X6,70 ;+
DB X15,10, X7,70 ;, -
DB X2,80, RT,7 ;/ A
DB RT,0, RT,1 ;B C
DB RT,2, RT,3 ;D E
DB RT,4, RT,5 ;H L
DB RT,6 ;M
;
TV2: ;TYPE,VALUE PAIRS FOR CHAR2 VECTOR
DB PT,1, O1,0F3H ;DB DI
DB PT,2, PT,3 ;DS DW
DB O1,0FBH, PT,8 ;EI IF
DB O15,0DBH, X11,40 ;IN OR
DB RT,6 ;SP
;
;
TV3: ;TYPE,VALUE PAIRS FOR CHAR3 VECTOR
DB O8,0CEH, O11,88H ;ACI ADC
DB O11,80H, O8,0C6H ;ADD ADI
DB O11,0A0H, X10,50 ;ANA AND
DB O8,0E6H, O1,2FH ;ANI CMA
DB O1,3FH, O11,0B8H ;CMC CMP
DB O8,0FEH, O1,27H ;CPI DAA
DB O3,09H, O12,05H ;DAD DCR
DB O13,0BH, PT,4 ;DCX END
DB PT,7, O1,76H ;EQU HLT
DB O12,04H, O13,03H ;INR INX
DB O5,0C3H, O10,3AH ;JMP LDA
DB O2,01H, X3,80 ;LXI MOD
DB O6,40H, O7,06H ;MOV MVI
DB O1,00H, X9,60 ;NOP NOT
DB O11,0B0H, PT,10 ;ORA ORG
DB O8,0F6H, O15,0D3H ;ORI OUT
DB O4,0C1H, RT,6 ;POP PSW
DB O1,17H, O1,1FH ;RAL RAR
DB O1,0C9H, O1,07H ;RET RLC
DB O1,0FH, O14,0C7H ;RRC RST
DB O11,098H, O8,0DEH ;SBB SBI
DB PT,11, X4,80 ;SET SHL
DB X5,80, O10,32H ;STA STC
DB O1,37H, O11,90H ;STC SUB
DB O8,0D6H, X12,40 ;SUI XOR
DB O11,0A8H, O8,0EEH ;XRA XRI
;
;
TV4: ;TYPE,VALUE PAIRS FOR CHAR4 VECTOR
DB O5,0CDH ;CALL
DB PT,6, O9,0AH ;ENDM LDAX
DB O10,02AH, O1,0E9H ;LHLD PCHL
DB O4,0C5H, O10,22H ;PUSH SHLD
DB O1,0F9H, O9,02H ;SPHL STAX
DB O1,0EBH, O1,0E3H ;XCHG XTHL
;
TV5: ;TYPE,VALUE PAIRS FOR CHAR5 VECTOR
DB PT,5, PT,9 ;ENDIF MACRO
DB PT,12 ;TITLE
;
SUFTAB: ;TABLE OF SUFFIXES FOR J C AND R OPERATIONS
DB 'NZZ NCC POPEP M '
;
BSEAR: ;BINARY SEARCH MNEMONIC TABLE
; INPUT: UR = UPPER BOUND OF TABLE (I.E., TABLE LENGTH-1)
; SR = SIZE OF EACH TABLE ELEMENT
; H,L ADDRESS BASE OF TABLE TO SEARCH
; OUTPUT: ZERO FLAG INDICATES MATCH WAS FOUND, IN WHICH CASE
; THE ACCUMULATOR CONTAINS AN INDEX TO THE ELEMENT
; NOT ZERO FLAG INDICATES NO MATCH FOUND IN TABLE
;
UR EQU B ;UPPER BOUND REGISTER
LR EQU C ;LOWER BOUND REGISTER
SR EQU D ;SIZE REGISTER
MR EQU E ;MIDDLE POINTER REGISTER
SP1 EQU B ;SIZE PRIME, USED IN COMPUTING MIDDLE POSITON
SP1P EQU C ;ANOTHER COPY OF SIZE PRIME
KR EQU H ;K
;
MVI MR,255 ;MARK M <> OLD M
INR UR ;U=U+1
MVI LR,0 ;L = 0
;
; COMPUTE M' = (U+L)/2
NEXT: XRA A
MOV A,UR ;CY=0, A=U
ADD LR ;(U+L)
RAR ;(U+L)/2
CMP MR ;SAME AS LAST TIME THROUGH?
JZ NMATCH ;JUMP IF = TO NO MATCH
;
; MORE ELEMENTS TO SCAN
MOV MR,A ;NEW MIDDLE VALUE
PUSH H ;SAVE A COPY OF THE BASE ADDRESS
PUSH D ;SAVE S,M
PUSH B ;SAVE U,L
PUSH H ;SAVE ANOTHER COPY OF THE BASE ADDRESS
MOV SP1,SR ;S' = S
MOV SP1P,SP1 ;S'' = S'
MVI SR,0 ;FOR DOUBLE ADD OPERATION BELOW (DOUBLE M)
;
LXI KR,0 ;K=0
SUMK: DAD D ;K = K + M
DCR SP1 ;S' = S' - 1
JNZ SUMK ;DECREMENT IF SP1 <> 0
;
; K IS NOW RELATIVE BYTE POSITION
POP D ;TABLE BASE ADDRESS
DAD D ;H,L CONTAINS ABSOLUTE ADDRESS OF BYTE TO COMPARE
LXI D,ACCUM ;D,E ADDRESS CHARACTERS TO COMPARE
;
COMK: ;COMPARE NEXT CHARACTER
LDAX D ;ACCUM CHARACTER TO REG A
CMP M ;SAME AS TABLE ENTRY?
INX D
INX H ;TO NEXT POSITIONS
JNZ NCOM ;JUMP IF NOT THE SAME
DCR SP1P ;MORE CHARACTERS?
JNZ COMK
;
; COMPLETE MATCH AT M
POP B
POP D ;M RESTORED
POP H
MOV A,MR ;VALUE OF M COPIED IN A
RET ;WITH ZERO FLAG SET
;
NCOM: ;NO MATCH, DETERMINE IF LESS OR GREATER
POP B ;U,L
POP D ;S,M
POP H ;TABLE ADDRESS
JC NCOML
; ACCUM IS HIGHER
MOV LR,MR ;L = M
JMP NEXT
;
NCOML: ;ACCUMULATOR IS LOW
MOV UR,MR ;U = M
JMP NEXT
;
NMATCH: ;NO MATCH
XRA A
INR A ;SETS NOT ZERO FLAG
RET
;
PREFIX: ;J C OR R PREFIX?
LDA ACCUM
LXI B,(0C2H SHL 8) OR O5 ;JNZ OPCODE TO B, TYPE TO C
CPI 'J'
RZ ;RETURN WITH ZERO FLAG SET IF J
MVI B,0C4H ;CNZ OPCODE TO B, TYPE IS IN C
CPI 'C'
RZ
LXI B,(0C0H SHL 8) OR O1 ;RNZ OPCODE
CPI 'R'
RET
;
SUFFIX: ;J R OR C RECOGNIZED, LOOK FOR SUFFIX
LDA ACCLEN
CPI 4 ;CHECK LENGTH
JNC NSUFF ;CARRY IF 0,1,2,3 IN LENGTH
CPI 3
JZ SUF0 ;ASSUME 1 OR 2 IF NO BRANCH
CPI 2
JNZ NSUFF ;RETURNS IF 0 OR 1
LXI H,ACCUM+2
MVI M,' ' ;BLANK-OUT FOR MATCH ATTEMPT
SUF0: ;SEARCH 'TIL END OF TABLE
LXI B,8 ;B=0, C=8 COUNTS TABLE DOWN TO ZERO OR MATCH
LXI D,SUFTAB
NEXTS: ;LOOK AT NEXT SUFFIX
LXI H,ACCUM+1 ;SUFFIX POSITION
LDAX D ;CHARACTER TO ACCUM
CMP M
INX D ;READY FOR NEXT CHARACTER
JNZ NEXT0 ;JMP IF NO MATCH
LDAX D ;GET NEXT CHARACTER
INX H ;READY FOR COMPARE WITH ACCUM
CMP M ;SAME?
RZ ;RETURN WITH ZERO FLAG SET, B IS SUFIX
NEXT0: INX D ;MOVE TO NEXT CHARACTER
INR B ;COUNT SUFFIX UP
DCR C ;COUNT TABLE LENGTH DOWN
JNZ NEXTS
; END OF TABLE, MARK WITH NON ZERO FLAG
INR C
RET
;
NSUFF: ;NOT PROPER SUFFIX - SET NON ZERO FLAG
XRA A
INR A
RET
;
BGET: ;PERFORM BINARY SEARCH, AND EXTRACT TYPE AND VAL FIELDS FOR
; THE ITEM. ZERO FLAG INDICATES MATCH WAS FOUND, WITH TYPE
; IN THE ACCUMULATOR, AND VAL IN REGISTER B. THE SEARCH IS BASED
; UPON THE LENGTH OF THE ACCUMULATOR
LDA ACCLEN ;ITEM LENGTH
MOV C,A ;SAVE A COPY
DCR A ;ACCLEN-1
MOV E,A
MVI D,0 ;DOUBLE ACCLEN-1 TO D,E
PUSH D ;SAVE A COPY FOR LATER
CPI CMAX ;TOO LONG?
JNC NGET ;NOT IN RANGE IF CARRY
LXI H,CLEN ;LENGTH VECTOR
DAD D
MOV UR,M ;FILL UPPER BOUND FROM MEMORY
LXI H,CINX
DAD D
DAD D ;BASE ADDRESS TO H,L
MOV D,M
INX H
MOV H,M
MOV L,D ;NOW IN H,L
MOV SR,C ;FILL THE SIZE REGISTER
CALL BSEAR ;PERFORM THE BINARY SEARCH
JNZ SCASE ;ZERO IF FOUND
POP D ;RESTORE INDEX
LXI H,TVINX
DAD D
DAD D ;ADDRESSING PROPER TV ELEMENT
MOV E,M
INX H
MOV D,M
; D,E IS BASE ADDRESS OF TYPE/VALUE VECTOR, ADD DISPLACEMENT
MOV L,A
MVI H,0
DAD H ;DOUBLED
DAD D ;INDEXED
MOV A,M ;TYPE TO ACC
INX H
MOV B,M ;VALUE TO B
RET ;TYPE IN ACC, VALUE IN B
;
SCASE: ;NAME NOT TOO LONG, BUT NOT FOUND IN TABLES, MAY BE J C OR R
POP D ;RESTORE INDEX
CALL PREFIX
RNZ ;NOT FOUND AS PREFIX J C OR R IF NOT ZERO FLAG
PUSH B ;SAVE VALUE AND TYPE
CALL SUFFIX ;ZERO IF SUFFIX MATCHED
MOV A,B ;READY FOR MASK IF ZERO FLAG
POP B ;RECALL VALUE AND TYPE
RNZ ;RETURN IF NOT ZERO FLAG SET
; MASK IN THE PROPER BITS AND RETURN
ORA A ;CLEAR CARRY
RAL
RAL
RAL
ORA B ;VALUE SET TO JNZ ...
MOV B,A ;REPLACE
MOV A,C ;RETURN WITH TYPE IN REGISTER A
CMP A ;CLEAR THE ZERO FLAG
RET
;
NGET: ;CAN'T FIND THE ENTRY, RETURN WITH ZERO FLAG RESET
POP D ;GET THE ELEMENT BACK
XRA A ;CLEAR
INR A ;ZERO FLAG RESET
RET
;
;
ENDMOD EQU ($ AND 0FFE0H) + 20H ;NEXT MODULE ADDRESS
END

View File

@@ -0,0 +1,593 @@
TITLE 'ASM OPERAND SCAN MODULE'
; OPERAND SCAN MODULE
ORG 1860H
;
; EXTERNALS
IOMOD EQU 200H ;I/O MODULE
SCMOD EQU 1100H ;SCANNER MODULE
SYMOD EQU 1340H ;SYMBOL TABLE MODULE
BMOD EQU 15A0H ;BINARY SEARCH MODULE
;
;
PERR EQU IOMOD+18H
SCAN EQU SCMOD+6H ;SCANNER ENTRY POINT
CR EQU 0DH ;CARRIAGE RETURN
;
LOOKUP EQU SYMOD+6H ;LOOKUP
FOUND EQU LOOKUP+3 ;FOUND SYMBOL IF ZERO FLAG NOT SET
ENTER EQU FOUND+3 ;ENTER SYMBOL
SETTY EQU ENTER+3 ;SET TYPE FIELD
GETTY EQU SETTY+3 ;SET TYPE FIELD
SETVAL EQU GETTY+3 ;SET VALUE FIELD
GETVAL EQU SETVAL+3 ;GET VALUE FIELD
;
BSEAR EQU BMOD+3 ;BINARY SEARCH ROUTINE
BGET EQU BSEAR+3 ;GET VALUES WITH SEARCH
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
;
; TABLE DEFINITIONS
XBASE EQU 0 ;START OF OPERATORS
OPER EQU 15 ;LAST OPERATOR
RT EQU 16
PT EQU RT+1 ;RT IS REGISTER TYPE, PT IS PSEUDO OPERATION
OBASE EQU PT+1
;
PLUS EQU 5
MINUS EQU 6
NOTF EQU 8 ;NOT
LPAR EQU 12
RPAR EQU 13
OSMAX EQU 10
VSMAX EQU 8*2
;
;
; BEGINNING OF MODULE
JMP ENDMOD ;PAST THIS MODULE
JMP OPAND ;SCAN OPERAND FIELD
JMP MULF ;MULTIPLY FUNCTION
JMP DIVE ;DIVIDE FUNCTION
UNARY: DS 1 ;TRUE IF NEXT OPERATOR IS UNARY
OPERV: DS OSMAX ;OPERATOR STACK
HIERV: DS OSMAX ;OPERATOR PRIORITY
VSTACK: DS VSMAX ;VALUE STACK
OSP: DS 1 ;OPERATOR STACK POINTER
VSP: DS 1 ;VALUE STACK POINTER
;
;
;
STKV: ;PLACE CURRENT H,L VALUE AT TOP OF VSTACK
XCHG ;HOLD VALUE IN D,E
LXI H,VSP
MOV A,M
CPI VSMAX
JC STKV0
CALL ERREX ;OVERFLOW IN EXPRESSION
MVI M,0 ;VSP=0
STKV0: MOV A,M ;GET VSP
INR M ;VSP=VSP+1
INR M ;VSP=VSP+2
MOV C,A ;SAVE VSP
MVI B,0 ;DOUBLE VSP
LXI H,VSTACK
DAD B
MOV M,E ;LOW BYTE
INX H
MOV M,D ;HIGH BYTE
RET
;
STKO: ;STACK OPERATOR (REG-A) AND PRIORITY (REG-B)
PUSH PSW ;SAVE IT
LXI H,OSP
MOV A,M
CPI OSMAX
JC STKO1
MVI M,0
CALL ERREX ;OPERATOR STACK OVERFLOW
STKO1: MOV E,M ;GET OSP
MVI D,0
INR M ;OSP=OSP+1
POP PSW ;RECALL OPERATOR
LXI H,OPERV
DAD D ;OPERV(OSP)
MOV M,A ;OPERV(OSP)=OPERATOR
LXI H,HIERV
DAD D
MOV M,B ;HIERV(OSP)=PRIORITY
RET
;
LODV1: ;LOAD TOP ELEMENT FROM VSTACK TO H,L
LXI H,VSP
MOV A,M
ORA A
JNZ LODOK
CALL ERREX ;UNDERFLOW
LXI H,0
RET
;
LODOK: DCR M
DCR M ;VSP=VSP-2
MOV C,M ;LOW BYTE
MVI B,0
LXI H,VSTACK
DAD B ;VSTACK(VSP)
MOV C,M ;GET LOW BYTE
INX H
MOV H,M
MOV L,C
RET
;
LODV2: ;LOAD TOP TWO ELEMENTS DE HOLDS TOP, HL HOLDS TOP-1
CALL LODV1
XCHG
CALL LODV1
RET
;
APPLY: ;APPLY OPERATOR IN REG-A TO TOP OF STACK
MOV L,A
MVI H,0
DAD H ;OPERATOR NUMBER*2
LXI D,OPTAB
DAD D ;INDEXED OPTAB
MOV E,M ;LOW ADDRESS
INX H
MOV H,M ;HIGH ADDRESS
MOV L,E
PCHL ;SET PC AND GO TO SUBROUTINE
;
OPTAB: DW MULOP
DW DIVOP
DW MODOP
DW SHLOP
DW SHROP
DW ADDOP
DW SUBOP
DW NEGOP
DW NOTOP
DW ANDOP
DW OROP
DW XOROP
DW ERREX ;(
;
; SPECIFIC HANDLERS FOLLOW
SHFT: ;SET UP OPERANDS FOR SHIFT L AND R
CALL LODV2
MOV A,D ;ENSURE 0-15
ORA A
JNZ SHERR
MOV A,E
CPI 17
RC ;RETURN IF 0-16 SHIFT
SHERR: CALL ERREX
MVI A,16
RET
;
NEGF: ;COMPUTE 0-H,L TO H,L
XRA A
SUB L
MOV L,A
MVI A,0
SBB H
MOV H,A
RET
;
DIVF: CALL LODV2
DIVE: ;(EXTERNAL ENTRY FROM MAIN PROGRAM)
XCHG ;SWAP D,E WITH H,L FOR DIVIDE FUNCTION
; COMPUTE X/Y WHERE X IS IN D,E AND Y IS IN H,L
; THE VALUE OF X/Y APPEARS IN D,E AND X MOD Y IS IN H,L
;
SHLD DTEMP ;SAVE X IN TEMPORARY
LXI H,BNUM ;STORE BIT COUNT
MVI M,11H
LXI B,0 ;INTIALIZE RESULT
PUSH B
XRA A ;CLEAR FLAGS
DLOOP:
MOV A,E ;GET LOW Y BYTE
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
DCR M ;DECREMENT BIT COUNT
POP H ;RESTORE TEMP RESULT
RZ ;ZERO BIT COUNT MEANS ALL DONE
MVI A,0 ;ADD IN CARRY
ACI 0 ;CARRY
DAD H ;SHIFT TEMP RESULT LEFT ONE BIT
MOV B,H ;COPY HA AND L TO A A ND C
ADD L
LHLD DTEMP ;GET ADDRESS OF X
SUB L ;SUBTRACT FROM TEMPORARY RESULT
MOV C,A
MOV A,B
SBB H
MOV B,A
PUSH B ;SAVE TEMP RESULT IN STACK
JNC DSKIP ;NO BORROW FROM SUBTRACT
DAD B ;ADD X BACK IN
XTHL ;REPLACE TEMP RESULT ON STACK
DSKIP: LXI H,BNUM ;RESTORE H,L
CMC
JMP DLOOP ;REPEAT LOOP STEPS
;
DTEMP: DS 2
BNUM: DS 1
;
MULF: ;MULTIPLY D,E BY H,L AND REPLACE H,L WITH RESULT
MOV B,H
MOV C,L ;COPY OF 1ST VALUE TO B,C FOR SHIFT AND ADD
LXI H,0 ;H,L IS THE ACCUMULATOR
MUL0: XRA A
MOV A,B ;CARRY IS CLEARED
RAR
MOV B,A
MOV A,C
RAR
MOV C,A
JC MUL1 ;SKIP THIS ADD IF LSB IS ZERO
ORA B
RZ ;RETURN WITH H,L
JMP MUL2 ;SKIP ADD
MUL1: DAD D ;ADD CURRENT VALUE OF D
MUL2: XCHG ;READY FOR *2
DAD H
XCHG
JMP MUL0
;
MULOP: ;MULTIPLY D,E BY H,L
CALL LODV2
CALL MULF
JMP ENDOP
;
DIVOP: ;DIVIDE H,L BY D,E
CALL DIVF
XCHG ;RESULT TO H,L
JMP ENDOP
;
MODOP: CALL DIVF
JMP ENDOP
;
SHLOP: CALL SHFT ;CHECK VALUES
SHL0: ORA A ;DONE?
JZ ENDOP
DAD H ;HL=HL*2
DCR A
JMP SHL0
;
SHROP: CALL SHFT
SHR0: ORA A ;DONE?
JZ ENDOP
PUSH PSW ;SAVE CURRENT COUNT
XRA A
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
POP PSW
DCR A
JMP SHR0
;
ADDOP: CALL LODV2
ADD0: DAD D
JMP ENDOP
;
SUBOP: CALL LODV2
XCHG ;TREAT AS HL+(-DE)
CALL NEGF ;0-HL
JMP ADD0
;
NEGOP: CALL LODV1
NEG0: CALL NEGF ;COMPUTE 0-HL
JMP ENDOP
;
NOTOP: CALL LODV1
INX H ;65536-HL = 65535-(HL+1)
JMP NEG0
;
ANDOP: CALL LODV2
MOV A,D
ANA H
MOV H,A
MOV A,E
ANA L
MOV L,A
JMP ENDOP
;
OROP: CALL LODV2
MOV A,D
ORA H
MOV H,A
MOV A,E
ORA L
MOV L,A
JMP ENDOP
;
XOROP: CALL LODV2
MOV A,D
XRA H
MOV H,A
MOV A,E
XRA L
MOV L,A
;
ENDOP: JMP STKV
;
;
;
ENDEXP: ;RETURNS ZERO FLAG IF SYMBOL IS CR, ;, OR ,
LDA TOKEN
CPI SPECL
RNZ ;NOT END IF NOT SPECIAL
;
LDA ACCUM
CPI CR
RZ
CPI ';'
RZ
CPI ','
RZ
CPI '!'
RET
;
OPAND: ;SCAN THE OPERAND FIELD OF AN INSTRUCTION
; (NOT A DB WITH FIRST TOKEN STRING > 2 OR 0)
XRA A
STA OSP ;ZERO OPERATOR STACK POINTER
STA VSP
DCR A ;255
STA UNARY
LXI H,0
SHLD EVALUE
;
OP0: ;ARRIVE HERE WITH NEXT ITEM ALREADY SCANNED
CALL ENDEXP ;DONE?
JNZ OP1
; EMPTY THE OPERATOR STACK
EMPOP: LXI H,OSP
MOV A,M ;GET THE OSP AND CHECK FOR EMPTY
ORA A
JZ CHKVAL ;JUMP IF EMPTY
DCR M ;POP ELEMENT
MOV E,A ;COPY FOR DOUBLE ADD
DCR E
MVI D,0
LXI H,OPERV
DAD D ;INDEXED - OPERV(OSP)
MOV A,M ;GET OPERATOR
CALL APPLY ;APPLY OPERATOR
JMP EMPOP
;
CHKVAL:
LDA VSP ;MUST HAVE ONE ELEMENT IT THE STACK
CPI 2
CNZ ERREX
LDA PBUFF
CPI ' '
RNZ ;EVALUE REMAINS AT ZERO
LHLD VSTACK ;GET DOUBLE BYTE IN STACK
SHLD EVALUE
RET
;
OP1: ;MORE TO SCAN
LDA PBUFF
CPI ' '
JNZ GETOP
LDA TOKEN
CPI STRNG ;IS THIS A STRING?
JNZ OP3
;
; STRING - CONVERT TO DOUBLE PRECISION
LDA ACCLEN
ORA A
CZ ERREX ;ERROR IF LENGTH=0
CPI 3
CNC ERREX ;ERROR IF LENGTH>2
MVI D,0
LXI H,ACCUM
MOV E,M ;LSBYTE
INX H
DCR A ;A HAS THE LENGTH
JZ OP2 ;ONE OR TWO BYTES
MOV D,M ;FILL HIGH ORDER
OP2: XCHG ;VALUE TO H,L
JMP STNUM ;STORE TO STACK
;
OP3: ;NOT A STRING, CHECK FOR NUMBER
CPI NUMB
JNZ OP4
LHLD VALUE ;NUMERIC VALUE
JMP STNUM
;
OP4: ;NOT STRING OR NUMBER, MUST BE ID OR SPECL
CALL BGET ;BINARY SEARCH, GET ATTRIBUTES
JNZ OP6 ;MATCH?
; YES, MAY BE OPERATOR
CPI OPER+1
JNC OP5
; OPERATOR ENCOUNTERED MS NIBBLE OF B IS PRIORITY NUMBER LS NIBBLE
; IS THE OPERATOR
; ACC HAS THE OPERATOR NUMBER, B HAS PRIORITY
CPI LPAR ;(?
MOV C,A ;SAVE COPY OF OPERATOR NUMBER
LDA UNARY
JNZ OPER1 ;JUMP IF NOT A (
; ( ENCOUNTERED, UNARY MUST BE TRUE
ORA A
CZ ERREX
MVI A,0FFH
STA UNARY ;UNARY IS SET TRUE
MOV A,C ;RECOVER OPERATOR
JMP OPER4 ;CALLS STKO AND SETS UNARY TO TRUE
;
;
OPER1: ;NOT A LEFT PAREN
ORA A
JNZ OPER6 ;MUST BE + OR - SINCE UNARY IS SET
;
; UNARY NOT SET, MUST BE BINARY OPERATOR
OPER2: ;COMPARE HIERARCHY OF TOS
PUSH B ;SAVE PRIORITY AND OPERATOR NUMBER
LDA OSP
ORA A
JZ OPER3 ;NO MORE OPERATORS IN STACK
MOV E,A ;OSP TO E
DCR E ;OSP-1
MVI D,0
LXI H,HIERV
DAD D ;HL ADDRESSES TOP OF OPERATOR STACK
MOV A,M ;PRIORITY OF TOP OPERATOR
CMP B ;CURRENT GREATER?
JC OPER3 ;JUMP IF SO
; APPLY TOP OPERATOR TO VALUE STACK
LXI H,OSP
MOV M,E ;OSP=OSP-1
LXI H,OPERV
DAD D
MOV A,M ;OPERATOR NUMBER TO ACC
CALL APPLY
POP B ;RESTORE OPERATOR NUMBER AND PRIORITY
JMP OPER2 ;FOR ANOTHER TEST
;
OPER3: ;ARRIVE HERE WHEN OPERATOR IS STACKED
; CHECK FOR RIGHT PAREN BALANCE
POP B ;OPERATOR NUMBER IN C, PRIORITY IN B
MOV A,C
CPI RPAR
JNZ OPER4 ;JUMP IF NOT A RIGHT PAREN
;
; RIGHT PAREN FOUND, STACK MUST CONTAIN LEFT PAREN TO DELETE
LXI H,OSP
MOV A,M
ORA A ;ZERO?
JZ LPERR ;PAREN ERROR IF SO
DCR A ;OSP-1
MOV M,A ;STORED TO MEMORY
MOV E,A
MVI D,0
LXI H,OPERV
DAD D
MOV A,M ;TOP OPERATOR IN REG-A
CPI LPAR
JZ NLERR ;JMP IF NO ERROR - PARENS BALANCE
LPERR: CALL ERREX
NLERR: ;ERROR REPORTING COMPLETE
XRA A
JMP OPER5 ;TO CLEAR UNARY FLAG
;
OPER4: ;ORDINARY OPERATOR
CALL STKO
MVI A,0FFH ;TO SET UNARY FLAG
OPER5: STA UNARY
JMP GETOP ;FOR ANOTHER ELEMENT
;
OPER6: ;UNARY SET, MUST BE + OR -
MOV A,C ;RECALL OPERATOR
CPI PLUS
JZ GETOP ;IGNORE UNARY PLUS
CPI MINUS
JNZ CHKNOT
INR A ;CHANGE TO UNARY MINUS
MOV C,A
JMP OPER2
CHKNOT: ;UNARY NOT SYMBOL?
CPI NOTF
CNZ ERREX
JMP OPER2
;
;
OP5: ;ELEMENT FOUND IN TABLE, NOT AN OPERATOR
CPI PT ;PSEUDO OPERATOR?
CZ ERREX ;ERROR IF SO
MOV L,B ;GET LOW VALUE TO L
MVI H,0 ;ZERO HIGH ORDER BYTE
JMP STNUM ;STORE IT
;
OP6: ;NOT FOUND IN TABLE SCAN, $?
LDA TOKEN
CPI SPECL
JNZ OP7
LDA ACCUM
CPI '$'
JZ CURPC ;USE CURRENT PC
CALL ERREX
LXI H,0
JMP STNUM
CURPC: LHLD ASPC ;GET CURRENT PC
JMP STNUM
;
OP7: ;NOT $, LOOK IT UP
CALL LOOKUP
CALL FOUND
JNZ FIDENT
; NOT FOUND IN SYMBOL TABLE, ENTER IF PASS 1
MVI A,'P'
CALL PERR
CALL ENTER ;ENTER SYMBOL WITH ZERO TYPE FIELD
JMP FIDE0
FIDENT: CALL GETTY ;TYPE TO H,L
ANI 111B
MVI A,'U'
CZ PERR
;
FIDE0:
CALL GETVAL ;VALUE TO H,L
;
STNUM: ;STORE H,L TO VALUE STACK
LDA UNARY
ORA A ;UNARY OPERATION SET
CZ ERREX ;OPERAND ENCOUNTERED WITH UNARY OFF
XRA A
STA UNARY ;SET TO OFF
CALL STKV ;STACK THE VALUE
;
GETOP: CALL SCAN
JMP OP0
;
ERREX: ;PUT 'E' ERROR IN OUTPUT BUFFER
PUSH H
MVI A,'E'
CALL PERR
POP H
RET
;
ENDMOD EQU ($ AND 0FFE0H) + 20H ;NEXT HALF PAGE
END

View File

@@ -0,0 +1,888 @@
TITLE 'ASM MAIN MODULE'
; CP/M RESIDENT ASSEMBLER MAIN PROGRAM
;
; COPYRIGHT (C) 1976, 1977, 1978
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE
; CALIFORNIA, 93950
;
;
ORG 1BA0H
; MODULE ENTRY POINTS
IOMOD EQU 200H ;IO MODULE
SCMOD EQU 1100H ;SCANNER MODULE
SYMOD EQU 1340H ;SYMBOL TABLE MODULE
BMOD EQU 15A0H ;BINARY SEARCH MODULE
OPMOD EQU 1860H ;OPERAND SCAN MODULE
;
SETUP EQU IOMOD+3H ;FILE SETUP FOR EACH PASS
PCON EQU IOMOD+12H ;WRITE CONSOLE BUFFER TO CR
WOBUFF EQU IOMOD+15H ;WRITE PRINT BUFFER AND REINITIALIZE
PERR EQU IOMOD+18H ;WRITE ERROR CHARACTER TO PRINT BUFFER
DHEX EQU IOMOD+1BH ;SEND HEX CHARACTER TO MACHINE CODE FILE
EOR EQU IOMOD+1EH ;END OF PROCESSING, CLOSE FILES AND TERMINATE
;
INITS EQU SCMOD+3H ;INITIALIZE SCANNER MODULE
SCAN EQU SCMOD+6H ;SCAN NEXT TOKEN
;
INISY EQU SYMOD+3H ;INITIALIZE SYMBOL TABLE
LOOKUP EQU SYMOD+6H ;LOOKUP SYMBOL IN ACCUMULATOR
FOUND EQU SYMOD+9H ;FOUND IF NZ FLAG
ENTER EQU SYMOD+0CH ;ENTER SYMBOL IN ACCUMULATOR
SETTY EQU SYMOD+0FH ;SET TYPE FIELD
GETTY EQU SYMOD+12H ;GET TYPE FIELD
SETVAL EQU SYMOD+15H ;SET VALUE FIELD
GETVAL EQU SYMOD+18H ;GET VALUE FIELD
;
BGET EQU BMOD+6H ;BINARY SEARCH AND GET TYPE/VALUE PAIR
;
OPAND EQU OPMOD+3H ;GET OPERAND VALUE TO 'EVALUE'
MULF EQU OPMOD+6H ;MULT D,E BY H,L TO H,L
DIVF EQU OPMOD+9H ;DIVIDE HL BY DE, RESULT TO DE
;
;
; COMMON EQUATES
PBMAX EQU 120 ;MAX PRINT SIZE
PBUFF EQU 10CH ;PRINT BUFFER
PBP EQU PBUFF+PBMAX ;PRINT BUFFER POINTER
;
TOKEN EQU PBP+1 ;CURRENT TOKEN UDER SCAN
VALUE EQU TOKEN+1 ;VALUE OF NUMBER IN BINARY
ACCLEN EQU VALUE+2 ;ACCUMULATOR LENGTH
ACMAX EQU 64 ;MAX ACCUMULATOR LENGTH
ACCUM EQU ACCLEN+1
;
EVALUE EQU ACCUM+ACMAX ;VALUE FROM EXPRESSION ANALYSIS
;
SYTOP EQU EVALUE+2 ;CURRENT SYMBOL TOP
SYMAX EQU SYTOP+2 ;MAX ADDRESS+1
;
PASS EQU SYMAX+2 ;CURRENT PASS NUMBER
FPC EQU PASS+1 ;FILL ADDRESS FOR NEXT HEX BYTE
ASPC EQU FPC+2 ;ASSEMBLER'S PSEUDO PC
SYBAS EQU ASPC+2 ;BASE OF SYMBOL TABLE
SYADR EQU SYBAS+2 ;CURRENT SYMBOL ADDRESS
;
; GLOBAL EQUATES
IDEN EQU 1 ;IDENTIFIER
NUMB EQU 2 ;NUMBER
STRNG EQU 3 ;STRING
SPECL EQU 4 ;SPECIAL CHARACTER
;
PLABT EQU 0001B ;PROGRAM LABEL
DLABT EQU 0010B ;DATA LABEL
EQUT EQU 0100B ;EQUATE
SETT EQU 0101B ;SET
MACT EQU 0110B ;MACRO
;
EXTT EQU 1000B ;EXTERNAL
REFT EQU 1011B ;REFER
GLBT EQU 1100B ;GLOBAL
;
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
EOF EQU 1AH ;END OF FILE
NBMAX EQU 16 ;STARTING POSITION OF PRINT LINE
;
;
RT EQU 16 ;REGISTER TYPE
PT EQU RT+1 ;PSEUDO OPERATION
PENDIF EQU 5 ;PSEUDO OPERATOR 'ENDIF'
OBASE EQU PT+1
O1 EQU OBASE+1 ;FIRST OPERATOR
O15 EQU OBASE+15;LAST OPERATOR
;
; MAIN STATEMENT PROCESSING LOOP
XRA A
STA PASS ;SET TO PASS 0 INITIALLY
CALL INISY ;INITIALIZE THE SYMBOL TABLE
RESTART: ;PASS LOOP GOES FROM 0 TO 1
CALL INITS ;INITIALIZE THE SCANNER
CALL SETUP ;SET UP THE INPUT FILE
LXI H,0
SHLD SYLAB ;ASSUME NO STARTING LABEL
SHLD FPC
SHLD ASPC
SHLD EPC ;END PC
;
SCNEXT: ;SCAN THE NEXT INPUT ITEM
CALL SCAN
SCN0: LDA TOKEN
CPI NUMB ;SKIP LEADING NUMBERS FROM LINE EDITORS
JZ SCNEXT
CPI SPECL ;MAY BE PROCESSOR TECH'S COMMENT
JNZ SCN1
; SPECIAL CHARACTER, CHECK FOR *
LDA ACCUM
CPI '*'
JNZ CHEND ;END OF LINE IF NOT *
; * FOUND, NO PRECEDING LABEL ALLOWED
CALL SETLA
JNZ STERR ;ERROR IF LABEL
JMP CHEN1 ;SCAN THE COMMENT OTHERWISE
;
SCN1: ;NOT NUMBER OR SPECIAL CHARACTER, CHECK FOR IDENTIFIER
CPI IDEN
JNZ STERR ;ERROR IF NOT
;
; IDENTIFIER FOUND, MAY BE LABEL, OPCODE, OR MACRO
CALL BGET ;BINARY SEARCH FIXED DATA
JZ CHKPT ;CHECK FOR PSEUDO OR REAL OPERATOR
;
; BINARY SEARCH WAS UNSUCCESSFUL, CHECK FOR MACRO
CALL LOOKUP
CALL FOUND
JNZ LFOUN ;NZ FLAG SET IF FOUND
;
; NOT FOUND, ENTER IT
CALL ENTER ;THIS MUST BE PASS 0
LDA PASS
ORA A
CNZ ERRP ;PHASE ERROR IF NOT
JMP SETSY ;SET SYLAB
;
; ITEM WAS FOUND, CHECK FOR MACRO
LFOUN: CALL GETTY
CPI MACT
JNZ SETSY
;
; MACRO DEFINITION FOUND, EXPAND MACRO
CALL ERRN ;NOT CURRENTLY IMPLEMENTED
JMP CHEN1 ;SCANS TO END OF CURRENT LINE
;
SETSY: ;LABEL FOUND - IS IT THE ONLY ONE?
LHLD SYLAB
MOV A,L
ORA H
CNZ ERRL ;LABEL ERROR IF NOT
LHLD SYADR ;ADDRESS OF SYMBOL
SHLD SYLAB ;MARK AS LABEL FOUND
;
; LABEL FOUND, SCAN OPTIONAL ':'
CALL SCAN
LDA TOKEN
CPI SPECL
JNZ SCN0 ;SKIP NEXT SCAN IF NOT SPECIAL
LDA ACCUM
CPI ':'
JNZ SCN0
JMP SCNEXT ;TO IGNORE ':'
;
; BINARY SEARCH FOUND SYMBOL, CHECK FOR PSEUDO OR REAL OP
CHKPT: CPI PT ;PSEUDO OPCODE?
JNZ CHKOT
;
; PSEUDO OPCODE FOUND, BRANCH TO CASES
MOV E,B ;B HAS PARTICULAR OPERATOR NUMBER
MVI D,0 ;DOUBLE PRECISION VALUE TO D,E
DCX D ;BIASED BY +1
LXI H,PTTAB ;BASE OF JUMP TABLE
DAD D
DAD D
MOV E,M
INX H
MOV H,M
MOV L,E
PCHL ;JUMP INTO TABLE
;
PTTAB: ;PSEUDO OPCODE JUMP TABLE
DW SDB ;DB
DW SDS ;DS
DW SDW ;DW
DW SEND ;END
DW SENDIF ;ENDIF
DW SENDM ;ENDM
DW SEQU ;EQU
DW SIF ;IF
DW SMACRO ;MACRO
DW SORG ;ORG
DW SSET ;SET
DW STITLE ;TITLE
;
SDB:
CALL FILAB ;SET LABEL FOR THIS LINE TO ASPC
SDB0:
CALL SCAN ;PAST DB TO NEXT ITEM
LDA TOKEN ;LOOK FOR LONG STRING
CPI STRNG
JNZ SDBC ;SKIP IF NOT STRING
LDA ACCLEN
DCR A ;LENGTH 1 STRING?
JZ SDBC
; LENGTH 0,2,... STRING
MOV B,A
INR B
INR B ;BECOMES 1,3,... FOR 0,2,... LENGTHS
LXI H,ACCUM ;ADDRESS CHARACTERS IN STRING
SDB1: DCR B ;COUNT DOWN TO ZERO
JZ SDB2 ;SCAN DELIMITER AT END OF STRING
PUSH B ;SAVE COUNT
MOV B,M ;GET CHARACTER
INX H
PUSH H ;SAVE ACCUM POINTER
CALL FILHB ;SEND TO HEX FILE
POP H
POP B
JMP SDB1
SDB2: CALL SCAN ;TO THE DELIMITER
JMP SDB3
;
; NOT A LONG STRING
SDBC: CALL OPAND ;COMPUTE OPERAND
LHLD EVALUE ;VALUE TO H,L
MOV A,H
ORA A ;HIGH ORDER MUST BE ZERO
CNZ ERRD ;DATA ERROR
MOV B,L ;GET LOW BYTE
CALL FILHB
SDB3: ;END OF ITEM - UPDATE ASPC
CALL SETAS ;SET ASPC TO FPC
CALL DELIM
CPI ','
JZ SDB0 ;FOR ANOTHER ITEM
JMP CHEND ;CHECK END OF LINE SYNTAX
;
SDS:
CALL FILAB ;HANDLE LABEL IF IT OCCURRED
CALL PADD ;PRINT ADDRESS
CALL EXP16 ;SCAN AND GET 16BIT OPERAND
XCHG ;TO D,E
LHLD ASPC ;CURRENT PSEUDO PC
DAD D ;+EXPRESSION
SHLD ASPC
SHLD FPC ;NEXT TO FILL
JMP CHEND
;
SDW:
CALL FILAB ;HANDLE OPTIONAL LABEL
SDW0:
CALL EXP16 ;GET 16BIT OPERAND
PUSH H ;SAVE A COPY
MOV B,L ;LOW BYTE FIRST
CALL FILHB ;SEND LOW BYTE
POP H ;RECLAIM A COPY
MOV B,H ;HIGH BYTE NEXT
CALL FILHB ;SEND HIGH BYTE
CALL SETAS ;SET ASPC=FPC
CALL DELIM ;CHECK DELIMITER SYNTAX
CPI ','
JZ SDW0 ;GET MORE DATA
JMP CHEND
;
SEND:
CALL FILAB
CALL PADD ;WRITE LAST LOC
LDA PBUFF
CPI ' '
JNZ CHEND
CALL EXP16 ;GET EXPRESSION IF IT'S THERE
LDA PBUFF
CPI ' '
JNZ SEND0
SHLD EPC ;EXPRESSION FOUND, STORE IT FOR LATER
SEND0: MVI A,' '
STA PBUFF ;CLEAR ERROR, IF IT OCCURRED
CALL SCAN ;CLEAR CR
LDA TOKEN
CPI SPECL
JNZ STERR
LDA ACCUM
CPI LF
JNZ STERR
JMP ENDAS ;END OF ASSEMBLER
;
SENDIF:
JMP POEND
;
SENDM:
CALL ERRN
JMP POEND
;
SEQU:
CALL SETLA
JZ STERR ;MUST BE A LABEL
LHLD ASPC ;HOLD TEMP ASPC
PUSH H ;IN STACK
CALL EXP16 ;GET 16BIT OPERAND
SHLD ASPC ;VALUE OF EXPRESSION
CALL FILAB
CALL PADDR ;COMPUTED VALUE
LXI H,PBUFF+6 ;SPACE AFTER VALUE
MVI M,'='
POP H ;REAL ASPC
SHLD ASPC ;CHANGE BACK
JMP CHEND
;
SIF:
CALL FILAB ;IN CASE OF LABEL
CALL EXP16 ;GET IF EXPRESSION
LDA PBUFF
CPI ' '
JNZ CHEND ;SKIP IF ERROR
MOV A,L ;GET LSB
RAR
JC CHEND ;TRUE IF CARRY BIT SET
;
; SKIP TO EOF OR ENDIF
SIF0: CALL SCAN
LDA TOKEN
CPI SPECL
JNZ SIF1
LDA ACCUM
CPI EOF
MVI A,'B' ;BALANCE ERROR
CZ PERR
JZ ENDAS
JMP SIF0 ;FOR ANOTHER
SIF1: ;NOT A SPECIAL CHARACTER
CPI IDEN
JNZ SIF0 ;NOT AN IDENTIFIER
CALL BGET ;LOOK FOR ENDIF
JNZ SIF0 ;NOT FOUND
CPI PT ;PSEUDO OP?
JNZ SIF0
MOV A,B ;GET OPERATOR NUMBER
CPI PENDIF ;ENDIF?
JNZ SIF0 ;GET ANOTHER TOKEN
JMP POEND ;OK, CHECK END OF LINE
;
SMACRO:
CALL ERRN
JMP CHEND
;
SORG:
CALL EXP16
LDA PBUFF
CPI ' '
JNZ CHEND ;SKIP ORG IF ERROR
SHLD ASPC ;CHANGE PC
SHLD FPC ;CHANGE NEXT TO FILL
CALL FILAB ;IN CASE OF LABEL
CALL PADD
JMP CHEND
;
SSET:
CALL SETLA
JZ STERR ;MUST BE LABELLED
;
CALL GETTY
CPI SETT
CNZ ERRL ;LABEL ERROR
MVI A,SETT
CALL SETTY ;REPLACE TYPE WITH 'SET'
CALL EXP16 ;GET THE EXPRESSION
PUSH H ;SAVE IT
CALL SETLA ;RE-ADDRESS LABEL
POP H ;RECLAIM IT
CALL SETVAL
LXI H,0
SHLD SYLAB ;PREVENT LABEL PROCESSING
JMP CHEND
;
;
STITLE:
CALL ERRN ;NOT IMPLEMENTED
;
POEND: ;PSEUDO OPERATOR END - SCAN TO NEXT TOKEN
CALL SCAN
JMP CHEND
;
; NOT A PSEUDO OPCODE, CHECK FOR REAL OPCODE
CHKOT: SUI O1 ;BASE OF OPCODES
CPI O15 ;PAST LAST OPCODE?
JNC STERR ;STATEMENT ERROR IF SO
;
; FOUND OPCODE, COMPUTE INDEX INTO TABLE AND JUMP TO CASE
MOV E,A
MVI D,0
LXI H,OPTAB
DAD D
DAD D
MOV E,M
INX H
MOV H,M
MOV L,E
PCHL ;JUMP TO CASE
;
OPTAB: ;OPCODE CATEGORIES
DW SSIMP ;SIMPLE
DW SLXI ;LXI
DW SDAD ;DAD
DW SPUSH ;PUSH/POP
DW SJMP ;JMP/CALL
DW SMOV ;MOV
DW SMVI ;MVI
DW SACCI ;ACCUM IMMEDIATE
DW SLDAX ;LDAX/STAX
DW SLHLD ;LHLD/SHLD/LDA/STA
DW SACCR ;ACCUM-REGISTER
DW SINC ;INC/DCR
DW SINX ;INX/DCX
DW SRST ;RESTART
DW SIN ;IN/OUT
;
SSIMP: ;SIMPLE OPERATION CODES
CALL FILHB ;SEND HEX VALUE TO MACHINE CODE FILE
CALL SCAN ;TO NEXT TOKEN
JMP INCPC
;
SLXI: ;LXI H,16B
CALL SHDREG ;SCAN DOUBLE PRECISION REGISTER
CALL CHCOM ;CHECK FOR COMMA FOLLOWING REGISTER
CALL SETADR ;SCAN AND EMIT DOUBLE PRECISION OPERAND
JMP INCPC
;
SDAD: ;DAD B
CALL SHDREG ;SCAN AND EMIT DOUBLE PRECISION REGISTER
JMP INCPC
;
SPUSH: ;PUSH B POP D
CALL SHREG ;SCAN SINGLE PRECISION REGISTER TO A
CPI 111000B ;MAY BE PSW
JZ SPU0
; NOT PSW, MUST BE B,D, OR H
ANI 001000B ;LOW BIT MUST BE 0
CNZ ERRR ;REGISTER ERROR IF NOT
SPU0: MOV A,C ;RECALL REGISTER AND MASK IN CASE OF ERROR
ANI 110000B
ORA B ;MASK IN OPCODE FOR PUSH OR POP
JMP FILINC ;FILL HEX VALUE AND INCREMENT PC
;
SJMP: ;JMP 16B/ CALL 16B
CALL FILHB ;EMIT JMP OR CALL OPCODE
CALL SETADR ;EMIT 16BIT OPERAND
JMP INCPC
;
SMOV: ;MOV A,B
CALL SHREG
ORA B ;MASK IN OPCODE
MOV B,A ;SAVE IN B TEMPORARILY
CALL CHCOM ;MUST BE COMMA SEPARATOR
CALL EXP3 ;VALUE MUST BE 0-7
ORA B ;MASK IN OPCODE
JMP FILINC
;
SMVI: ;MVI A,8B
CALL SHREG
ORA B ;MASK IN OPCODE
CALL FILHEX ;EMIT OPCODE
CALL CHCOM ;SCAN COMMA
CALL SETBYTE ;EMIT 8BIT VALUE
JMP INCPC
;
SACCI: ;ADI 8B
CALL FILHB ;EMIT IMMEDIATE OPCODE
CALL SETBYTE ;EMIT 8BIT OPERAND
JMP INCPC
;
SLDAX: ;LDAX B/STAX D
CALL SHREG
ANI 101000B ;MUST BE B OR D
CNZ ERRR ;REGISTER ERROR IF NOT
MOV A,C ;RECOVER REGISTER NUMBER
ANI 010000B ;CHANGE TO B OR D IF ERROR
ORA B ;MASK IN OPCODE
JMP FILINC ;EMIT OPCODE
;
SLHLD: ;LHLD 16B/ SHLD 16B/ LDA 16B/ STA 16B
CALL FILHB ;EMIT OPCODE
CALL SETADR ;EMIT OPERAND
JMP INCPC
;
SACCR: ;ADD B
CALL EXP3 ;RIGHT ADJUSTED 3BIT VALUE FOR REGISTER
ORA B ;MASK IN OPCODE
JMP FILINC
;
SINC: ;INR B/DCR D
CALL SHREG ;GET REGISTER
ORA B
JMP FILINC
;
SINX: ;INX H/DCX B
CALL SHREG
ANI 001000B ;MUST BE B D M OR SP
CNZ ERRR ;REGISTER ERROR IF NOT
MOV A,C ;RECOVER REGISTER
ANI 110000B ;IN CASE OF ERROR
ORA B ;MASK IN OPCODE
JMP FILINC
;
SRST: ;RESTART 4
CALL SHREG ;VALUE IS 0-7
ORA B ;OPCODE MASKED
JMP FILINC
;
SIN: ;IN 8B/OUT 8B
CALL FILHB ;EMIT OPCODE
CALL SETBYTE ;EMIT 8BIT OPERAND
JMP INCPC
;
FILINC: ;FILL HEX VALUE FROM A BEFORE INCREMENTING PC
CALL FILHEX
;
INCPC: ;CHANGE ASSEMBLER'S PSEUDO PROGRAM COUNTER
CALL FILAB ;SET ANY LABELS WHICH OCCUR ON THE LINE
CALL SETAS ;ASPC=FPC
JMP CHEND ;END OF LINE SCAN
;
;
; UTILITY SUBROUTINES FOR OPERATION CODES
;
DELIM: ;CHECK DELIMITER SYNTAX FOR DATA STATEMENTS
LDA TOKEN
CPI SPECL
CNZ ERRD
LDA ACCUM
CPI ','
RZ
CPI ';'
RZ
CPI CR
CNZ ERRD
RET
;
EXP16: ;GET 16BIT VALUE TO H,L
PUSH B
CALL SCAN ;START SCANNING OPERAND FIELD
CALL OPAND
LHLD EVALUE ;VALUE TO H,L
POP B
RET
;
EXP8: ;GET 8BIT VALUE TO REG A
CALL EXP16
MOV A,H
ORA A
CNZ ERRV ;VALUE ERROR IF HIGH BYTE NOT ZERO
MOV A,L
RET
;
EXP3: ;GET 3BIT VALUE TO REG A
CALL EXP8
CPI 8
CNC ERRV ;VALUE ERROR IF >=8
ANI 111B ;REDUCE IF ERROR OCCURS
RET
;
SHREG: ;GET 3BIT VALUE AND SHIFT LEFT BY 3
CALL EXP3
RAL
RAL
RAL
ANI 111000B
MOV C,A ;COPY TO C
RET
;
SHDREG: ;GET DOUBLE REGISTER TO A
CALL SHREG
ANI 001000B ;CHECK FOR A,C,E, OR L
CNZ ERRR ;REGISTER ERROR
MOV A,C ;RECOVER REGISTER
ANI 110000B ;FIX IT IF ERROR OCCURRED
ORA B ;MASK OPCODE
JMP FILHEX ;EMIT IT
;
SETBYTE: ;EMIT 16BIT OPERAND
CALL EXP8
JMP FILHEX
;
SETADR: ;EMIT 16BIT OPERAND
CALL EXP16
JMP FILADR
;
CHCOM: ;CHECK FOR COMMA FOLLOWING EXPRESSION
PUSH PSW
PUSH B
LDA TOKEN
CPI SPECL
JNZ COMER
; SPECIAL CHARACTER, CHECK FOR COMMA
LDA ACCUM
CPI ','
JZ COMRET ;RETURN IF COMMA FOUND
COMER: ;COMMA ERROR
MVI A,'C'
CALL PERR
COMRET:
POP B
POP PSW
RET
;
CHEND: ;END OF LINE CHECK
CALL FILAB ;IN CASE OF A LABEL
LDA TOKEN
CPI SPECL
JNZ STERR ;MUST BE A SPECIAL CHARACTER
LDA ACCUM
CPI CR ;CARRIAGE RETURN
JNZ CHEN0
; CARRIAGE RETURN FOUND, SCAN PICKS UP LF AND PUSHES LINE
CALL SCAN
JMP SCNEXT
;
CHEN0: ;NOT CR, CHECK FOR COMMENT
CPI ';'
JNZ CHEN2
CALL FILAB ;IN CASE LABELLED EMPTY LINE
; CLEAR COMMENT TO END OF LINE
CHEN1: CALL SCAN
LDA TOKEN
CPI SPECL
JNZ CHEN1
LDA ACCUM
CPI LF
JZ SCNEXT
CPI EOF
JZ ENDAS ;END OF ASSEMBLY IF EOF
CPI '!'
JZ SCNEXT ;LOGICAL END OF LINE
JMP CHEN1 ;NONE OF THE ABOVE
;
; NOT CR OR LF, MAY BE LOGICAL END OF LINE
CHEN2: CPI '!'
JZ SCNEXT
CPI EOF
JZ ENDAS
;
; STATEMENT ERROR IN OPERAND FIELD
STERR: MVI A,'S'
CALL PERR
JMP CHEN1 ;TO DUMP LINE
;
DIFF: ;COMPUTE DE-HL TO HL
MOV A,E
SUB L
MOV L,A
MOV A,D
SBB H
MOV H,A
RET
;
ENDAS: ;END OF ASSEMBLY FOR THIS PASS
LXI H,PASS
MOV A,M
INR M ;PASS NUMBER INCREMENTED
ORA A
JZ RESTART
CALL SCAN ;TO CLEAR LAST LINE FEED
CALL PADD ;WRITE LAST ADDRESS
LXI H,PBUFF+5
MVI M,CR ;SET TO CR FOR END OF MESSAGE
LXI H,PBUFF+1
CALL PCON ;PRINT LAST ADDRESS
;
; COMPUTE REMAINING SPACE
LHLD SYTOP
XCHG
LHLD SYBAS
CALL DIFF ;DIFFERENCE TO H,L
PUSH H ;SYTOP-SYBAS TO STACK
LHLD SYMAX
XCHG
LHLD SYBAS
CALL DIFF ;SYMAX-SYBAS TO H,L
MOV E,H
MVI D,0 ;DIVIDED BY 256
POP H ;SYTOP-SYBAS TO H,L
CALL DIVF ;RESULT TO DE
XCHG
CALL PADDR ;PRINT H,L TO PBUFF
LXI H,PBUFF+5 ;MESSAGE
LXI D,EMSG ;END MESSAGE
ENDA0: LDAX D
ORA A ;ZERO?
JZ ENDA1
MOV M,A
INX H
INX D
JMP ENDA0
;
EMSG: DB 'H USE FACTOR',CR,0
;
ENDA1: LXI H,PBUFF+2 ;BEGINNING OF RATIO
CALL PCON
LHLD EPC
SHLD FPC ;END PROGRAM COUNTER
JMP EOR
;
; UTILITY SUBROUTINES
COMDH: ;COMPARE D,E WITH H,L FOR EQUALITY (NZ FLAG IF NOT EQUAL)
MOV A,D
CMP H
RNZ
MOV A,E
CMP L
RET
;
SETAS: ;ASPC=FPC
LHLD FPC
SHLD ASPC
RET
;
SETLA: ;SYADR=SYLAB, FOLLOWED BY CHECK FOR ZERO
LHLD SYLAB
SHLD SYADR
CALL FOUND
RET
;
FILAB: ;FILL LABEL VALUE WITH CURRENT ASPC, IF LABEL FOUND
CALL SETLA
RZ ;RETURN IF NO LABEL DETECTED
;
; LABEL FOUND, MUST BE DEFINED ON PASS-1
LXI H,0
SHLD SYLAB ;TO MARK NEXT STATEMENT WITH NO LABEL
LDA PASS
ORA A
JNZ FIL1
;
; PASS 0
CALL GETTY
PUSH PSW ;SAVE A COPY OF TYPE
ANI 111B ;CHECK FOR UNDEFINED
CNZ ERRL ;LABEL ERROR
POP PSW ;RESTORE TYPE
ORI PLABT ;SET TO LABEL TYPE
CALL SETTY ;SET TYPE FIELD
LHLD ASPC ;GET CURRENT PC
CALL SETVAL ;PLACE INTO VALUE FIELD
RET
;
FIL1: ;CHECK FOR DEFINED VALUE
CALL GETTY
ANI 111B
CZ ERRP ;PHASE ERROR
; GET VALUE AND COMPARE WITH ASPC
CALL GETVAL ;TO H,L
XCHG
LHLD ASPC
CALL COMDH
CNZ ERRP ;PHASE ERROR IF NOT THE SAME
RET
;
FILHEX: ;WRITE HEX BYTE IN REGISTER A TO MACHINE CODE FILE IF PASS-1
MOV B,A
FILHB: LDA PASS
ORA A
MOV A,B
JZ FILHI
;
; PASS - 1, WRITE HEX AND PRINT DATA
PUSH B ;SAVE A COPY
CALL DHEX ;INTO MACHINE CODE FILE
; MAY BE COMPLETELY EMPTY LINE, SO CHECK ADDRESS
LDA PBUFF+1
CPI ' '
LHLD ASPC
CZ PADDR ;PRINT ADDRESS FIELD
;
LDA NBP
CPI NBMAX ;TRUNCATE CODE IF TOO MUCH ON THIS LINE
POP B ;RECALL HEX DIGIT
JNC FILHI
; ROOM FOR DIGIT ON THIS LINE
MOV A,B
CALL WHEXB ;WRITE HEX BYTE TO PRINT LINE
FILHI: LHLD FPC
INX H
SHLD FPC ;READY FOR NEXT BYTE
RET
;
FILADR: ;EMIT DOUBLE PRECISION VALUE FROM H,L
PUSH H ;SAVE A COPY
MOV B,L
CALL FILHB ;LOW BYTE EMITTED
POP H ;RECOVER A COPY OF H,L
MOV B,H
JMP FILHB ;EMIT HIGH BYTE AND RETURN
;
; UTILITY FUNCTIONS FOR PRINTING HEX ADDRESSES AND DATA
CHEX: ;CONVERT TO HEX
ADI '0'
CPI '0'+10
RC
ADI 'A'-'0'-10
RET
;
WHEXN: ;WRITE HEX NIBBLE
CALL CHEX ;CONVERT TO ASCII FROM HEX
LXI H,NBP
MOV E,M ;NEXT POSITION TO PRINT
MVI D,0 ;DOUBLE PRECISION
INR M ;NBP=NBP+1
LXI H,PBUFF
DAD D
MOV M,A ;STORE IN PRINT BUFFER
RET
;
WHEXB: ;WRITE HEX BYTE TO PRINT BUFFER
PUSH PSW
RAR
RAR
RAR
RAR
ANI 0FH ;HIGH ORDER NIBBLE NORMALIZE IN A
CALL WHEXN ;WRITE IT
POP PSW
ANI 0FH
JMP WHEXN ;WRITE AND RETURN
;
PADD: LHLD ASPC
PADDR: ;PRINT ADDRESS FIELD OF PRINT LINE FROM H,L
XCHG
LXI H,NBP ;INITIALIZE NEXT TO FILL
PUSH H ;SAVE A COPY OF NBP'S ADDRESS
MVI M,1
MOV A,D ;PRINT HIGH BYTE
PUSH D ;SAVE A COPY
CALL WHEXB
POP D
MOV A,E
CALL WHEXB
POP H ;ADDRESSING NBP
INR M ;SKIP A SPACE AFTER ADDRESS FIELD
RET
;
ERRR: ;EMIT REGISTER ERROR
PUSH PSW
PUSH B
MVI A,'R'
CALL PERR
POP B
POP PSW
RET
;
ERRV: ;EMIT VALUE ERROR
PUSH PSW
PUSH H
MVI A,'V'
CALL PERR
POP H
POP PSW
RET
;
ERRD: PUSH PSW
MVI A,'D' ;DATA ERROR
JMP ERR
;
ERRP: PUSH PSW
MVI A,'P'
JMP ERR
;
ERRL: PUSH PSW
MVI A,'L' ;LABEL ERROR
JMP ERR
;
ERRN: PUSH PSW
MVI A,'N' ;NOT IMPLEMENTED
;
ERR:
CALL PERR
POP PSW
RET
;
SYLAB: DS 2 ;ADDRESS OF LINE LABEL
EPC: DS 2 ;END PC VALUE
NBP: DS 1 ;NEXT BYTE POSITION TO WRITE FOR MACHINE CODE
END

View File

@@ -0,0 +1,504 @@
; MDS-800 I/O Drivers for CP/M 2.2
; (four drive single density version)
;
; Version 2.2 February, 1980
;
vers equ 22 ;version 2.2
;
; Copyright (c) 1980
; Digital Research
; Box 579, Pacific Grove
; California, 93950
;
;
true equ 0ffffh ;value of "true"
false equ not true ;"false"
test equ false ;true if test bios
;
if test
bias equ 03400h ;base of CCP in test system
endif
if not test
bias equ 0000h ;generate relocatable cp/m system
endif
;
patch equ 1600h
;
org patch
cpmb equ $-patch ;base of cpm console processor
bdos equ 806h+cpmb ;basic dos (resident portion)
cpml equ $-cpmb ;length (in bytes) of cpm system
nsects equ cpml/128 ;number of sectors to load
offset equ 2 ;number of disk tracks used by cp/m
cdisk equ 0004h ;address of last logged disk on warm start
buff equ 0080h ;default buffer address
retry equ 10 ;max retries on disk i/o before error
;
; perform following functions
; boot cold start
; wboot warm start (save i/o byte)
; (boot and wboot are the same for mds)
; const console status
; reg-a = 00 if no character ready
; reg-a = ff if character ready
; conin console character in (result in reg-a)
; conout console character out (char in reg-c)
; list list out (char in reg-c)
; punch punch out (char in reg-c)
; reader paper tape reader in (result to reg-a)
; home move to track 00
;
; (the following calls set-up the io parameter block for the
; mds, which is used to perform subsequent reads and writes)
; seldsk select disk given by reg-c (0,1,2...)
; settrk set track address (0,...76) for subsequent read/write
; setsec set sector address (1,...,26) for subsequent read/write
; setdma set subsequent dma address (initially 80h)
;
; (read and write assume previous calls to set up the io parameters)
; read read track/sector to preset dma address
; write write track/sector from preset dma address
;
; jump vector for indiviual routines
jmp boot
wboote: jmp wboot
jmp const
jmp conin
jmp conout
jmp list
jmp punch
jmp reader
jmp home
jmp seldsk
jmp settrk
jmp setsec
jmp setdma
jmp read
jmp write
jmp listst ;list status
jmp sectran
;
maclib diskdef ;load the disk definition library
disks 4 ;four disks
diskdef 0,1,26,6,1024,243,64,64,offset
diskdef 1,0
diskdef 2,0
diskdef 3,0
; endef occurs at end of assembly
;
; end of controller - independent code, the remaining subroutines
; are tailored to the particular operating environment, and must
; be altered for any system which differs from the intel mds.
;
; the following code assumes the mds monitor exists at 0f800h
; and uses the i/o subroutines within the monitor
;
; we also assume the mds system has four disk drives
revrt equ 0fdh ;interrupt revert port
intc equ 0fch ;interrupt mask port
icon equ 0f3h ;interrupt control port
inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor)
;
; mds monitor equates
mon80 equ 0f800h ;mds monitor
rmon80 equ 0ff0fh ;restart mon80 (boot error)
ci equ 0f803h ;console character to reg-a
ri equ 0f806h ;reader in to reg-a
co equ 0f809h ;console char from c to console out
po equ 0f80ch ;punch char from c to punch device
lo equ 0f80fh ;list from c to list device
csts equ 0f812h ;console status 00/ff to register a
;
; disk ports and commands
base equ 78h ;base of disk command io ports
dstat equ base ;disk status (input)
rtype equ base+1 ;result type (input)
rbyte equ base+3 ;result byte (input)
;
ilow equ base+1 ;iopb low address (output)
ihigh equ base+2 ;iopb high address (output)
;
readf equ 4h ;read function
writf equ 6h ;write function
recal equ 3h ;recalibrate drive
iordy equ 4h ;i/o finished mask
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;
signon: ;signon message: xxk cp/m vers y.y
db cr,lf,lf
if test
db '32' ;32k example bios
endif
if not test
db '00' ;memory size filled by relocator
endif
db 'k CP/M vers '
db vers/10+'0','.',vers mod 10+'0'
db cr,lf,0
;
boot: ;print signon message and go to ccp
; (note: mds boot initialized iobyte at 0003h)
lxi sp,buff+80h
lxi h,signon
call prmsg ;print message
xra a ;clear accumulator
sta cdisk ;set initially to disk a
jmp gocpm ;go to cp/m
;
;
wboot:; loader on track 0, sector 1, which will be skipped for warm
; read cp/m from disk - assuming there is a 128 byte cold start
; start.
;
lxi sp,buff ;using dma - thus 80 thru ff available for stack
;
mvi c,retry ;max retries
push b
wboot0: ;enter here on error retries
lxi b,cpmb ;set dma address to start of disk system
call setdma
mvi c,0 ;boot from drive 0
call seldsk
mvi c,0
call settrk ;start with track 0
mvi c,2 ;start reading sector 2
call setsec
;
; read sectors, count nsects to zero
pop b ;10-error count
mvi b,nsects
rdsec: ;read next sector
push b ;save sector count
call read
jnz booterr ;retry if errors occur
lhld iod ;increment dma address
lxi d,128 ;sector size
dad d ;incremented dma address in hl
mov b,h
mov c,l ;ready for call to set dma
call setdma
lda ios ;sector number just read
cpi 26 ;read last sector?
jc rd1
; must be sector 26, zero and go to next track
lda iot ;get track to register a
inr a
mov c,a ;ready for call
call settrk
xra a ;clear sector number
rd1: inr a ;to next sector
mov c,a ;ready for call
call setsec
pop b ;recall sector count
dcr b ;done?
jnz rdsec
;
; done with the load, reset default buffer address
gocpm: ;(enter here from cold start boot)
; enable rst0 and rst7
di
mvi a,12h ;initialize command
out revrt
xra a
out intc ;cleared
mvi a,inte ;rst0 and rst7 bits on
out intc
xra a
out icon ;interrupt control
;
; set default buffer address to 80h
lxi b,buff
call setdma
;
; reset monitor entry points
mvi a,jmp
sta 0
lxi h,wboote
shld 1 ;jmp wboot at location 00
sta 5
lxi h,bdos
shld 6 ;jmp bdos at location 5
if not test
sta 7*8 ;jmp to mon80 (may have been changed by ddt)
lxi h,mon80
shld 7*8+1
endif
; leave iobyte set
; previously selected disk was b, send parameter to cpm
lda cdisk ;last logged disk number
mov c,a ;send to ccp to log it in
ei
jmp cpmb
;
; error condition occurred, print message and retry
booterr:
pop b ;recall counts
dcr c
jz booter0
; try again
push b
jmp wboot0
;
booter0:
; otherwise too many retries
lxi h,bootmsg
call prmsg
jmp rmon80 ;mds hardware monitor
;
bootmsg:
db '?boot',0
;
;
const: ;console status to reg-a
; (exactly the same as mds call)
jmp csts
;
conin: ;console character to reg-a
call ci
ani 7fh ;remove parity bit
ret
;
conout: ;console character from c to console out
jmp co
;
list: ;list device out
; (exactly the same as mds call)
jmp lo
;
listst:
;return list status
xra a
ret ;always not ready
;
punch: ;punch device out
; (exactly the same as mds call)
jmp po
;
reader: ;reader character in to reg-a
; (exactly the same as mds call)
jmp ri
;
home: ;move to home position
; treat as track 00 seek
mvi c,0
jmp settrk
;
seldsk: ;select disk given by register c
lxi h,0000h ;return 0000 if error
mov a,c
cpi ndisks ;too large?
rnc ;leave HL = 0000
;
ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3
sta dbank ;to select drive bank
mov a,c ;00, 01, 10, 11
ani 1b ;mds has 0,1 at 78, 2,3 at 88
ora a ;result 00?
jz setdrive
mvi a,00110000b ;selects drive 1 in bank
setdrive:
mov b,a ;save the function
lxi h,iof ;io function
mov a,m
ani 11001111b ;mask out disk number
ora b ;mask in new disk number
mov m,a ;save it in iopb
mov l,c
mvi h,0 ;HL=disk number
dad h ;*2
dad h ;*4
dad h ;*8
dad h ;*16
lxi d,dpbase
dad d ;HL=disk header table address
ret
;
;
settrk: ;set track address given by c
lxi h,iot
mov m,c
ret
;
setsec: ;set sector number given by c
lxi h,ios
mov m,c
ret
sectran:
;translate sector bc using table at de
mvi b,0 ;double precision sector number in BC
xchg ;translate table address to HL
dad b ;translate(sector) address
mov a,m ;translated sector number to A
sta ios
mov l,a ;return sector number in L
ret
;
setdma: ;set dma address given by regs b,c
mov l,c
mov h,b
shld iod
ret
;
read: ;read next disk record (assuming disk/trk/sec/dma set)
mvi c,readf ;set to read function
call setfunc
call waitio ;perform read function
ret ;may have error set in reg-a
;
;
write: ;disk write function
mvi c,writf
call setfunc ;set to write function
call waitio
ret ;may have error set
;
;
; utility subroutines
prmsg: ;print message at h,l to 0
mov a,m
ora a ;zero?
rz
; more to print
push h
mov c,a
call conout
pop h
inx h
jmp prmsg
;
setfunc:
; set function for next i/o (command in reg-c)
lxi h,iof ;io function address
mov a,m ;get it to accumulator for masking
ani 11111000b ;remove previous command
ora c ;set to new command
mov m,a ;replaced in iopb
; the mds-800 controller requires disk bank bit in sector byte
; mask the bit from the current i/o function
ani 00100000b ;mask the disk select bit
lxi h,ios ;address the sector select byte
ora m ;select proper disk bank
mov m,a ;set disk select bit on/off
ret
;
waitio:
mvi c,retry ;max retries before perm error
rewait:
; start the i/o function and wait for completion
call intype ;in rtype
call inbyte ;clears the controller
;
lda dbank ;set bank flags
ora a ;zero if drive 0,1 and nz if 2,3
mvi a,iopb and 0ffh ;low address for iopb
mvi b,iopb shr 8 ;high address for iopb
jnz iodr1 ;drive bank 1?
out ilow ;low address to controller
mov a,b
out ihigh ;high address
jmp wait0 ;to wait for complete
;
iodr1: ;drive bank 1
out ilow+10h ;88 for drive bank 10
mov a,b
out ihigh+10h
;
wait0: call instat ;wait for completion
ani iordy ;ready?
jz wait0
;
; check io completion ok
call intype ;must be io complete (00) unlinked
; 00 unlinked i/o complete, 01 linked i/o complete (not used)
; 10 disk status changed 11 (not used)
cpi 10b ;ready status change?
jz wready
;
; must be 00 in the accumulator
ora a
jnz werror ;some other condition, retry
;
; check i/o error bits
call inbyte
ral
jc wready ;unit not ready
rar
ani 11111110b ;any other errors? (deleted data ok)
jnz werror
;
; read or write is ok, accumulator contains zero
ret
;
wready: ;not ready, treat as error for now
call inbyte ;clear result byte
jmp trycount
;
werror: ;return hardware malfunction (crc, track, seek, etc.)
; the mds controller has returned a bit in each position
; of the accumulator, corresponding to the conditions:
; 0 - deleted data (accepted as ok above)
; 1 - crc error
; 2 - seek error
; 3 - address error (hardware malfunction)
; 4 - data over/under flow (hardware malfunction)
; 5 - write protect (treated as not ready)
; 6 - write error (hardware malfunction)
; 7 - not ready
; (accumulator bits are numbered 7 6 5 4 3 2 1 0)
;
; it may be useful to filter out the various conditions,
; but we will get a permanent error message if it is not
; recoverable. in any case, the not ready condition is
; treated as a separate condition for later improvement
trycount:
; register c contains retry count, decrement 'til zero
dcr c
jnz rewait ;for another try
;
; cannot recover from error
mvi a,1 ;error code
ret
;
; intype, inbyte, instat read drive bank 00 or 10
intype: lda dbank
ora a
jnz intyp1 ;skip to bank 10
in rtype
ret
intyp1: in rtype+10h ;78 for 0,1 88 for 2,3
ret
;
inbyte: lda dbank
ora a
jnz inbyt1
in rbyte
ret
inbyt1: in rbyte+10h
ret
;
instat: lda dbank
ora a
jnz insta1
in dstat
ret
insta1: in dstat+10h
ret
;
;
;
; data areas (must be in ram)
dbank: db 0 ;disk bank 00 if drive 0,1
; 10 if drive 2,3
iopb: ;io parameter block
db 80h ;normal i/o operation
iof: db readf ;io function, initial read
ion: db 1 ;number of sectors to read
iot: db offset ;track number
ios: db 1 ;sector number
iod: dw buff ;io address
;
;
; define ram areas for bdos operation
endef
end

View File

@@ -0,0 +1,307 @@
; Skeletal CBIOS for first level of CP/M 2.0 alteration
;
msize equ 20 ;cp/m version memory size in kilobytes
;
; "bias" is address offset from 3400H for memory systems
; than 16K (referred to as "b" throughout the text).
;
bias equ (msize-20)*1024
ccp equ 3400H+bias ;base of ccp
bdos equ ccp+806h ;base of bdos
bios equ ccp+1600h ;base of bios
cdisk equ 0004H ;current disk number 0=A,...,15=P
iobyte equ 0003h ;intel i/o byte
;
org bios ;origin of this program
nsects equ ($-ccp)/128 ;warm start sector count
;
; jump vector for individual subroutines
jmp boot ;cold start
wboote: jmp wboot ;warm start
jmp const ;console status
jmp conin ;console character in
jmp conout ;console character out
jmp list ;list character out
jmp punch ;punch character out
jmp reader ;reader character out
jmp home ;move head to home position
jmp seldsk ;select disk
jmp settrk ;set track number
jmp setsec ;set sector number
jmp setdma ;set dma address
jmp read ;read disk
jmp write ;write disk
jmp listst ;return list status
jmp sectran ;sector translate
;
; fixed data tables for four-drive standard
; IBM-compatible 8" disks
; disk parameter header for disk 00
dpbase: dw trans,0000H
dw 0000H,0000H
dw dirbf,dpblk
dw chk00,all00
; disk parameter header for disk 01
dw trans,0000H
dw 0000H,0000H
dw dirbf,dpblk
dw chk01,all01
; disk parameter header for disk 02
dw trans,0000H
dw 0000H,0000H
dw dirbf,dpblk
dw chk02,all02
; disk parameter header for disk 03
dw trans,0000H
dw 0000H,0000H
dw dirbf,dpblk
dw chk03,all03
;
; sector translate vector
trans: db 1,7,13,19 ;sectors 1,2,3,4
db 25,5,11,17 ;sectors 5,6,7,8
db 23,3,9,15 ;sectors 9,10,11,12
db 21,2,8,14 ;sectors 13,14,15,16
db 20,26,6,12 ;sectors 17,18,19,20
db 18,24,4,10 ;sectors 21,22,23,24
db 16,22 ;sectors 25,26
;
dpblk: ;disk parameter block, common to all disks
dw 26 ;sectors per track
db 3 ;block shift factor
db 7 ;block mask
db 0 ;null mask
dw 242 ;disk size-1
dw 63 ;directory max
db 192 ;alloc 0
db 0 ;alloc 1
dw 16 ;check size
dw 2 ;track offset
;
; end of fixed tables
;
; individual subroutines to perform each function
boot: ;simplest case is to just perform parameter initialization
xra a ;zero in the accum
sta iobyte ;clear the iobyte
sta cdisk ;select disk zero
jmp gocpm ;initialize and go to cp/m
;
wboot: ;simplest case is to read the disk until all sectors loaded
lxi sp,80h ;use space below buffer for stack
mvi c,0 ;select disk 0
call seldsk
call home ;go to track 00
;
mvi b,nsects ;b counts # of sectors to load
mvi c,0 ;c has the current track number
mvi d,2 ;d has the next sector to read
; note that we begin by reading track 0, sector 2 since sector 1
; contains the cold start loader, which is skipped in a warm start
lxi h,ccp ;base of cp/m (initial load point)
load1: ;load one more sector
push b ;save sector count, current track
push d ;save next sector to read
push h ;save dma address
mov c,d ;get sector address to register c
call setsec ;set sector address from register c
pop b ;recall dma address to b,c
push b ;replace on stack for later recall
call setdma ;set dma address from b,c
;
; drive set to 0, track set, sector set, dma address set
call read
cpi 00h ;any errors?
jnz wboot ;retry the entire boot if an error occurs
;
; no error, move to next sector
pop h ;recall dma address
lxi d,128 ;dma=dma+128
dad d ;new dma address is in h,l
pop d ;recall sector address
pop b ;recall number of sectors remaining, and current trk
dcr b ;sectors=sectors-1
jz gocpm ;transfer to cp/m if all have been loaded
;
; more sectors remain to load, check for track change
inr d
mov a,d ;sector=27?, if so, change tracks
cpi 27
jc load1 ;carry generated if sector<27
;
; end of current track, go to next track
mvi d,1 ;begin with first sector of next track
inr c ;track=track+1
;
; save register state, and change tracks
push b
push d
push h
call settrk ;track address set from register c
pop h
pop d
pop b
jmp load1 ;for another sector
;
; end of load operation, set parameters and go to cp/m
gocpm:
mvi a,0c3h ;c3 is a jmp instruction
sta 0 ;for jmp to wboot
lxi h,wboote ;wboot entry point
shld 1 ;set address field for jmp at 0
;
sta 5 ;for jmp to bdos
lxi h,bdos ;bdos entry point
shld 6 ;address field of jump at 5 to bdos
;
lxi b,80h ;default dma address is 80h
call setdma
;
ei ;enable the interrupt system
lda cdisk ;get current disk number
mov c,a ;send to the ccp
jmp ccp ;go to cp/m for further processing
;
;
; simple i/o handlers (must be filled in by user)
; in each case, the entry point is provided, with space reserved
; to insert your own code
;
const: ;console status, return 0ffh if character ready, 00h if not
ds 10h ;space for status subroutine
mvi a,00h
ret
;
conin: ;console character into register a
ds 10h ;space for input routine
ani 7fh ;strip parity bit
ret
;
conout: ;console character output from register c
mov a,c ;get to accumulator
ds 10h ;space for output routine
ret
;
list: ;list character from register c
mov a,c ;character to register a
ret ;null subroutine
;
listst: ;return list status (0 if not ready, 1 if ready)
xra a ;0 is always ok to return
ret
;
punch: ;punch character from register c
mov a,c ;character to register a
ret ;null subroutine
;
;
reader: ;read character into register a from reader device
mvi a,1ah ;enter end of file for now (replace later)
ani 7fh ;remember to strip parity bit
ret
;
;
; i/o drivers for the disk follow
; for now, we will simply store the parameters away for use
; in the read and write subroutines
;
home: ;move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
mvi c,0 ;select track 0
call settrk
ret ;we will move to 00 on first read/write
;
seldsk: ;select disk given by register C
lxi h,0000h ;error return code
mov a,c
sta diskno
cpi 4 ;must be between 0 and 3
rnc ;no carry if 4,5,...
; disk number is in the proper range
ds 10 ;space for disk select
; compute proper disk parameter header address
lda diskno
mov l,a ;L=disk number 0,1,2,3
mvi h,0 ;high order zero
dad h ;*2
dad h ;*4
dad h ;*8
dad h ;*16 (size of each header)
lxi d,dpbase
dad d ;HL=.dpbase(diskno*16)
ret
;
settrk: ;set track given by register c
mov a,c
sta track
ds 10h ;space for track select
ret
;
setsec: ;set sector given by register c
mov a,c
sta sector
ds 10h ;space for sector select
ret
;
sectran:
;translate the sector given by BC using the
;translate table given by DE
xchg ;HL=.trans
dad b ;HL=.trans(sector)
mov l,m ;L = trans(sector)
mvi h,0 ;HL= trans(sector)
ret ;with value in HL
;
setdma: ;set dma address given by registers b and c
mov l,c ;low order address
mov h,b ;high order address
shld dmaad ;save the address
ds 10h ;space for setting the dma address
ret
;
read: ;perform read operation (usually this is similar to write
; so we will allow space to set up read command, then use
; common code in write)
ds 10h ;set up read command
jmp waitio ;to perform the actual i/o
;
write: ;perform a write operation
ds 10h ;set up write command
;
waitio: ;enter here from read and write to perform the actual i/o
; operation. return a 00h in register a if the operation completes
; properly, and 01h if an error occurs during the read or write
;
; in this case, we have saved the disk number in 'diskno' (0,1)
; the track number in 'track' (0-76)
; the sector number in 'sector' (1-26)
; the dma address in 'dmaad' (0-65535)
ds 256 ;space reserved for I/O drivers
mvi a,1 ;error condition
ret ;replaced when filled-in
;
; the remainder of the CBIOS is reserved uninitialized
; data area, and does not need to be a part of the
; system memory image (the space must be available,
; however, between "begdat" and "enddat").
;
track: ds 2 ;two bytes for expansion
sector: ds 2 ;two bytes for expansion
dmaad: ds 2 ;direct memory address
diskno: ds 1 ;disk number 0-15
;
; scratch ram area for BDOS use
begdat equ $ ;beginning of data area
dirbf: ds 128 ;scratch directory area
all00: ds 31 ;allocation vector 0
all01: ds 31 ;allocation vector 1
all02: ds 31 ;allocation vector 2
all03: ds 31 ;allocation vector 3
chk00: ds 16 ;check vector 0
chk01: ds 16 ;check vector 1
chk02: ds 16 ;check vector 2
chk03: ds 16 ;check vector 3
;
enddat equ $ ;end of data area
datsiz equ $-begdat;size of data area
end

View File

@@ -0,0 +1,421 @@
TITLE 'CP/M VERSION 2.2 SYSTEM RELOCATOR - 2/80'
; CPM RELOCATOR PROGRAM, INCLUDED WITH THE MODULE TO PERFORM
; THE MOVE FROM 900H TO THE DESTINATION ADDRESS
;
; COPYRIGHT (C) 1979
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE CALIFORNIA
; 93950
;
ORG 100H
JMP PASTCOPY
COPY: DB 'COPYRIGHT (C) DIGITAL RESEARCH, 1979 '
PASTCOPY:
BIOSWK EQU 03H ;THREE PAGES FOR BIOS WORKSPACE
STACK EQU 800H
MODSIZ EQU 801H ;MODULE SIZE IS STORED HERE
VERSION EQU 22 ;CPM VERSION NUMBER
BOOTSIZ EQU 100H ;SIZE OF THE COLD START LOADER
; (MAY HAVE FIRST 80H BYTES = 00H)
BDOSL EQU 0800H ;RELATIVE LOCATION OF BDOS
BIOS EQU 1600H ;RELATIVE LOCATION OF BIOS
;
BOOT EQU 0000H ;REBOOT LOCATION
BDOS EQU 0005H
PRNT EQU 9 ;PRINT BUFFER FUNCTION
FCB EQU 5CH ;DEFAULT FCB
MODULE EQU 900H ;MODULE ADDRESS
;
CR EQU 0DH
LF EQU 0AH
LXI SP,STACK
;
; MAY BE MEMORY SIZE SPECIFIED IN COMMAND
LXI D,FCB+1
LDAX D
CPI ' '
JZ FINDTOP
CPI '?' ;WAS * SPECIFIED?
JZ FINDTOP
;
; MUST BE MEMORY SIZE SPECIFICATION
LXI H,0
CLOOP: ;CONVERT TO DECIMAL
LDAX D
INX D
CPI ' '
JZ ECON
ORA A
JZ ECON
; MUST BE DECIMAL DIGIT
SUI '0'
CPI 10
JNC CERROR
; DECIMAL DIGIT IS IN A
DAD H ;*2
PUSH H
DAD H ;*4
DAD H ;*8
POP B ;*2 IN B,C
DAD B ;*10 IN H,L
MOV C,A
MVI B,0
DAD B ;*10+X
JMP CLOOP
ECON: ;END OF CONVERSION, CHECK FOR PROPER RANGE
MOV A,H
ORA A
JNZ CERROR
MOV A,L
CPI 16
JC CERROR
MVI L,0
MOV H,A
DAD H ;SHL 1
DAD H ;SHL 2 FOR KILOBYTES
; H,L HAVE TOP OF MEMORY+1
JMP SETASC
;
CERROR:
LXI D,CONMSG
CALL PRINT
JMP BOOT
CONMSG: DB CR,LF,'INVALID MEMORY SIZE$'
;
;
; FIND END OF MEMORY
FINDTOP:
LXI H,0
FINDM: INR H ;TO NEXT PAGE
JZ MSIZED ;CAN OVERFLOW ON 64K SYSTEMS
MOV A,M
CMA
MOV M,A
CMP M
CMA
MOV M,A ;BITS INVERTED FOR RAM OPERATIONAL TEST
JZ FINDM
; BITS DIDN'T CHANGE, MUST BE END OF MEMORY
; ALIGN ON EVEN BOUNDARY
MSIZED: MOV A,H
ANI 1111$1100B ;EVEN 1K BOUNDARY
MOV H,A
SETASC: ;SET ASCII VALUE OF MEMORY SIZE
PUSH H ;SAVE FOR LATER
; **** SERIALIZATION ****
LHLD BDOS+1
SHLD SER1
; **** SERIALIZATION ****
POP H
PUSH H
MOV A,H
RRC
RRC
ANI 11$1111B ;FOR 1K COUNTS
JNZ NOT64 ;MAY BE 64 K MEM SIZE
MVI A,64 ;SET TO LITERAL IF SO
NOT64: MOV B,A ;READY FOR COUNT DOWN
LXI H,AMEM
MVI A,'0'
MOV M,A
INX H
MOV M,A ;BOTH ARE SET TO ASCII 0
ASC0: LXI H,AMEM+1 ;ADDRESS OF ASCII EQUIVALENT
INR M
MOV A,M
CPI '9'+1
JC ASC1
MVI M,'0'
DCX H
INR M
ASC1: DCR B ;COUNT DOWN BY KILOBYTES
JNZ ASC0
LXI D,MEMSG
CALL PRINT ;MEMORY SIZE MESSAGE
;
LXI H,MODSIZ
MOV C,M
INX H
MOV B,M ;B,C CONTAINS MODULE SIZE
PUSH B ;MODULE SIZE STACKED ON MEM SIZE
;
; TRY TO FIND THE ASCII STRING 'K CP/M VER X.X' TO SET SIZE
LXI H,MODULE
; B,C CONTAINS MODULE LENGTH
SLOOP: ;SEARCH LOOP
LXI D,AMSG
MOV A,B
ORA C
JZ ESEAR ;END OF SEARCH
DCX B ;COUNT SEARCH LENGTH DOWN
PUSH B
MVI C,LAMSG ;LENGTH OF SEARCH MESSAGE
PUSH H ;SAVE BASE ADDRESS OF SEARCH
CHLOOP: ;CHARACTER LOOP, MATCH ON CONTENTS OF D,E AND H,L
LDAX D
CMP M
JNZ NOMATCH
INX D ;TO NEXT SEARCH CHARACTER
INX H ;TO NEXT MATCH CHARACTER
DCR C ;COUNT LENGTH DOWN
JZ FSEAR ;FOUND SEARCH STRING
JMP CHLOOP
;
; **** SERIALIZATION ****
DB LXI ;CONFUSE DISASSEMBLER
BADSER: ;BAD SERIAL NUMBER, LOOP TO CONFUSE ICE-80
XRA A
BADSER0:
DCR A
JNZ BADSER0
;
LXI H,DI OR (HLT SHL 8)
SHLD PRHLT
LXI H,PRJMP
MVI M,CALL ;CHANGE JMP BDOS TO CALL
LXI D,SYNCMSG-5
LXI H,5
DAD D ;TO CONFUSE SEARCHES ON ADDRESSES
XCHG
JMP PRINT
; **** SERIALIZATION ****
;
NOMATCH:
;NOT FOUND AT THIS ADDRESS, LOOK AT NEXT ADDRESS
POP H
INX H
POP B ;RECALL MODULE LENGTH
JMP SLOOP
;
FSEAR:
;FOUND STRING, SET MEMORY SIZE
POP H ;START ADDRESS OF STRING BEING MATCHED
POP B ;CLEAR B,C WHICH WAS STACKED
DCX H
LXI D,AMEM+1
LDAX D
MOV M,A
DCX H
DCX D
LDAX D
MOV M,A
; END OF FILL
;
ESEAR: ;END OF SEARCH
; **** SERIALIZATION ****
; CHECK FOR LEAST SIGNIFICANT BYTE OF 06 IN SER1
LXI B,SER1
LDAX B
CPI 6
MVI A,0
JNZ SETJMP ;BAD SERIALIZATION IF NOT 06
STAX B ;STORE 00 TO LEAST SIGNIFICANT BYTE
; **** SERIALIZATION ****
POP B ;RECOVER MODULE LENGTH
POP H ;H,L CONTAINS END OF MEMORY
PUSH B ;SAVE LENGTH FOR RELOCATION BELOW
MOV A,B
ADI BIOSWK ;ADD BIOS WORK SPACE TO MODULE LENGTH
MOV B,A
MOV A,L
SUB C ;COMPUTE MEMTOP-MODULE SIZE
MOV L,A
MOV A,H
SBB B
MOV H,A
; H,L CONTAINS THE BASE OF THE RELOCATION AREA
SHLD RELBAS ;SAVE THE RELOCATION BASE
XCHG ;MODULE BASE TO D,E
LXI H,MODULE;READY FOR THE MOVE
POP B ;RECOVER ACTUAL MODULE LENGTH
PUSH B ;SAVE FOR RELOCATION
LDA FCB+17 ;CHECK FOR NO MOVE CONDITION
CPI ' '
JZ MOVE
; SECOND PARAMETER SPECIFIED, LEAVE THE DATA AT 'MODULE'
DAD B ;MOVE H,L TO BIT MAP POSITION
JMP RELOC
;
; **** SERIALIZATION ****
SETJMP: LXI H,BADSER ;BAD SERIALIZATION
SHLD JMPSER+1 ;FILL JUMP INSTRUCTION
JMP JMPSER ;EVENTUAL JUMP TO MESSAGE
; **** SERIALIZATION ****
;
MOVE:
MOV A,B ;BC=0?
ORA C
JZ RELOC
DCX B ;COUNT MODULE SIZE DOWN TO ZERO
MOV A,M ;GET NEXT ABSOLUTE LOCATION
STAX D ;PLACE IT INTO THE RELOC AREA
INX D
INX H
JMP MOVE
;
RELOC: ;STORAGE MOVED, READY FOR RELOCATION
; HL ADDRESSES BEGINNING OF THE BIT MAP FOR RELOCATION
POP B ;RECALL MODULE LENGTH
PUSH H ;SAVE BIT MAP BASE IN STACK
LHLD RELBAS
XCHG
LXI H,BOOTSIZ
DAD D ;TO FIND BIAS VALUE
; REGISTER H CONTAINS BIAS VALUE
;
; RELOCATE AT 'MODULE' IF SECOND PARAMETER GIVEN
LDA FCB+17
CPI ' '
JZ REL0
;
; IMAGE NOT MOVED, ADJUST VALUES AT 'MODULE'
LXI D,MODULE
REL0: MOV A,B ;BC=0?
ORA C
JZ ENDREL
; **** SERIALIZATION ****
JMP PASTSYNC
SYNCMSG:
DB CR,LF,'SYNCRONIZATION ERROR$'
PASTSYNC:
; **** SERIALIZATION ****
;
; NOT END OF THE RELOCATION, MAY BE INTO NEXT BYTE OF BIT MAP
DCX B ;COUNT LENGTH DOWN
MOV A,E
ANI 111B ;0 CAUSES FETCH OF NEXT BYTE
JNZ REL1
; FETCH BIT MAP FROM STACKED ADDRESS
XTHL
MOV A,M ;NEXT 8 BITS OF MAP
INX H
XTHL ;BASE ADDRESS GOES BACK TO STACK
MOV L,A ;L HOLDS THE MAP AS WE PROCESS 8 LOCATIONS
REL1: MOV A,L
RAL ;CY SET TO 1 IF RELOCATION NECESSARY
MOV L,A ;BACK TO L FOR NEXT TIME AROUND
JNC REL2 ;SKIP RELOCATION IF CY=0
;
; CURRENT ADDRESS REQUIRES RELOCATION
LDAX D
ADD H ;APPLY BIAS IN H
STAX D
JMP REL2
;
REL2: INX D ;TO NEXT ADDRESS
JMP REL0 ;FOR ANOTHER BYTE TO RELOCATE
;
ENDREL: ;END OF RELOCATION
POP D ;CLEAR STACKED ADDRESS
; **** SERIALIZATION ****
LXI D,MODULE+BDOSL+BOOTSIZ ;ADDRESSING NEW SERIAL NUMBER
LHLD SER1 ;ADDRESSING HOST SERIAL NUMBER
MVI C,6 ;LENGTH OF SERIAL NUMBER
CHKSER: LDAX D
CMP M
JNZ SETJMP
INX H
INX D
DCR C
JNZ CHKSER
; **** SERIALIZATION ****
;
LDA FCB+17
CPI ' '
JZ TRANSFER
; DON'T GO TO THE LOADED PROGRAM, LEAVE IN MEMORY
; MAY HAVE TO MOVE THE PROGRAM IMAGE DOWN 1/2 PAGE
MVI B,128 ;CHECK FOR 128 ZEROES
LXI H,MODULE
TR0: MOV A,M
ORA A
JNZ TREND
INX H
DCR B
JNZ TR0
;
; ALL ZERO FIRST 1/2 PAGE, MOVE DOWN 80H BYTES
XCHG ;NEXT TO GET IN D,E
LHLD MODSIZ
LXI B,-128
DAD B ;NUMBER OF BYTES TO MOVE IN H,L
MOV B,H
MOV C,L ;TRANSFERRED TO B,C
LXI H,MODULE;DESTINATION IN H,L
TRMOV: MOV A,B
ORA C ;ALL MOVED?
JZ TREND
DCX B
LDAX D
MOV M,A ;ONE BYTE TRANSFERRED
INX D
INX H
JMP TRMOV
;
;
; **** SERIALIZATION ****
DB LXI
JMPSER: JMP JMPSER ;ADDRESS FIELD FILLED-IN
; **** SERIALIZATION ****
;
TREND: ;SET ASCII MEMORY IMAGE SIZE
LXI H,MODSIZ
MOV C,M
INX H
MOV B,M
LXI H,MODULE;B,C MODULE SIZE, H,L BASE
DAD B
MOV B,H ;B CONTAINS NUMBER OF PAGES TO SAVE+1
LXI H,SAVMEM;ASCII MEMORY SIZE
MVI A,'0'
MOV M,A
INX H
MOV M,A
; '00' STORED INTO MESSAGE
TRCOMP:
DCR B
JZ TRC1
LXI H,SAVMEM+1 ;ADDRESSING LEAST DIGIT
INR M
MOV A,M
CPI '9'+1
JC TRCOMP
MVI M,'0'
DCX H
INR M
JMP TRCOMP
; FILL CPMXX.COM FROM SAVMEM
TRC1: LHLD AMEM
SHLD SAVM0
; MESSAGE SET, PRINT IT AND REBOOT
LXI D,RELOK
CALL PRINT
JMP BOOT
RELOK: DB CR,LF,'READY FOR "SYSGEN" OR'
DB CR,LF,'"SAVE '
SAVMEM: DB '00 CPM'
SAVM0: DB '00.COM"$'
;
TRANSFER:
; GO TO THE RELOCATED MEMORY IMAGE
LXI D,BOOTSIZ+BIOS ;MODULE
LHLD RELBAS ;RECALL BASE OF RELOC AREA
DAD D ;INDEX TO 'BOOT' ENTRY POINT
PCHL ;GO TO RELOCATED PROGRAM
;
; **** SERIALIZATION ****
PRINT:
MVI C,PRNT
PRJMP: JMP BDOS
PRHLT:
;
; DATA AREAS
SER1: DS 2 ;SERIAL NUMBER ADDRESS FOR HOST
RELBAS: DS 2 ;RELOCATION BASE
MEMSG: DB CR,LF,'CONSTRUCTING '
AMEM: DB '00'
AMSG: DB 'k CP/M vers '
DB VERSION/10+'0','.',VERSION MOD 10 +'0'
LAMSG EQU $-AMSG ;LENGTH OF MESSAGE
DB '$' ;TERMINATOR FOR MESSAGE
END

View File

@@ -0,0 +1,88 @@
; DDT RELOCATOR PROGRAM, INCLUDED WITH THE MODULE TO PERFORM
; THE MOVE FROM 200H TO THE DESTINATION ADDRESS
VERSION EQU 22 ;2.2
;
; COPYRIGHT (C) 1976, 1977, 1978, 1979, 1980
; DIGITAL RESEARCH
; BOX 579 PACIFIC GROVE
; CALIFORNIA 93950
;
ORG 100H
STACK EQU 200H
BDOS EQU 0005H
PRNT EQU 9 ;BDOS PRINT FUNCTION
MODULE EQU 200H ;MODULE ADDRESS
;
db 01h ;lxi instruction
ds 2 ;space for address
; LXI B,0 ;ADDRESS FIELD FILLED-IN WHEN MODULE BUILT
JMP START
DB 'COPYRIGHT (C) 1980, DIGITAL RESEARCH '
SIGNON: DB 'DDT VERS '
DB VERSION/10+'0','.'
DB VERSION MOD 10 + '0','$'
START: LXI SP,STACK
PUSH B
PUSH B
LXI D,SIGNON
MVI C,PRNT
CALL BDOS
POP B ;RECOVER LENGTH OF MOVE
LXI H,BDOS+2;ADDRESS FIELD OF JUMP TO BDOS (TOP MEMORY)
MOV A,M ;A HAS HIGH ORDER ADDRESS OF MEMORY TOP
DCR A ;PAGE DIRECTLY BELOW BDOS
SUB B ;A HAS HIGH ORDER ADDRESS OF RELOC AREA
MOV D,A
MVI E,0 ;D,E ADDRESSES BASE OF RELOC AREA
PUSH D ;SAVE FOR RELOCATION BELOW
;
LXI H,MODULE;READY FOR THE MOVE
MOVE: MOV A,B ;BC=0?
ORA C
JZ RELOC
DCX B ;COUNT MODULE SIZE DOWN TO ZERO
MOV A,M ;GET NEXT ABSOLUTE LOCATION
STAX D ;PLACE IT INTO THE RELOC AREA
INX D
INX H
JMP MOVE
;
RELOC: ;STORAGE MOVED, READY FOR RELOCATION
; HL ADDRESSES BEGINNING OF THE BIT MAP FOR RELOCATION
POP D ;RECALL BASE OF RELOCATION AREA
POP B ;RECALL MODULE LENGTH
PUSH H ;SAVE BIT MAP BASE IN STACK
MOV H,D ;RELOCATION BIAS IS IN D
;
REL0: MOV A,B ;BC=0?
ORA C
JZ ENDREL
;
; NOT END OF THE RELOCATION, MAY BE INTO NEXT BYTE OF BIT MAP
DCX B ;COUNT LENGTH DOWN
MOV A,E
ANI 111B ;0 CAUSES FETCH OF NEXT BYTE
JNZ REL1
; FETCH BIT MAP FROM STACKED ADDRESS
XTHL
MOV A,M ;NEXT 8 BITS OF MAP
INX H
XTHL ;BASE ADDRESS GOES BACK TO STACK
MOV L,A ;L HOLDS THE MAP AS WE PROCESS 8 LOCATIONS
REL1: MOV A,L
RAL ;CY SET TO 1 IF RELOCATION NECESSARY
MOV L,A ;BACK TO L FOR NEXT TIME AROUND
JNC REL2 ;SKIP RELOCATION IF CY=0
;
; CURRENT ADDRESS REQUIRES RELOCATION
LDAX D
ADD H ;APPLY BIAS IN H
STAX D
REL2: INX D ;TO NEXT ADDRESS
JMP REL0 ;FOR ANOTHER BYTE TO RELOCATE
;
ENDREL: ;END OF RELOCATION
POP D ;CLEAR STACKED ADDRESS
MVI L,0
PCHL ;GO TO RELOCATED PROGRAM
END

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,388 @@
;*****************************************************
;* *
;* Sector Deblocking Algorithms for CP/M 2.0 *
;* *
;*****************************************************
;
; utility macro to compute sector mask
smask macro hblk
;; compute log2(hblk), return @x as result
;; (2 ** @x = hblk on return)
@y set hblk
@x set 0
;; count right shifts of @y until = 1
rept 8
if @y = 1
exitm
endif
;; @y is not 1, shift right one position
@y set @y shr 1
@x set @x + 1
endm
endm
;
;*****************************************************
;* *
;* CP/M to host disk constants *
;* *
;*****************************************************
blksiz equ 2048 ;CP/M allocation size
hstsiz equ 512 ;host disk sector size
hstspt equ 20 ;host disk sectors/trk
hstblk equ hstsiz/128 ;CP/M sects/host buff
cpmspt equ hstblk * hstspt ;CP/M sectors/track
secmsk equ hstblk-1 ;sector mask
smask hstblk ;compute sector mask
secshf equ @x ;log2(hstblk)
;
;*****************************************************
;* *
;* BDOS constants on entry to write *
;* *
;*****************************************************
wrall equ 0 ;write to allocated
wrdir equ 1 ;write to directory
wrual equ 2 ;write to unallocated
;
;*****************************************************
;* *
;* The BDOS entry points given below show the *
;* code which is relevant to deblocking only. *
;* *
;*****************************************************
;
; DISKDEF macro, or hand coded tables go here
dpbase equ $ ;disk param block base
;
boot:
wboot:
;enter here on system boot to initialize
xra a ;0 to accumulator
sta hstact ;host buffer inactive
sta unacnt ;clear unalloc count
ret
;
home:
;home the selected disk
home:
lda hstwrt ;check for pending write
ora a
jnz homed
sta hstact ;clear host active flag
homed:
ret
;
seldsk:
;select disk
mov a,c ;selected disk number
sta sekdsk ;seek disk number
mov l,a ;disk number to HL
mvi h,0
rept 4 ;multiply by 16
dad h
endm
lxi d,dpbase ;base of parm block
dad d ;hl=.dpb(curdsk)
ret
;
settrk:
;set track given by registers BC
mov h,b
mov l,c
shld sektrk ;track to seek
ret
;
setsec:
;set sector given by register c
mov a,c
sta seksec ;sector to seek
ret
;
setdma:
;set dma address given by BC
mov h,b
mov l,c
shld dmaadr
ret
;
sectran:
;translate sector number BC
mov h,b
mov l,c
ret
;
;*****************************************************
;* *
;* The READ entry point takes the place of *
;* the previous BIOS defintion for READ. *
;* *
;*****************************************************
read:
;read the selected CP/M sector
xra a
sta unacnt
mvi a,1
sta readop ;read operation
sta rsflag ;must read data
mvi a,wrual
sta wrtype ;treat as unalloc
jmp rwoper ;to perform the read
;
;*****************************************************
;* *
;* The WRITE entry point takes the place of *
;* the previous BIOS defintion for WRITE. *
;* *
;*****************************************************
write:
;write the selected CP/M sector
xra a ;0 to accumulator
sta readop ;not a read operation
mov a,c ;write type in c
sta wrtype
cpi wrual ;write unallocated?
jnz chkuna ;check for unalloc
;
; write to unallocated, set parameters
mvi a,blksiz/128 ;next unalloc recs
sta unacnt
lda sekdsk ;disk to seek
sta unadsk ;unadsk = sekdsk
lhld sektrk
shld unatrk ;unatrk = sectrk
lda seksec
sta unasec ;unasec = seksec
;
chkuna:
;check for write to unallocated sector
lda unacnt ;any unalloc remain?
ora a
jz alloc ;skip if not
;
; more unallocated records remain
dcr a ;unacnt = unacnt-1
sta unacnt
lda sekdsk ;same disk?
lxi h,unadsk
cmp m ;sekdsk = unadsk?
jnz alloc ;skip if not
;
; disks are the same
lxi h,unatrk
call sektrkcmp ;sektrk = unatrk?
jnz alloc ;skip if not
;
; tracks are the same
lda seksec ;same sector?
lxi h,unasec
cmp m ;seksec = unasec?
jnz alloc ;skip if not
;
; match, move to next sector for future ref
inr m ;unasec = unasec+1
mov a,m ;end of track?
cpi cpmspt ;count CP/M sectors
jc noovf ;skip if no overflow
;
; overflow to next track
mvi m,0 ;unasec = 0
lhld unatrk
inx h
shld unatrk ;unatrk = unatrk+1
;
noovf:
;match found, mark as unnecessary read
xra a ;0 to accumulator
sta rsflag ;rsflag = 0
jmp rwoper ;to perform the write
;
alloc:
;not an unallocated record, requires pre-read
xra a ;0 to accum
sta unacnt ;unacnt = 0
inr a ;1 to accum
sta rsflag ;rsflag = 1
;
;*****************************************************
;* *
;* Common code for READ and WRITE follows *
;* *
;*****************************************************
rwoper:
;enter here to perform the read/write
xra a ;zero to accum
sta erflag ;no errors (yet)
lda seksec ;compute host sector
rept secshf
ora a ;carry = 0
rar ;shift right
endm
sta sekhst ;host sector to seek
;
; active host sector?
lxi h,hstact ;host active flag
mov a,m
mvi m,1 ;always becomes 1
ora a ;was it already?
jz filhst ;fill host if not
;
; host buffer active, same as seek buffer?
lda sekdsk
lxi h,hstdsk ;same disk?
cmp m ;sekdsk = hstdsk?
jnz nomatch
;
; same disk, same track?
lxi h,hsttrk
call sektrkcmp ;sektrk = hsttrk?
jnz nomatch
;
; same disk, same track, same buffer?
lda sekhst
lxi h,hstsec ;sekhst = hstsec?
cmp m
jz match ;skip if match
;
nomatch:
;proper disk, but not correct sector
lda hstwrt ;host written?
ora a
cnz writehst ;clear host buff
;
filhst:
;may have to fill the host buffer
lda sekdsk
sta hstdsk
lhld sektrk
shld hsttrk
lda sekhst
sta hstsec
lda rsflag ;need to read?
ora a
cnz readhst ;yes, if 1
xra a ;0 to accum
sta hstwrt ;no pending write
;
match:
;copy data to or from buffer
lda seksec ;mask buffer number
ani secmsk ;least signif bits
mov l,a ;ready to shift
mvi h,0 ;double count
rept 7 ;shift left 7
dad h
endm
; hl has relative host buffer address
lxi d,hstbuf
dad d ;hl = host address
xchg ;now in DE
lhld dmaadr ;get/put CP/M data
mvi c,128 ;length of move
lda readop ;which way?
ora a
jnz rwmove ;skip if read
;
; write operation, mark and switch direction
mvi a,1
sta hstwrt ;hstwrt = 1
xchg ;source/dest swap
;
rwmove:
;C initially 128, DE is source, HL is dest
ldax d ;source character
inx d
mov m,a ;to dest
inx h
dcr c ;loop 128 times
jnz rwmove
;
; data has been moved to/from host buffer
lda wrtype ;write type
cpi wrdir ;to directory?
lda erflag ;in case of errors
rnz ;no further processing
;
; clear host buffer for directory write
ora a ;errors?
rnz ;skip if so
xra a ;0 to accum
sta hstwrt ;buffer written
call writehst
lda erflag
ret
;
;*****************************************************
;* *
;* Utility subroutine for 16-bit compare *
;* *
;*****************************************************
sektrkcmp:
;HL = .unatrk or .hsttrk, compare with sektrk
xchg
lxi h,sektrk
ldax d ;low byte compare
cmp m ;same?
rnz ;return if not
; low bytes equal, test high 1s
inx d
inx h
ldax d
cmp m ;sets flags
ret
;
;*****************************************************
;* *
;* WRITEHST performs the physical write to *
;* the host disk, READHST reads the physical *
;* disk. *
;* *
;*****************************************************
writehst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. write "hstsiz" bytes
;from hstbuf and return error flag in erflag.
;return erflag non-zero if error
ret
;
readhst:
;hstdsk = host disk #, hsttrk = host track #,
;hstsec = host sect #. read "hstsiz" bytes
;into hstbuf and return error flag in erflag.
ret
;
;*****************************************************
;* *
;* Unitialized RAM data areas *
;* *
;*****************************************************
;
sekdsk: ds 1 ;seek disk number
sektrk: ds 2 ;seek track number
seksec: ds 1 ;seek sector number
;
hstdsk: ds 1 ;host disk number
hsttrk: ds 2 ;host track number
hstsec: ds 1 ;host sector number
;
sekhst: ds 1 ;seek shr secshf
hstact: ds 1 ;host active flag
hstwrt: ds 1 ;host written flag
;
unacnt: ds 1 ;unalloc rec cnt
unadsk: ds 1 ;last unalloc disk
unatrk: ds 2 ;last unalloc track
unasec: ds 1 ;last unalloc sector
;
erflag: ds 1 ;error reporting
rsflag: ds 1 ;read sector flag
readop: ds 1 ;1 if read operation
wrtype: ds 1 ;write operation type
dmaadr: ds 2 ;last dma address
hstbuf: ds hstsiz ;host buffer
;
;*****************************************************
;* *
;* The ENDEF macro invocation goes here *
;* *
;*****************************************************
end

View File

@@ -0,0 +1,250 @@
; CP/M 2.0 disk re-definition library
;
; Copyright (c) 1979
; Digital Research
; Box 579
; Pacific Grove, CA
; 93950
;
; CP/M logical disk drives are defined using the
; macros given below, where the sequence of calls
; is:
;
; disks n
; diskdef parameter-list-0
; diskdef parameter-list-1
; ...
; diskdef parameter-list-n
; endef
;
; where n is the number of logical disk drives attached
; to the CP/M system, and parameter-list-i defines the
; characteristics of the ith drive (i=0,1,...,n-1)
;
; each parameter-list-i takes the form
; dn,fsc,lsc,[skf],bls,dks,dir,cks,ofs,[0]
; where
; dn is the disk number 0,1,...,n-1
; fsc is the first sector number (usually 0 or 1)
; lsc is the last sector number on a track
; skf is optional "skew factor" for sector translate
; bls is the data block size (1024,2048,...,16384)
; dks is the disk size in bls increments (word)
; dir is the number of directory elements (word)
; cks is the number of dir elements to checksum
; ofs is the number of tracks to skip (word)
; [0] is an optional 0 which forces 16K/directory entry
;
; for convenience, the form
; dn,dm
; defines disk dn as having the same characteristics as
; a previously defined disk dm.
;
; a standard four drive CP/M system is defined by
; disks 4
; diskdef 0,1,26,6,1024,243,64,64,2
; dsk set 0
; rept 3
; dsk set dsk+1
; diskdef %dsk,0
; endm
; endef
;
; the value of "begdat" at the end of assembly defines the
; beginning of the uninitialize ram area above the bios,
; while the value of "enddat" defines the next location
; following the end of the data area. the size of this
; area is given by the value of "datsiz" at the end of the
; assembly. note that the allocation vector will be quite
; large if a large disk size is defined with a small block
; size.
;
dskhdr macro dn
;; define a single disk header list
dpe&dn: dw xlt&dn,0000h ;translate table
dw 0000h,0000h ;scratch area
dw dirbuf,dpb&dn ;dir buff,parm block
dw csv&dn,alv&dn ;check, alloc vectors
endm
;
disks macro nd
;; define nd disks
ndisks set nd ;;for later reference
dpbase equ $ ;base of disk parameter blocks
;; generate the nd elements
dsknxt set 0
rept nd
dskhdr %dsknxt
dsknxt set dsknxt+1
endm
endm
;
dpbhdr macro dn
dpb&dn equ $ ;disk parm block
endm
;
ddb macro data,comment
;; define a db statement
db data comment
endm
;
ddw macro data,comment
;; define a dw statement
dw data comment
endm
;
gcd macro m,n
;; greatest common divisor of m,n
;; produces value gcdn as result
;; (used in sector translate table generation)
gcdm set m ;;variable for m
gcdn set n ;;variable for n
gcdr set 0 ;;variable for r
rept 65535
gcdx set gcdm/gcdn
gcdr set gcdm - gcdx*gcdn
if gcdr = 0
exitm
endif
gcdm set gcdn
gcdn set gcdr
endm
endm
;
diskdef macro dn,fsc,lsc,skf,bls,dks,dir,cks,ofs,k16
;; generate the set statements for later tables
if nul lsc
;; current disk dn same as previous fsc
dpb&dn equ dpb&fsc ;equivalent parameters
als&dn equ als&fsc ;same allocation vector size
css&dn equ css&fsc ;same checksum vector size
xlt&dn equ xlt&fsc ;same translate table
else
secmax set lsc-(fsc) ;;sectors 0...secmax
sectors set secmax+1;;number of sectors
als&dn set (dks)/8 ;;size of allocation vector
if ((dks) mod 8) ne 0
als&dn set als&dn+1
endif
css&dn set (cks)/4 ;;number of checksum elements
;; generate the block shift value
blkval set bls/128 ;;number of sectors/block
blkshf set 0 ;;counts right 0's in blkval
blkmsk set 0 ;;fills with 1's from right
rept 16 ;;once for each bit position
if blkval=1
exitm
endif
;; otherwise, high order 1 not found yet
blkshf set blkshf+1
blkmsk set (blkmsk shl 1) or 1
blkval set blkval/2
endm
;; generate the extent mask byte
blkval set bls/1024 ;;number of kilobytes/block
extmsk set 0 ;;fill from right with 1's
rept 16
if blkval=1
exitm
endif
;; otherwise more to shift
extmsk set (extmsk shl 1) or 1
blkval set blkval/2
endm
;; may be double byte allocation
if (dks) > 256
extmsk set (extmsk shr 1)
endif
;; may be optional [0] in last position
if not nul k16
extmsk set k16
endif
;; now generate directory reservation bit vector
dirrem set dir ;;# remaining to process
dirbks set bls/32 ;;number of entries per block
dirblk set 0 ;;fill with 1's on each loop
rept 16
if dirrem=0
exitm
endif
;; not complete, iterate once again
;; shift right and add 1 high order bit
dirblk set (dirblk shr 1) or 8000h
if dirrem > dirbks
dirrem set dirrem-dirbks
else
dirrem set 0
endif
endm
dpbhdr dn ;;generate equ $
ddw %sectors,<;sec per track>
ddb %blkshf,<;block shift>
ddb %blkmsk,<;block mask>
ddb %extmsk,<;extnt mask>
ddw %(dks)-1,<;disk size-1>
ddw %(dir)-1,<;directory max>
ddb %dirblk shr 8,<;alloc0>
ddb %dirblk and 0ffh,<;alloc1>
ddw %(cks)/4,<;check size>
ddw %ofs,<;offset>
;; generate the translate table, if requested
if nul skf
xlt&dn equ 0 ;no xlate table
else
if skf = 0
xlt&dn equ 0 ;no xlate table
else
;; generate the translate table
nxtsec set 0 ;;next sector to fill
nxtbas set 0 ;;moves by one on overflow
gcd %sectors,skf
;; gcdn = gcd(sectors,skew)
neltst set sectors/gcdn
;; neltst is number of elements to generate
;; before we overlap previous elements
nelts set neltst ;;counter
xlt&dn equ $ ;translate table
rept sectors ;;once for each sector
if sectors < 256
ddb %nxtsec+(fsc)
else
ddw %nxtsec+(fsc)
endif
nxtsec set nxtsec+(skf)
if nxtsec >= sectors
nxtsec set nxtsec-sectors
endif
nelts set nelts-1
if nelts = 0
nxtbas set nxtbas+1
nxtsec set nxtbas
nelts set neltst
endif
endm
endif ;;end of nul fac test
endif ;;end of nul bls test
endm
;
defds macro lab,space
lab: ds space
endm
;
lds macro lb,dn,val
defds lb&dn,%val&dn
endm
;
endef macro
;; generate the necessary ram data areas
begdat equ $
dirbuf: ds 128 ;directory access buffer
dsknxt set 0
rept ndisks ;;once for each disk
lds alv,%dsknxt,als
lds csv,%dsknxt,css
dsknxt set dsknxt+1
endm
enddat equ $
datsiz equ $-begdat
;; db 0 at this point forces hex record
endm
;

View File

@@ -0,0 +1,214 @@
; FILE DUMP PROGRAM, READS AN INPUT FILE AND PRINTS IN HEX
;
; COPYRIGHT (C) 1975, 1976, 1977, 1978
; DIGITAL RESEARCH
; BOX 579, PACIFIC GROVE
; CALIFORNIA, 93950
;
ORG 100H
BDOS EQU 0005H ;DOS ENTRY POINT
CONS EQU 1 ;READ CONSOLE
TYPEF EQU 2 ;TYPE FUNCTION
PRINTF EQU 9 ;BUFFER PRINT ENTRY
BRKF EQU 11 ;BREAK KEY FUNCTION (TRUE IF CHAR READY)
OPENF EQU 15 ;FILE OPEN
READF EQU 20 ;READ FUNCTION
;
FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS
BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS
;
; NON GRAPHIC CHARACTERS
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
;
; FILE CONTROL BLOCK DEFINITIONS
FCBDN EQU FCB+0 ;DISK NAME
FCBFN EQU FCB+1 ;FILE NAME
FCBFT EQU FCB+9 ;DISK FILE TYPE (3 CHARACTERS)
FCBRL EQU FCB+12 ;FILE'S CURRENT REEL NUMBER
FCBRC EQU FCB+15 ;FILE'S RECORD COUNT (0 TO 128)
FCBCR EQU FCB+32 ;CURRENT (NEXT) RECORD NUMBER (0 TO 127)
FCBLN EQU FCB+33 ;FCB LENGTH
;
; SET UP STACK
LXI H,0
DAD SP
; ENTRY STACK POINTER IN HL FROM THE CCP
SHLD OLDSP
; SET SP TO LOCAL STACK AREA (RESTORED AT FINIS)
LXI SP,STKTOP
; READ AND PRINT SUCCESSIVE BUFFERS
CALL SETUP ;SET UP INPUT FILE
CPI 255 ;255 IF FILE NOT PRESENT
JNZ OPENOK ;SKIP IF OPEN IS OK
;
; FILE NOT THERE, GIVE ERROR MESSAGE AND RETURN
LXI D,OPNMSG
CALL ERR
JMP FINIS ;TO RETURN
;
OPENOK: ;OPEN OPERATION OK, SET BUFFER INDEX TO END
MVI A,80H
STA IBP ;SET BUFFER POINTER TO 80H
; HL CONTAINS NEXT ADDRESS TO PRINT
LXI H,0 ;START WITH 0000
;
GLOOP:
PUSH H ;SAVE LINE POSITION
CALL GNB
POP H ;RECALL LINE POSITION
JC FINIS ;CARRY SET BY GNB IF END FILE
MOV B,A
; PRINT HEX VALUES
; CHECK FOR LINE FOLD
MOV A,L
ANI 0FH ;CHECK LOW 4 BITS
JNZ NONUM
; PRINT LINE NUMBER
CALL CRLF
;
; CHECK FOR BREAK KEY
CALL BREAK
; ACCUM LSB = 1 IF CHARACTER READY
RRC ;INTO CARRY
JC FINIS ;DON'T PRINT ANY MORE
;
MOV A,H
CALL PHEX
MOV A,L
CALL PHEX
NONUM:
INX H ;TO NEXT LINE NUMBER
MVI A,' '
CALL PCHAR
MOV A,B
CALL PHEX
JMP GLOOP
;
FINIS:
; END OF DUMP, RETURN TO CCP
; (NOTE THAT A JMP TO 0000H REBOOTS)
CALL CRLF
LHLD OLDSP
SPHL
; STACK POINTER CONTAINS CCP'S STACK LOCATION
RET ;TO THE CCP
;
;
; SUBROUTINES
;
BREAK: ;CHECK BREAK KEY (ACTUALLY ANY KEY WILL DO)
PUSH H! PUSH D! PUSH B; ENVIRONMENT SAVED
MVI C,BRKF
CALL BDOS
POP B! POP D! POP H; ENVIRONMENT RESTORED
RET
;
PCHAR: ;PRINT A CHARACTER
PUSH H! PUSH D! PUSH B; SAVED
MVI C,TYPEF
MOV E,A
CALL BDOS
POP B! POP D! POP H; RESTORED
RET
;
CRLF:
MVI A,CR
CALL PCHAR
MVI A,LF
CALL PCHAR
RET
;
;
PNIB: ;PRINT NIBBLE IN REG A
ANI 0FH ;LOW 4 BITS
CPI 10
JNC P10
; LESS THAN OR EQUAL TO 9
ADI '0'
JMP PRN
;
; GREATER OR EQUAL TO 10
P10: ADI 'A' - 10
PRN: CALL PCHAR
RET
;
PHEX: ;PRINT HEX CHAR IN REG A
PUSH PSW
RRC
RRC
RRC
RRC
CALL PNIB ;PRINT NIBBLE
POP PSW
CALL PNIB
RET
;
ERR: ;PRINT ERROR MESSAGE
; D,E ADDRESSES MESSAGE ENDING WITH "$"
MVI C,PRINTF ;PRINT BUFFER FUNCTION
CALL BDOS
RET
;
;
GNB: ;GET NEXT BYTE
LDA IBP
CPI 80H
JNZ G0
; READ ANOTHER BUFFER
;
;
CALL DISKR
ORA A ;ZERO VALUE IF READ OK
JZ G0 ;FOR ANOTHER BYTE
; END OF DATA, RETURN WITH CARRY SET FOR EOF
STC
RET
;
G0: ;READ THE BYTE AT BUFF+REG A
MOV E,A ;LS BYTE OF BUFFER INDEX
MVI D,0 ;DOUBLE PRECISION INDEX TO DE
INR A ;INDEX=INDEX+1
STA IBP ;BACK TO MEMORY
; POINTER IS INCREMENTED
; SAVE THE CURRENT FILE ADDRESS
LXI H,BUFF
DAD D
; ABSOLUTE CHARACTER ADDRESS IS IN HL
MOV A,M
; BYTE IS IN THE ACCUMULATOR
ORA A ;RESET CARRY BIT
RET
;
SETUP: ;SET UP FILE
; OPEN THE FILE FOR INPUT
XRA A ;ZERO TO ACCUM
STA FCBCR ;CLEAR CURRENT RECORD
;
LXI D,FCB
MVI C,OPENF
CALL BDOS
; 255 IN ACCUM IF OPEN ERROR
RET
;
DISKR: ;READ DISK FILE RECORD
PUSH H! PUSH D! PUSH B
LXI D,FCB
MVI C,READF
CALL BDOS
POP B! POP D! POP H
RET
;
; FIXED MESSAGE AREA
SIGNON: DB 'FILE DUMP VERSION 1.4$'
OPNMSG: DB CR,LF,'NO INPUT FILE PRESENT ON DISK$'
; VARIABLE AREA
IBP: DS 2 ;INPUT BUFFER POINTER
OLDSP: DS 2 ;ENTRY SP VALUE FROM CCP
;
; STACK AREA
DS 64 ;RESERVE 32 LEVEL STACK
STKTOP:
;
END

View File

@@ -0,0 +1,219 @@
0000 ED#
0000 ED#
0AF3 17 0AF3 18 0AFC 19 0AFC 22 0B00 24
0B07 25 0B08 26 0B13 27 0B14 29 0B18 31
0B20 32 0B24 33 0B2C 34 0B31 35 0B38 36
0B39 37 0B39 38 0B41 39 0B42 40 0B47 41
0B4C 42 0B51 43 0B56 44 0B57 45 0B5B 47
0B73 48 0B78 49 0B7D 50 0B8C 51 0B93 52
0B9A 53 0B9B 54 0B9F 56 0BA7 57 0BAA 58
0BCB 59 0BCB 60 0BCF 62 0BDA 64 0BDF 65
0BE7 66 0BE7 67 0BEE 68 0BEF 69 0BEF 70
0BF4 71 0BF9 72 0BFA 73 0C00 75 0C09 76
0C0A 77 0C10 79 0C13 80 0C1B 81 0C1C 82
0C22 84 0C2B 85 0C2C 87 0C32 89 0C3E 90
0C3F 91 0C45 93 0C51 94 0C52 95 0C58 97
0C64 98 0C65 99 0C6B 101 0C74 102 0C75 103
0C7B 105 0C85 106 0C85 107 0C8B 109 0C95 110
0C95 111 0C9B 113 0CA7 114 0CA8 115 0CAE 117
0CB7 118 0CB8 120 0CB8 121 0CBD 122 0CC3 123
0CC4 124 0CC4 125 0CD0 127 0CD8 128 0CDB 129
0CDB 130 0CDE 131 0CDE 132 0CDE 133 0CE7 134
0CE7 135 0CEB 137 0CF6 138 0CF7 139 0CFD 141
0D06 142 0D07 143 0D07 144 0D0E 145 0D14 146
0D17 147 0D18 149 0D1E 151 0D26 152 0D29 153
0D2C 154 0D2D 155 0D2D 156 0D33 157 0D39 158
0D3A 159 0D40 161 0D54 162 0D55 163 0D55 164
0D5B 165 0D61 166 0D70 167 0D80 168 0D8A 170
0D91 171 0D97 172 0D9F 173 0DA5 174 0DA5 175
0DAC 176 0DB2 177 0DBA 179 0DC0 180 0DC8 181
0DCB 182 0DD1 183 0DD4 184 0DD7 185 0DDF 187
0DE5 188 0DE8 189 0DEB 190 0DF3 191 0DF9 192
0DFF 193 0E05 194 0E0F 196 0E16 197 0E1C 198
0E1C 199 0E22 200 0E28 201 0E2E 202 0E33 203
0E3B 204 0E3E 205 0E44 206 0E45 207 0E45 208
0E59 209 0E5A 210 0E5A 211 0E61 212 0E67 213
0E68 214 0ED3 216 0ED3 217 0ED9 218 0E68 219
0E6B 220 0E72 221 0E81 222 0E8E 223 0E9C 225
0EA5 226 0EA8 227 0EB2 228 0EB8 229 0EBB 230
0EC5 231 0ECF 232 0ED2 233 0EDA 234 0EDA 236
0EE6 237 0EE9 238 0EFA 239 0F01 240 0F05 241
0F05 242 0F66 244 0F66 245 0F6C 246 0F05 247
0F0C 248 0F20 249 0F21 250 0F24 251 0F33 252
0F40 253 0F4B 254 0F4E 255 0F58 256 0F62 257
0F65 258 0F6D 259 0F71 261 0F7D 262 0F80 263
0F8C 264 0F93 265 0F94 266 0F98 268 0FA0 270
0FA3 271 0FAE 272 0FB1 273 0FB6 274 0FB6 275
0FC3 276 0FCA 277 0FCB 278 103B 279 103B 280
104B 281 0FCB 282 0FD0 283 0FDB 284 0FE2 285
0FE7 286 0FEA 287 0FED 288 0FF3 289 0FFB 290
0FFE 291 1004 292 1007 293 100E 294 101E 295
1024 296 1027 297 102D 298 1034 299 103A 300
104C 306 1050 308 1058 309 1059 310 1060 311
1061 313 1065 315 1079 316 1079 317 107D 319
1088 320 108E 321 1092 322 1092 323 1096 325
109D 326 10A5 327 10A9 328 10A9 329 10AF 331
10B5 332 10BA 333 10C6 334 10D4 335 10E1 336
10EF 337 10FF 339 1104 340 110D 341 1110 342
1115 343 1118 344 1119 345 111F 347 1127 348
1128 349 1130 350 1135 351 113A 352 1141 353
1149 354 114E 355 114F 356 114F 357 1157 358
1158 359 1158 360 1160 361 1161 362 1164 363
1165 364 1165 365 116E 367 1175 368 1178 369
1182 371 118E 373 119E 374 11A1 375 11A1 376
11A6 377 11A6 378 11BA 379 11BA 380 11C1 381
11C9 382 11D0 384 11D5 385 11E5 387 11F1 388
11FA 389 11FD 390 1200 391 1205 392 1208 393
120D 394 1212 395 1217 396 1217 397 1228 398
1233 399 1247 400 1247 401 1247 402 124E 403
1254 404 1255 405 1255 406 125D 408 1260 409
126B 410 126E 411 1273 412 1273 413 1287 414
1287 416 1287 417 128D 418 128E 419 128E 420
129B 421 129B 422 129B 423 12A1 424 12A2 425
12A2 426 12AA 428 12B1 429 12B4 430 12B4 431
12B7 432 12B7 433 12B7 435 12BD 436 12C5 438
12CC 439 12D2 440 12D8 441 12DC 442 12DF 444
12E5 445 12EB 446 12F1 447 12F1 448 12F6 449
12FD 450 132A 451 1330 452 1333 453 133A 454
134D 455 1355 457 135A 458 1368 459 136B 460
1372 461 1378 462 137B 463 1383 465 1389 466
1390 467 1393 469 139A 470 13A1 471 13A1 472
13A2 473 13A2 474 13A9 475 13AA 476 13AA 477
13B1 478 13B2 479 13B2 480 13B9 481 13BA 482
13BA 483 13C1 484 13C2 485 13C2 486 13C9 487
13CA 488 13CE 490 13D6 491 13E2 492 13E5 493
13EC 495 13FC 496 13FF 497 140A 498 140D 499
140D 500 1413 501 141F 502 1422 503 1432 504
1439 505 1440 507 144B 508 144E 509 144E 510
1451 511 1452 512 1452 513 1457 514 1458 515
1458 516 145D 517 145E 518 145E 519 1461 520
1464 521 1465 522 1465 523 146D 525 1473 526
147F 527 1488 528 1494 529 1497 531 149D 532
14AF 533 14B8 534 14C3 535 14C3 536 14C4 537
1504 539 1508 541 150F 542 1517 543 151B 544
14C4 545 14C4 546 14D0 547 14D3 548 14E2 550
14E5 551 14E6 552 14E6 553 14F1 554 14F4 555
14FC 557 14FF 558 1500 559 1500 560 1503 561
151B 562 151B 564 151B 565 1527 567 152A 568
152B 569 152B 570 152E 571 153D 572 1545 574
1548 575 1549 576 1549 577 154C 578 154D 579
154D 580 1550 581 1557 582 1569 583 156F 584
1572 585 1575 586 1576 587 1576 588 157B 589
1581 590 1587 591 158A 592 1591 593 1594 594
159B 595 159E 596 15A1 597 15AD 599 15B2 600
15B5 601 15B5 602 15B6 603 15B6 604 15B9 605
15BC 606 15BD 607 15BD 608 15C0 609 15CB 610
15D2 611 15D5 612 15D8 613 15D9 614 15D9 615
15E6 616 15E9 617 15F4 618 15F7 619 15FF 620
1602 621 1603 622 1603 623 1624 624 1624 625
1652 626 1652 627 165F 628 166B 629 166E 630
1624 631 162B 632 1633 634 1638 635 163B 636
1640 637 1640 638 1648 639 164B 640 164E 641
1651 642 166F 643 1675 646 167B 647 1680 648
1696 649 16A0 650 16A6 651 16D3 652 16DA 653
16E1 654 16E4 655 16E7 656 16EE 658 16F5 659
16F8 660 16F8 661 16FC 662 16FC 663 16FC 664
1701 665 1704 666 170A 667 170B 668 170B 669
1719 670 171C 671 171D 672 171D 673 1737 674
1738 675 1738 676 1745 677 1746 678 1746 681
1749 682 174E 683 1756 685 175C 686 1762 687
1765 688 176B 689 178C 690 178F 691 17A1 692
17A9 694 17AC 695 17B3 696 17BA 697 17BD 698
17BD 699 17CC 700 17D9 701 17DA 702 17DA 703
17E0 704 17E1 705 17E1 706 17E7 707 17E8 708
17E8 709 17EE 710 17EF 711 17EF 713 17F2 714
17F5 715 17F8 716 17FE 717 1803 718 1806 719
1809 720 180F 721 1830 722 1836 723 1839 724
183A 725 183A 727 1848 728 184F 729 1852 730
1857 731 1861 732 1862 733 1862 734 1867 735
186D 736 186E 737 186E 738 1871 739 1878 740
1884 741 188A 742 188D 743 1890 744 1891 745
1891 746 1896 747 1899 748 189E 749 18A1 750
18A2 751 18A2 753 18A7 754 18B1 755 18BB 756
18C5 757 18C6 758 18C6 759 18CB 760 18D1 761
18D4 762 18D5 763 18D9 765 18FC 766 18FC 767
1900 769 190B 771 190E 772 1915 773 191D 774
1927 775 192A 776 1932 777 1935 778 1938 779
1938 780 193B 781 01C0 782 01DA 783 01E9 784
01F9 786 01FF 787 0202 788 0202 789 0211 790
021E 791 022A 792 0236 793 023F 794 0246 795
0253 796 025D 797 0262 798 027A 799 027D 800
0288 801 0291 803 0298 804 029D 805 029D 806
02A8 807 02B1 808 02B8 809 02BB 810 02BE 811
02C3 812 02C9 813 02CF 814 02D4 815 02D7 816
02DF 817 02E2 818 02EA 819 02ED 820 02F5 821
02FD 822 0303 823 030A 824 0310 825 0317 826
031A 827 0322 828 0327 829 0327 830 032C 831
032F 832 0335 833 033E 835 0341 836 034B 837
035C 838 035F 839 0362 840 036B 842 036E 843
0374 844 037A 845 0380 846 0383 847 0386 848
038E 850 03AB 851 03AE 852 03B4 853 03BB 854
03C3 855 03E7 857 03ED 858 03F2 859 03F9 861
03FC 862 03FF 863 0402 865 0405 866 0408 867
0410 869 0413 870 0416 871 0419 872 0423 873
0426 874 0429 875 0429 876 042C 877 0434 879
0441 880 0446 881 045F 883 046D 885 0470 886
0475 887 047A 888 0480 889 0485 890 0488 891
048D 892 049A 893 04A0 894 04A6 895 04B0 896
04B3 897 04B6 898 04BC 899 04BC 900 04BC 901
04C1 902 04C7 903 04CA 904 04D2 906 04DE 907
04E1 908 04E4 909 04F3 910 04FB 911 0502 912
0507 913 050A 915 0516 917 051B 918 0524 919
0524 920 052C 921 0532 923 053A 925 0542 926
054C 927 0554 928 0562 929 0562 930 0565 931
0565 932 0565 933 056D 934 0570 935 0578 936
0585 937 058A 938 058D 939 0590 940 0598 941
059B 942 05A6 943 05A9 944 05AC 945 05B5 946
05B8 947 05C0 950 05C5 951 05C8 952 05CF 953
05D8 954 05DB 955 05DE 956 05E1 957 05E6 958
05F5 960 0605 961 060B 962 060E 963 0617 964
061A 965 061D 966 0627 967 062D 968 0632 969
063A 971 063F 972 0642 973 0642 974 064D 975
0650 976 0653 977 0658 978 065F 979 0669 980
0676 981 067D 982 0680 983 0683 984 0686 985
068F 987 0695 988 0698 989 193B 992 193B 993
194A 994 194A 995 194A 996 1950 997 1957 998
196F 999 1972 1000 1975 1001 1976 1002 1976 1003
1982 1005 1987 1006 1995 1007 1998 1009 199D 1010
19A9 1011 19A9 1012 069B 1013 069E 1014 06A6 1016
06A9 1017 06AE 1018 06AE 1019 06B6 1021 06B9 1022
06BC 1023 06BF 1024 06C6 1026 06C9 1027 06D1 1029
06D6 1030 06D9 1031 06D9 1032 06DC 1033 06E4 1035
06E7 1036 06EA 1037 06ED 1038 06F5 1039 06FC 1040
06FC 1041 0703 1042 0708 1043 0710 1045 0717 1046
071D 1047 0723 1048 0726 1049 0729 1050 0731 1052
0734 1053 0737 1054 073A 1055 0742 1057 0745 1058
0748 1059 074B 1060 0753 1062 0756 1063 0759 1064
075C 1065 0764 1066 076A 1067 0772 1069 0779 1071
077E 1072 0781 1073 0784 1074 0787 1075 078E 1076
0791 1077 0794 1078 0797 1079 079A 1080 07A2 1081
07A8 1082 07B0 1083 07BE 1084 07C6 1086 07CD 1088
07DB 1089 07E0 1090 07E8 1091 07EB 1092 07EE 1093
07F9 1094 07FC 1095 0804 1097 081C 1099 081F 1100
0822 1101 0825 1102 0825 1103 0828 1104 083B 1106
0843 1108 0848 1109 084E 1110 0854 1111 0857 1112
085E 1113 0861 1114 0868 1115 086B 1116 086E 1117
0873 1118 0876 1119 0879 1120 0881 1122 0884 1123
088B 1124 088E 1125 0891 1126 0894 1127 089C 1130
089F 1131 08A2 1132 08A8 1133 08AB 1134 08B2 1135
08B5 1136 08BC 1137 08CA 1138 08D7 1139 08DA 1140
08DD 1141 08E3 1142 08F3 1143 08F6 1144 0906 1145
090B 1146 090E 1147 0914 1148 0917 1149 091A 1150
0932 1152 0937 1153 0943 1154 0946 1155 0961 1156
0964 1157 096A 1158 096F 1159 0979 1160 097C 1161
0984 1163 0987 1164 098E 1165 099C 1166 09A3 1167
09A6 1168 09A9 1169 09AC 1170 09AF 1171 09B4 1172
09BA 1173 09BD 1174 09C0 1175 09C5 1176 09D1 1177
09D4 1178 09D7 1179 09DA 1180 09DD 1181 09E5 1183
09E8 1184 09EB 1185 09F2 1186 09F5 1187 0A06 1188
0A10 1189 0A1D 1190 0A24 1191 0A27 1192 0A2A 1193
0A2D 1194 0A30 1195 0A38 1196 0A3E 1197 0A46 1199
0A49 1200 0A50 1202 0A53 1203 0A59 1204 0A5C 1207
0A64 1209 0A67 1210 0A6C 1211 0A72 1212 0A78 1213
0A80 1214 0A83 1215 0A83 1216 0A86 1217 0A98 1218
0AA3 1219 0AB0 1220 0AB0 1221 0AB3 1222 0ABB 1224
0AC2 1226 0ACA 1227 0ACD 1228 0ACD 1229 0AD4 1230
0AD7 1231 0ADA 1232 0ADD 1233 0AE5 1234 0AE8 1235
0AEB 1236 0AEE 1237 0AEE 1238 0AF1 1239
0000 MODULE#

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
; assembly language version of mem$move for ed speedup
; version 2.0 of ED
;
mem$move equ 13cah
moveflag equ 1d34h
direction equ 1d20h
front equ 1d22h
back equ 1d24h
first equ 1d26h
last equ 1d28h
baseline equ 1c10h
memory equ 1d4dh
;
forward equ 1
lf equ 0ah
;
org mem$move
lxi h,moveflag
mov m,c ;1 = move data
lxi d,memory
lhld front
dad d ;memory+front
push h
lhld back
dad d
push h
lda direction
cpi forward
jnz moveback
lhld last
mov a,c ;moveflag to a
rar
jc moveforw
; set back to last
shld back
pop h
pop h
ret
;
moveforw:
dad d ;memory+last
mov b,h
mov c,l
pop h
pop d ;bc=last, de=front, hl=back
movef: mov a,l ;back < last?
sub c
mov a,h
sbb b ;cy if true
jnc emove
inx h ;back=back+1
mov a,m ;char to a
cpi lf ;end of line?
jnz notlff
push h
lhld baseline
inx h ;baseline=baseline+1
shld baseline
pop h
notlff:
stax d ;to front
inx d ;front=front+1
jmp movef
moveback:
lhld first
dad d ;memory+first
mov b,h
mov c,l
pop h
pop d ;bc=first, de=front, hl=last
moveb: mov a,c ;first > front?
sub e
mov a,b
sbb d ;cy if true
jnc emove
dcx d ;front=front-1
ldax d ;char to a
cpi lf
jnz notlfb
push h
lhld baseline
dcx h ;baseline=baseline-1
shld baseline
pop h
notlfb: push psw ;save char
lda moveflag
rar
jnc nomove
pop psw
mov m,a ;store to back
dcx h
jmp moveb
nomove: pop psw
jmp moveb
;
emove: push d
lxi d,-memory
dad d ;relative value of back
shld back
pop h
dad d ;relative value of front
shld front
ret
end

View File

@@ -0,0 +1,46 @@
0000 LOAD#
0000 LOAD#
023B 13 023B 14 023F 15 0240 16 0240 17
02D0 22 02D4 24 02DF 25 02E0 26 02E0 27
02E5 28 02EA 29 02EB 30 02EF 32 02F8 33
0306 34 030F 35 0310 36 0314 38 0321 39
032A 40 032B 41 0331 43 0339 44 0341 45
0342 46 0348 48 0351 49 0352 50 0358 52
035B 53 0363 54 0364 56 036A 58 0370 59
0378 60 037E 61 0386 62 0389 63 038A 65
0390 67 039C 68 039D 69 03A3 71 03AF 72
03B0 73 03B6 75 03C2 76 03C3 77 03C3 78
03CE 79 03CF 80 03D5 82 03DE 83 03DF 84
03E5 86 03EF 87 03EF 88 03F5 90 03FF 91
03FF 92 0405 94 0411 95 0412 96 0418 98
0421 99 0422 100 0431 102 043D 103 0447 104
044E 105 0455 106 0458 107 0459 108 0459 110
0469 111 0472 112 0497 113 04A5 114 04BA 116
04C2 117 04C8 118 04D1 119 04D7 120 04D7 121
04DA 122 04E0 123 04E4 124 04E4 126 05FD 129
0601 131 060D 132 0613 133 0624 134 0632 135
064A 136 0651 137 0658 138 065C 139 0667 141
066D 142 066D 143 0670 144 067F 145 0680 146
06E6 148 06E6 149 06E9 150 06F1 151 06F6 152
06FB 153 0680 154 0686 155 068E 156 0694 157
069C 158 06A2 159 06A5 160 06B1 161 06BC 162
06BF 163 06D0 164 06D7 165 06DC 166 06DF 167
06E2 168 06E5 169 06FC 170 06FC 172 070B 173
0711 174 071D 176 0723 177 0726 178 0726 179
072E 180 072E 181 072E 182 073D 183 073D 184
073D 186 0748 187 074C 188 074C 189 0752 191
0763 192 04E4 193 04F0 194 04F4 195 04FD 196
0502 197 0502 198 050A 199 050D 200 0512 201
051D 202 0520 203 052E 204 0541 205 054D 206
0553 207 0559 208 0565 209 056C 210 0573 211
0576 212 0582 213 0589 214 0595 216 059B 217
059E 218 059E 219 05A1 220 05A7 221 05B3 222
05B8 223 05BF 224 05C2 225 05C8 226 05D0 227
05D6 228 05DE 229 05E4 230 05EC 231 05F2 232
05F9 233 05FC 234 0240 236 0247 237 024B 238
0251 239 0257 240 0263 241 026F 242 0275 243
027D 244 0283 245 028F 246 0295 247 029B 248
02A1 249 02A9 250 02B2 252 02B5 253 02BB 254
02C3 255 02C9 256 02C9 257 02CC 258 02CF 259
0000 MODULE#

View File

@@ -0,0 +1,359 @@
LOAD:
DO;
/* C P / M C O M M A N D F I L E L O A D E R
COPYRIGHT (C) 1976, 1977, 1978
DIGITAL RESEARCH
BOX 579 PACIFIC GROVE
CALIFORNIA 93950
*/
DECLARE
TPA LITERALLY '0100H', /* TRANSIENT PROGRAM AREA */
DFCBA LITERALLY '005CH', /* DEFAULT FILE CONTROL BLOCK */
DBUFF LITERALLY '0080H'; /* DEFAULT BUFFER ADDRESS */
/* JMP LOADCOM TO START LOAD */
DECLARE JUMP BYTE DATA(0C3H);
DECLARE JUMPA ADDRESS DATA(.LOADCOM);
DECLARE COPYRIGHT(*) BYTE DATA
(' COPYRIGHT (C) 1978, DIGITAL RESEARCH ');
MON1: PROCEDURE(F,A) EXTERNAL;
DECLARE F BYTE, A ADDRESS;
END MON1;
MON2: PROCEDURE(F,A) BYTE EXTERNAL;
DECLARE F BYTE, A ADDRESS;
END MON2;
DECLARE SP ADDRESS;
BOOT: PROCEDURE;
STACKPTR = SP;
RETURN;
END BOOT;
LOADCOM: PROCEDURE;
DECLARE FCB (33) BYTE AT (DFCBA),
FCBA LITERALLY 'DFCBA';
DECLARE BUFFER (128) BYTE AT (DBUFF),
BUFFA LITERALLY 'DBUFF';
DECLARE SFCB(33) BYTE, /* SOURCE FILE CONTROL BLOCK */
BSIZE LITERALLY '1024',
EOFILE LITERALLY '1AH',
SBUFF(BSIZE) BYTE, /* SOURCE FILE BUFFER */
RFLAG BYTE, /* READER FLAG */
SBP ADDRESS; /* SOURCE FILE BUFFER POINTER */
/* LOADCOM LOADS TRANSIENT COMMAND FILES TO THE DISK FROM THE
CURRENTLY DEFINED READER PERIPHERAL. THE LOADER PLACES THE MACHINE
CODE INTO A FILE WHICH APPEARS IN THE LOADCOM COMMAND */
DECLARE
TRUE LITERALLY '1',
FALSE LITERALLY '0',
FOREVER LITERALLY 'WHILE TRUE',
CR LITERALLY '13',
LF LITERALLY '10',
WHAT LITERALLY '63';
PRINTCHAR: PROCEDURE(CHAR);
DECLARE CHAR BYTE;
CALL MON1(2,CHAR);
END PRINTCHAR;
CRLF: PROCEDURE;
CALL PRINTCHAR(CR);
CALL PRINTCHAR(LF);
END CRLF;
PRINTNIB: PROCEDURE(N);
DECLARE N BYTE;
IF N > 9 THEN CALL PRINTCHAR(N+'A'-10); ELSE
CALL PRINTCHAR(N+'0');
END PRINTNIB;
PRINTHEX: PROCEDURE(B);
DECLARE B BYTE;
CALL PRINTNIB(SHR(B,4)); CALL PRINTNIB(B AND 0FH);
END PRINTHEX;
PRINTADDR: PROCEDURE(A);
DECLARE A ADDRESS;
CALL PRINTHEX(HIGH(A)); CALL PRINTHEX(LOW(A));
END PRINTADDR;
PRINTM: PROCEDURE(A);
DECLARE A ADDRESS;
CALL MON1(9,A);
END PRINTM;
PRINT: PROCEDURE(A);
DECLARE A ADDRESS;
/* PRINT THE STRING STARTING AT ADDRESS A UNTIL THE
NEXT DOLLAR SIGN IS ENCOUNTERED WITH PRECEDING CRLF */
CALL CRLF;
CALL PRINTM(A);
END PRINT;
DECLARE LA ADDRESS; /* CURRENT LOAD ADDRESS */
PERROR: PROCEDURE(A);
/* PRINT ERROR MESSAGE */
DECLARE A ADDRESS;
CALL PRINT(.('ERROR: $'));
CALL PRINTM(A);
CALL PRINTM(.(', LOAD ADDRESS $'));
CALL PRINTADDR(LA);
CALL BOOT;
END PERROR;
DECLARE DCNT BYTE;
OPEN: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(15,FCB);
END OPEN;
CLOSE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(16,FCB);
END CLOSE;
SEARCH: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(17,FCB);
END SEARCH;
SEARCHN: PROCEDURE;
DCNT = MON2(18,0);
END SEARCHN;
DELETE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL MON1(19,FCB);
END DELETE;
DISKREAD: PROCEDURE(FCB) BYTE;
DECLARE FCB ADDRESS;
RETURN MON2(20,FCB);
END DISKREAD;
DISKWRITE: PROCEDURE(FCB) BYTE;
DECLARE FCB ADDRESS;
RETURN MON2(21,FCB);
END DISKWRITE;
MAKE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
DCNT = MON2(22,FCB);
END MAKE;
RENAME: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL MON1(23,FCB);
END RENAME;
MOVE: PROCEDURE(S,D,N);
DECLARE (S,D) ADDRESS, N BYTE,
A BASED S BYTE, B BASED D BYTE;
DO WHILE (N:=N-1) <> 255;
B = A; S=S+1; D=D+1;
END;
END MOVE;
GETCHAR: PROCEDURE BYTE;
/* GET NEXT CHARACTER */
DECLARE I BYTE;
IF (SBP := SBP+1) <= LAST(SBUFF) THEN
RETURN SBUFF(SBP);
/* OTHERWISE READ ANOTHER BUFFER FULL */
DO SBP = 0 TO LAST(SBUFF) BY 128;
IF (I:=DISKREAD(.SFCB)) = 0 THEN
CALL MOVE(80H,.SBUFF(SBP),80H); ELSE
DO;
IF I<>1 THEN CALL PERROR(.('DISK READ$'));
SBUFF(SBP) = EOFILE;
SBP = LAST(SBUFF);
END;
END;
SBP = 0; RETURN SBUFF(0);
END GETCHAR;
DECLARE
STACKPOINTER LITERALLY 'STACKPTR';
/* INTEL HEX FORMAT LOADER */
RELOC: PROCEDURE;
DECLARE (RL, CS, RT) BYTE;
DECLARE
TA ADDRESS, /* TEMP ADDRESS */
SA ADDRESS, /* START ADDRESS */
FA ADDRESS, /* FINAL ADDRESS */
NB ADDRESS, /* NUMBER OF BYTES LOADED */
MBUFF(256) BYTE,
P BYTE,
L ADDRESS;
SETMEM: PROCEDURE(B);
/* SET MBUFF TO B AT LOCATION LA MOD LENGTH(MBUFF) */
DECLARE (B,I) BYTE;
IF LA < L THEN
CALL PERROR(.('INVERTED LOAD ADDRESS$'));
DO WHILE LA > L + LAST(MBUFF); /* WRITE A PARAGRAPH */
DO I = 0 TO 127; /* COPY INTO BUFFER */
BUFFER(I) = MBUFF(LOW(L)); L = L + 1;
END;
/* WRITE BUFFER ONTO DISK */
P = P + 1;
IF DISKWRITE(FCBA) <> 0 THEN
DO; CALL PERROR(.('DISK WRITE$'));
END;
END;
MBUFF(LOW(LA)) = B;
END SETMEM;
DIAGNOSE: PROCEDURE;
DECLARE M BASED TA BYTE;
NEWLINE: PROCEDURE;
CALL CRLF; CALL PRINTADDR(TA); CALL PRINTCHAR(':');
CALL PRINTCHAR(' ');
END NEWLINE;
/* PRINT DIAGNOSTIC INFORMATION AT THE CONSOLE */
CALL PRINT(.('LOAD ADDRESS $')); CALL PRINTADDR(TA);
CALL PRINT(.('ERROR ADDRESS $')); CALL PRINTADDR(LA);
CALL PRINT(.('BYTES READ:$')); CALL NEWLINE;
DO WHILE TA < LA;
IF (LOW(TA) AND 0FH) = 0 THEN CALL NEWLINE;
CALL PRINTHEX(MBUFF(TA-L)); TA=TA+1;
CALL PRINTCHAR(' ');
END;
CALL CRLF;
CALL BOOT;
END DIAGNOSE;
READHEX: PROCEDURE BYTE;
/* READ ONE HEX CHARACTER FROM THE INPUT */
DECLARE H BYTE;
IF (H := GETCHAR) - '0' <= 9 THEN RETURN H - '0';
IF H - 'A' > 5 THEN
DO; CALL PRINT(.('INVALID HEX DIGIT$'));
CALL DIAGNOSE;
END;
RETURN H - 'A' + 10;
END READHEX;
READBYTE: PROCEDURE BYTE;
/* READ TWO HEX DIGITS */
RETURN SHL(READHEX,4) OR READHEX;
END READBYTE;
READCS: PROCEDURE BYTE;
/* READ BYTE WHILE COMPUTING CHECKSUM */
DECLARE B BYTE;
CS = CS + (B := READBYTE);
RETURN B;
END READCS;
MAKE$DOUBLE: PROCEDURE(H,L) ADDRESS;
/* CREATE A BOUBLE BYTE VALUE FROM TWO SINGLE BYTES */
DECLARE (H,L) BYTE;
RETURN SHL(DOUBLE(H),8) OR L;
END MAKE$DOUBLE;
/* INITIALIZE */
SA, FA, NB = 0;
P = 0; /* PARAGRAPH COUNT */
TA,L = TPA; /* BASE ADDRESS OF TRANSIENT ROUTINES */
SBUFF(0) = EOFILE;
/* READ RECORDS UNTIL :00XXXX IS ENCOUNTERED */
DO FOREVER;
/* SCAN THE : */
DO WHILE GETCHAR <> ':';
END;
/* SET CHECK SUM TO ZERO, AND SAVE THE RECORD LENGTH */
CS = 0;
/* MAY BE THE END OF TAPE */
IF (RL := READCS) = 0 THEN
GO TO FIN;
NB = NB + RL;
TA, LA = MAKE$DOUBLE(READCS,READCS);
IF SA = 0 THEN SA = LA;
/* READ THE RECORD TYPE (NOT CURRENTLY USED) */
RT = READCS;
/* PROCESS EACH BYTE */
DO WHILE (RL := RL - 1) <> 255;
CALL SETMEM(READCS); LA = LA+1;
END;
IF LA > FA THEN FA = LA - 1;
/* NOW READ CHECKSUM AND COMPARE */
IF CS + READBYTE <> 0 THEN
DO; CALL PRINT(.('CHECK SUM ERROR $'));
CALL DIAGNOSE;
END;
END;
FIN:
/* EMPTY THE BUFFERS */
TA = LA;
DO WHILE L < TA;
CALL SETMEM(0); LA = LA+1;
END;
/* PRINT FINAL STATISTICS */
CALL PRINT(.('FIRST ADDRESS $')); CALL PRINTADDR(SA);
CALL PRINT(.('LAST ADDRESS $')); CALL PRINTADDR(FA);
CALL PRINT(.('BYTES READ $')); CALL PRINTADDR(NB);
CALL PRINT(.('RECORDS WRITTEN $')); CALL PRINTHEX(P);
CALL CRLF;
END RELOC;
/* ARRIVE HERE FROM THE SYSTEM MONITOR, READY TO READ THE HEX TAPE */
/* SET UP STACKPOINTER IN THE LOCAL AREA */
DECLARE STACK(16) ADDRESS;
SP = STACKPOINTER; STACKPOINTER = .STACK(LENGTH(STACK));
LA = TPA;
SBP = LENGTH(SBUFF);
/* SET UP THE SOURCE FILE */
CALL MOVE(FCBA,.SFCB,33);
CALL MOVE(.('HEX',0),.SFCB(9),4);
CALL OPEN(.SFCB);
IF DCNT = 255 THEN CALL PERROR(.('CANNOT OPEN SOURCE$'));
CALL MOVE(.('COM'),FCBA+9,3);
/* REMOVE ANY EXISTING FILE BY THIS NAME */
CALL DELETE(FCBA);
/* THEN OPEN A NEW FILE */
CALL MAKE(FCBA); CALL OPEN(FCBA);
IF DCNT = 255 THEN CALL PERROR(.('NO MORE DIRECTORY SPACE$')); ELSE
DO; CALL RELOC;
CALL CLOSE(FCBA);
IF DCNT = 255 THEN CALL PERROR(.('CANNOT CLOSE FILE$'));
END;
CALL CRLF;
CALL BOOT;
END LOADCOM;
END;

View File

@@ -0,0 +1,126 @@
title 'mds cold start loader at 3000h'
;
; MDS-800 Cold Start Loader for CP/M 2.0
;
; Version 2.0 August, 1979
;
false equ 0
true equ not false
testing equ false ;if true, then go to mon80 on errors
;
if testing
bias equ 03400h
endif
if not testing
bias equ 0000h
endif
cpmb equ bias ;base of dos load
bdos equ 806h+bias ;entry to dos for calls
bdose equ 1880h+bias ;end of dos load
boot equ 1600h+bias ;cold start entry point
rboot equ boot+3 ;warm start entry point
;
org 03000h ;loaded down from hardware boot at 3000h
;
bdosl equ bdose-cpmb
ntrks equ 2 ;number of tracks to read
bdoss equ bdosl/128 ;number of sectors in dos
bdos0 equ 25 ;number of bdos sectors on track 0
bdos1 equ bdoss-bdos0 ;number of sectors on track 1
;
mon80 equ 0f800h ;intel monitor base
rmon80 equ 0ff0fh ;restart location for mon80
base equ 078h ;'base' used by controller
rtype equ base+1 ;result type
rbyte equ base+3 ;result byte
reset equ base+7 ;reset controller
;
dstat equ base ;disk status port
ilow equ base+1 ;low iopb address
ihigh equ base+2 ;high iopb address
bsw equ 0ffh ;boot switch
recal equ 3h ;recalibrate selected drive
readf equ 4h ;disk read function
stack equ 100h ;use end of boot for stack
;
rstart:
lxi sp,stack;in case of call to mon80
; clear disk status
in rtype
in rbyte
; check if boot switch is off
coldstart:
in bsw
ani 02h ;switch on?
jnz coldstart
; clear the controller
out reset ;logic cleared
;
;
mvi b,ntrks ;number of tracks to read
lxi h,iopb0
;
start:
;
; read first/next track into cpmb
mov a,l
out ilow
mov a,h
out ihigh
wait0: in dstat
ani 4
jz wait0
;
; check disk status
in rtype
ani 11b
cpi 2
;
if testing
cnc rmon80 ;go to monitor if 11 or 10
endif
if not testing
jnc rstart ;retry the load
endif
;
in rbyte ;i/o complete, check status
; if not ready, then go to mon80
ral
cc rmon80 ;not ready bit set
rar ;restore
ani 11110b ;overrun/addr err/seek/crc/xxxx
;
if testing
cnz rmon80 ;go to monitor
endif
if not testing
jnz rstart ;retry the load
endif
;
;
lxi d,iopbl ;length of iopb
dad d ;addressing next iopb
dcr b ;count down tracks
jnz start
;
;
; jmp to boot to print initial message, and set up jmps
jmp boot
;
; parameter blocks
iopb0: db 80h ;iocw, no update
db readf ;read function
db bdos0 ;# sectors to read on track 0
db 0 ;track 0
db 2 ;start with sector 2 on track 0
dw cpmb ;start at base of bdos
iopbl equ $-iopb0
;
iopb1: db 80h
db readf
db bdos1 ;sectors to read on track 1
db 1 ;track 1
db 1 ;sector 1
dw cpmb+bdos0*128 ;base of second read
;
end

View File

@@ -0,0 +1,832 @@
title 'console command processor (CCP), ver 2.0'
; assembly language version of the CP/M console command processor
;
; version 2.2 February, 1980
;
; Copyright (c) 1976, 1977, 1978, 1979, 1980
; Digital Research
; Box 579, Pacific Grove,
; California, 93950
;
false equ 0000h
true equ not false
testing equ false ;true if debugging
;
;
if testing
org 3400h
bdosl equ $+800h ;bdos location
else
org 000h
bdosl equ $+800h ;bdos location
endif
tran equ 100h
tranm equ $
ccploc equ $
;
; ********************************************************
; * Base of CCP contains the following code/data *
; * ccp: jmp ccpstart (start with command) *
; * jmp ccpclear (start, clear command) *
; * ccp+6 127 (max command length) *
; * ccp+7 comlen (command length = 00) *
; * ccp+8 ' ... ' (16 blanks) *
; ********************************************************
; * Normal entry is at ccp, where the command line given *
; * at ccp+8 is executed automatically (normally a null *
; * command with comlen = 00). An initializing program *
; * can be automatically loaded by storing the command *
; * at ccp+8, with the command length at ccp+7. In this *
; * case, the ccp executes the command before prompting *
; * the console for input. Note that the command is exe-*
; * cuted on both warm and cold starts. When the command*
; * line is initialized, a jump to "jmp ccpclear" dis- *
; * ables the automatic command execution. *
; ********************************************************
;
jmp ccpstart ;start ccp with possible initial command
jmp ccpclear ;clear the command buffer
maxlen: db 127 ;max buffer length
comlen: db 0 ;command length (filled in by dos)
; (command executed initially if comlen non zero)
combuf:
db ' ' ;8 character fill
db ' ' ;8 character fill
db 'COPYRIGHT (C) 1979, DIGITAL RESEARCH '; 38
ds 128-($-combuf)
; total buffer length is 128 characters
comaddr:dw combuf ;address of next to char to scan
staddr: ds 2 ;starting address of current fillfcb request
;
diska equ 0004h ;disk address for current disk
bdos equ 0005h ;primary bdos entry point
buff equ 0080h ;default buffer
fcb equ 005ch ;default file control block
;
rcharf equ 1 ;read character function
pcharf equ 2 ;print character function
pbuff equ 9 ;print buffer function
rbuff equ 10 ;read buffer function
breakf equ 11 ;break key function
liftf equ 12 ;lift head function (no operation)
initf equ 13 ;initialize bdos function
self equ 14 ;select disk function
openf equ 15 ;open file function
closef equ 16 ;close file function
searf equ 17 ;search for file function
searnf equ 18 ;search for next file function
delf equ 19 ;delete file function
dreadf equ 20 ;disk read function
dwritf equ 21 ;disk write function
makef equ 22 ;file make function
renf equ 23 ;rename file function
logf equ 24 ;return login vector
cself equ 25 ;return currently selected drive number
dmaf equ 26 ;set dma address
userf equ 32 ;set user number
;
; special fcb flags
rofile equ 9 ;read only file
sysfile equ 10 ;system file flag
;
; special characters
cr equ 13 ;carriage return
lf equ 10 ;line feed
la equ 5fh ;left arrow
eofile equ 1ah ;end of file
;
; utility procedures
printchar:
mov e,a! mvi c,pcharf! jmp bdos
;
printbc:
;print character, but save b,c registers
push b! call printchar! pop b! ret
;
crlf:
mvi a,cr! call printbc
mvi a,lf! jmp printbc
;
blank:
mvi a,' '! jmp printbc
;
print: ;print string starting at b,c until next 00 entry
push b! call crlf! pop h ;now print the string
prin0: mov a,m! ora a! rz ;stop on 00
inx h! push h ;ready for next
call printchar! pop h ;character printed
jmp prin0 ;for another character
;
initialize:
mvi c,initf! jmp bdos
;
select:
mov e,a! mvi c,self! jmp bdos
;
bdos$inr:
call bdos! sta dcnt! inr a! ret
;
open: ;open the file given by d,e
mvi c,openf! jmp bdos$inr
;
openc: ;open comfcb
xra a! sta comrec ;clear next record to read
lxi d,comfcb! jmp open
;
close: ;close the file given by d,e
mvi c,closef! jmp bdos$inr
;
search: ;search for the file given by d,e
mvi c,searf! jmp bdos$inr
;
searchn:
;search for the next occurrence of the file given by d,e
mvi c,searnf! jmp bdos$inr
;
searchcom:
;search for comfcb file
lxi d,comfcb! jmp search
;
delete: ;delete the file given by d,e
mvi c,delf! jmp bdos
;
bdos$cond:
call bdos! ora a! ret
;
diskread:
;read the next record from the file given by d,e
mvi c,dreadf! jmp bdos$cond
;
diskreadc:
;read the comfcb file
lxi d,comfcb! jmp diskread
;
diskwrite:
;write the next record to the file given by d,e
mvi c,dwritf! jmp bdos$cond
;
make: ;create the file given by d,e
mvi c,makef! jmp bdos$inr
;
renam: ;rename the file given by d,e
mvi c,renf! jmp bdos
;
getuser:
;return current user code in a
mvi e,0ffh ;drop through to setuser
;
setuser:
mvi c,userf! jmp bdos ;sets user number
;
saveuser:
;save user#/disk# before possible ^c or transient
call getuser ;code to a
add a! add a! add a! add a ;rot left
lxi h,cdisk! ora m ;4b=user, 4b=disk
sta diska ;stored away in memory for later
ret
;
setdiska:
lda cdisk! sta diska ;user/disk
ret
;
translate:
;translate character in register A to upper case
cpi 61h! rc ;return if below lower case a
cpi 7bh! rnc ;return if above lower case z
ani 5fh! ret ;translated to upper case
;
readcom:
;read the next command into the command buffer
;check for submit file
lda submit! ora a! jz nosub
;scanning a submit file
;change drives to open and read the file
lda cdisk! ora a! mvi a,0! cnz select
;have to open again in case xsub present
lxi d,subfcb! call open! jz nosub ;skip if no sub
lda subrc! dcr a ;read last record(s) first
sta subcr ;current record to read
lxi d,subfcb! call diskread ;end of file if last record
jnz nosub
;disk read is ok, transfer to combuf
lxi d,comlen! lxi h,buff! mvi b,128! call move0
;line is transferred, close the file with a
;deleted record
lxi h,submod! mvi m,0 ;clear fwflag
inx h! dcr m ;one less record
lxi d,subfcb! call close! jz nosub
;close went ok, return to original drive
lda cdisk! ora a! cnz select
;print to the 00
lxi h,combuf! call prin0
call break$key! jz noread
call del$sub! jmp ccp ;break key depressed
;
nosub: ;no submit file! call del$sub
;translate to upper case, store zero at end
call saveuser ;user # save in case control c
mvi c,rbuff! lxi d,maxlen! call bdos
call setdiska ;no control c, so restore diska
noread: ;enter here from submit file
;set the last character to zero for later scans
lxi h,comlen! mov b,m ;length is in b
readcom0: inx h! mov a,b! ora a ;end of scan?
jz readcom1! mov a,m ;get character and translate
call translate! mov m,a! dcr b! jmp readcom0
;
readcom1: ;end of scan, h,l address end of command
mov m,a ;store a zero
lxi h,combuf! shld comaddr ;ready to scan to zero
ret
;
break$key:
;check for a character ready at the console
mvi c,breakf! call bdos
ora a! rz
mvi c,rcharf! call bdos ;character cleared
ora a! ret
;
cselect:
;get the currently selected drive number to reg-A
mvi c,cself! jmp bdos
;
setdmabuff:
;set default buffer dma address
lxi d,buff ;(drop through)
;
setdma:
;set dma address to d,e
mvi c,dmaf! jmp bdos
;
del$sub:
;delete the submit file, and set submit flag to false
lxi h,submit! mov a,m! ora a! rz ;return if no sub file
mvi m,0 ;submit flag is set to false
xra a! call select ;on drive a to erase file
lxi d,subfcb! call delete
lda cdisk! jmp select ;back to original drive
;
serialize:
;check serialization
lxi d,serial! lxi h,bdosl! mvi b,6 ;check six bytes
ser0: ldax d! cmp m! jnz badserial
inx d! inx h! dcr b! jnz ser0
ret ;serial number is ok
;
comerr:
;error in command string starting at position
;'staddr' and ending with first delimiter
call crlf ;space to next line
lhld staddr ;h,l address first to print
comerr0: ;print characters until blank or zero
mov a,m! cpi ' '! jz comerr1; not blank
ora a! jz comerr1; not zero, so print it
push h! call printchar! pop h! inx h
jmp comerr0; for another character
comerr1: ;print question mark,and delete sub file
mvi a,'?'! call printchar
call crlf! call del$sub
jmp ccp ;restart with next command
;
; fcb scan and fill subroutine (entry is at fillfcb below)
;fill the comfcb, indexed by A (0 or 16)
;subroutines
delim: ;look for a delimiter
ldax d! ora a! rz ;not the last element
cpi ' '! jc comerr ;non graphic
rz ;treat blank as delimiter
cpi '='! rz
cpi la! rz ;left arrow
cpi '.'! rz
cpi ':'! rz
cpi ';'! rz
cpi '<'! rz
cpi '>'! rz
ret ;delimiter not found
;
deblank: ;deblank the input line
ldax d! ora a! rz ;treat end of line as blank
cpi ' '! rnz! inx d! jmp deblank
;
addh: ;add a to h,l
add l! mov l,a! rnc
inr h! ret
;
fillfcb0:
;equivalent to fillfcb(0)
mvi a,0
;
fillfcb:
lxi h,comfcb! call addh! push h! push h ;fcb rescanned at end
xra a! sta sdisk ;clear selected disk (in case A:...)
lhld comaddr! xchg ;command address in d,e
call deblank ;to first non-blank character
xchg! shld staddr ;in case of errors
xchg! pop h ;d,e has command, h,l has fcb address
;look for preceding file name A: B: ...
ldax d! ora a! jz setcur0 ;use current disk if empty command
sbi 'A'-1! mov b,a ;disk name held in b if : follows
inx d! ldax d! cpi ':'! jz setdsk ;set disk name if :
;
setcur: ;set current disk
dcx d ;back to first character of command
setcur0:
lda cdisk! mov m,a! jmp setname
;
setdsk: ;set disk to name in register b
mov a,b! sta sdisk ;mark as disk selected
mov m,b! inx d ;past the :
;
setname: ;set the file name field
mvi b,8 ;file name length (max)
setnam0: call delim! jz padname ;not a delimiter
inx h! cpi '*'! jnz setnam1 ;must be ?'s
mvi m,'?'! jmp setnam2 ;to dec count
;
setnam1: mov m,a ;store character to fcb! inx d
setnam2: dcr b ;count down length! jnz setnam0
;
;end of name, truncate remainder
trname: call delim! jz setty ;set type field if delimiter
inx d! jmp trname
;
padname: inx h! mvi m,' '! dcr b! jnz padname
;
setty: ;set the type field
mvi b,3! cpi '.'! jnz padty ;skip the type field if no .
inx d ;past the ., to the file type field
setty0: ;set the field from the command buffer
call delim! jz padty! inx h! cpi '*'! jnz setty1
mvi m,'?' ;since * specified! jmp setty2
;
setty1: ;not a *, so copy to type field
mov m,a! inx d
setty2: ;decrement count and go again
dcr b! jnz setty0
;
;end of type field, truncate
trtyp: ;truncate type field
call delim! jz efill! inx d! jmp trtyp
;
padty: ;pad the type field with blanks
inx h! mvi m,' '! dcr b! jnz padty
;
efill: ;end of the filename/filetype fill, save command address
;fill the remaining fields for the fcb
mvi b,3
efill0: inx h! mvi m,0! dcr b! jnz efill0
xchg! shld comaddr ;set new starting point
;
;recover the start address of the fcb and count ?'s
pop h! lxi b,11 ;b=0, c=8+3
scnq: inx h! mov a,m! cpi '?'! jnz scnq0
;? found, count it in b! inr b
scnq0: dcr c! jnz scnq
;
;number of ?'s in c, move to a and return with flags set
mov a,b! ora a! ret
;
intvec:
;intrinsic function names (all are four characters)
db 'DIR '
db 'ERA '
db 'TYPE'
db 'SAVE'
db 'REN '
db 'USER'
intlen equ ($-intvec)/4 ;intrinsic function length
serial: db 0,0,0,0,0,0
;
;
intrinsic:
;look for intrinsic functions (comfcb has been filled)
lxi h,intvec! mvi c,0 ;c counts intrinsics as scanned
intrin0: mov a,c! cpi intlen ;done with scan?! rnc
;no, more to scan
lxi d,comfcb+1 ;beginning of name
mvi b,4 ;length of match is in b
intrin1: ldax d! cmp m ;match?
jnz intrin2 ;skip if no match
inx d! inx h! dcr b
jnz intrin1 ;loop while matching
;
;complete match on name, check for blank in fcb
ldax d! cpi ' '! jnz intrin3 ;otherwise matched
mov a,c! ret ;with intrinsic number in a
;
intrin2: ;mismatch, move to end of intrinsic
inx h! dcr b! jnz intrin2
;
intrin3: ;try next intrinsic
inr c ;to next intrinsic number
jmp intrin0 ;for another round
;
ccpclear:
;clear the command buffer
xra a
sta comlen
;drop through to start ccp
ccpstart:
;enter here from boot loader
lxi sp,stack! push b ;save initial disk number
;(high order 4bits=user code, low 4bits=disk#)
mov a,c! rar! rar! rar! rar! ani 0fh ;user code
mov e,a! call setuser ;user code selected
;initialize for this user, get $ flag
call initialize ;0ffh in accum if $ file present
sta submit ;submit flag set if $ file present
pop b ;recall user code and disk number
mov a,c! ani 0fh ;disk number in accumulator
sta cdisk ;clears user code nibble
call select ;proper disk is selected, now check sub files
;check for initial command
lda comlen! ora a! jnz ccp0 ;assume typed already
;
ccp:
;enter here on each command or error condition
lxi sp,stack
call crlf ;print d> prompt, where d is disk name
call cselect ;get current disk number
adi 'A'! call printchar
mvi a,'>'! call printchar
call readcom ;command buffer filled
ccp0: ;(enter here from initialization with command full)
lxi d,buff! call setdma ;default dma address at buff
call cselect! sta cdisk ;current disk number saved
call fillfcb0 ;command fcb filled
cnz comerr ;the name cannot be an ambiguous reference
lda sdisk! ora a! jnz userfunc
;check for an intrinsic function
call intrinsic
lxi h,jmptab ;index is in the accumulator
mov e,a! mvi d,0! dad d! dad d ;index in d,e
mov a,m! inx h! mov h,m! mov l,a! pchl
;pc changes to the proper intrinsic or user function
jmptab:
dw direct ;directory search
dw erase ;file erase
dw type ;type file
dw save ;save memory image
dw rename ;file rename
dw user ;user number
dw userfunc;user-defined function
badserial:
LXI H,76F3H ;'DI HLT' instructions.
;typo "lxi h,di or (hlt shl 8)" here originally,
;corrected by comparing to disassembly of Clark Calkins.
shld ccploc! lxi h,ccploc! pchl
;
;
;utility subroutines for intrinsic handlers
readerr:
;print the read error message
lxi b,rdmsg! jmp print
rdmsg: db 'READ ERROR',0
;
nofile:
;print no file message
lxi b,nofmsg! jmp print
nofmsg: db 'NO FILE',0
;
getnumber: ;read a number from the command line
call fillfcb0 ;should be number
lda sdisk! ora a! jnz comerr ;cannot be prefixed
;convert the byte value in comfcb to binary
lxi h,comfcb+1! lxi b,11 ;(b=0, c=11)
;value accumulated in b, c counts name length to zero
conv0: mov a,m! cpi ' '! jz conv1
;more to scan, convert char to binary and add
inx h! sui '0'! cpi 10! jnc comerr ;valid?
mov d,a ;save value! mov a,b ;mult by 10
ani 1110$0000b! jnz comerr
mov a,b ;recover value
rlc! rlc! rlc ;*8
add b! jc comerr
add b! jc comerr ;*8+*2 = *10
add d! jc comerr ;+digit
mov b,a! dcr c! jnz conv0 ;for another digit
ret
conv1: ;end of digits, check for all blanks
mov a,m! cpi ' '! jnz comerr ;blanks?
inx h! dcr c! jnz conv1
mov a,b ;recover value! ret
;
movename:
;move 3 characters from h,l to d,e addresses
mvi b,3
move0: mov a,m! stax d! inx h! inx d
dcr b! jnz move0
ret
;
addhcf: ;buff + a + c to h,l followed by fetch
lxi h,buff! add c! call addh! mov a,m! ret
;
setdisk:
;change disks for this command, if requested
xra a! sta comfcb ;clear disk name from fcb
lda sdisk! ora a! rz ;no action if not specified
dcr a! lxi h,cdisk! cmp m! rz ;already selected
jmp select
;
resetdisk:
;return to original disk after command
lda sdisk! ora a! rz ;no action if not selected
dcr a! lxi h,cdisk! cmp m! rz ;same disk
lda cdisk! jmp select
;
;individual intrinsics follow
direct:
;directory search
call fillfcb0 ;comfcb gets file name
call setdisk ;change disk drives if requested
lxi h,comfcb+1! mov a,m ;may be empty request
cpi ' '! jnz dir1 ;skip fill of ??? if not blank
;set comfcb to all ??? for current disk
mvi b,11 ;length of fill ????????.???
dir0: mvi m,'?'! inx h! dcr b! jnz dir0
;not a blank request, must be in comfcb
dir1: mvi e,0! push d ;E counts directory entries
call searchcom ;first one has been found
cz nofile ;not found message
dir2: jz endir
;found, but may be system file
lda dcnt ;get the location of the element
rrc! rrc! rrc! ani 110$0000b! mov c,a
;c contains base index into buff for dir entry
mvi a,sysfile! call addhcf ;value to A
ral! jc dir6 ;skip if system file
;c holds index into buffer
;another fcb found, new line?
pop d! mov a,e! inr e! push d
;e=0,1,2,3,...new line if mod 4 = 0
ani 11b! push psw ;and save the test
jnz dirhdr0 ;header on current line
call crlf
push b! call cselect! pop b
;current disk in A
adi 'A'! call printbc
mvi a,':'! call printbc
jmp dirhdr1 ;skip current line hdr
dirhdr0:call blank ;after last one
mvi a,':'! call printbc
dirhdr1:
call blank
;compute position of name in buffer
mvi b,1 ;start with first character of name
dir3: mov a,b! call addhcf ;buff+a+c fetched
ani 7fh ;mask flags
;may delete trailing blanks
cpi ' '! jnz dir4 ;check for blank type
pop psw! push psw ;may be 3rd item
cpi 3! jnz dirb ;place blank at end if not
mvi a,9! call addhcf ;first char of type
ani 7fh! cpi ' '! jz dir5
;not a blank in the file type field
dirb: mvi a,' ' ;restore trailing filename chr
dir4:
call printbc ;char printed
inr b! mov a,b! cpi 12! jnc dir5
;check for break between names
cpi 9! jnz dir3 ;for another char
;print a blank between names
call blank! jmp dir3
;
dir5: ;end of current entry
pop psw ;discard the directory counter (mod 4)
dir6: call break$key ;check for interrupt at keyboard
jnz endir ;abort directory search
call searchn! jmp dir2 ;for another entry
endir: ;end of directory scan
pop d ;discard directory counter
jmp retcom
;
;
erase:
call fillfcb0 ;cannot be all ???'s
cpi 11
jnz erasefile
;erasing all of the disk
lxi b,ermsg! call print!
call readcom
lxi h,comlen! dcr m! jnz ccp ;bad input
inx h! mov a,m! cpi 'Y'! jnz ccp
;ok, erase the entire diskette
inx h! shld comaddr ;otherwise error at retcom
erasefile:
call setdisk
lxi d,comfcb! call delete
inr a ;255 returned if not found
cz nofile ;no file message if so
jmp retcom
;
ermsg: db 'ALL (Y/N)?',0
;
type:
call fillfcb0! jnz comerr ;don't allow ?'s in file name
call setdisk! call openc ;open the file
jz typerr ;zero flag indicates not found
;file opened, read 'til eof
call crlf! lxi h,bptr! mvi m,255 ;read first buffer
type0: ;loop on bptr
lxi h,bptr! mov a,m! cpi 128 ;end buffer
jc type1! push h ;carry if 0,1,...,127
;read another buffer full
call diskreadc! pop h ;recover address of bptr
jnz typeof ;hard end of file
xra a! mov m,a ;bptr = 0
type1: ;read character at bptr and print
inr m ;bptr = bptr + 1
lxi h,buff! call addh ;h,l addresses char
mov a,m! cpi eofile! jz retcom
call printchar
call break$key! jnz retcom ;abort if break
jmp type0 ;for another character
;
typeof: ;end of file, check for errors
dcr a! jz retcom
call readerr
typerr: call resetdisk! jmp comerr
;
save:
call getnumber; value to register a
push psw ;save it for later
;
;should be followed by a file to save the memory image
call fillfcb0
jnz comerr ;cannot be ambiguous
call setdisk ;may be a disk change
lxi d,comfcb! push d! call delete ;existing file removed
pop d! call make ;create a new file on disk
jz saverr ;no directory space
xra a! sta comrec; clear next record field
pop psw ;#pages to write is in a, change to #sectors
mov l,a! mvi h,0! dad h!
lxi d,tran ;h,l is sector count, d,e is load address
save0: ;check for sector count zero
mov a,h! ora l! jz save1 ;may be completed
dcx h ;sector count = sector count - 1
push h ;save it for next time around
lxi h,128! dad d! push h ;next dma address saved
call setdma ;current dma address set
lxi d,comfcb! call diskwrite
pop d! pop h ;dma address, sector count
jnz saverr ;may be disk full case
jmp save0 ;for another sector
;
save1: ;end of dump, close the file
lxi d,comfcb! call close
inr a; 255 becomes 00 if error
jnz retsave ;for another command
saverr: ;must be full or read only disk
lxi b,fullmsg! call print
retsave:
;reset dma buffer
call setdmabuff
jmp retcom
fullmsg: db 'NO SPACE',0
;
;
rename:
;rename a file on a specific disk
call fillfcb0! jnz comerr ;must be unambiguous
lda sdisk! push psw ;save for later compare
call setdisk ;disk selected
call searchcom ;is new name already there?
jnz renerr3
;file doesn't exist, move to second half of fcb
lxi h,comfcb! lxi d,comfcb+16! mvi b,16! call move0
;check for = or left arrow
lhld comaddr! xchg! call deblank
cpi '='! jz ren1 ;ok if =
cpi la! jnz renerr2
ren1: xchg! inx h! shld comaddr ;past delimiter
;proper delimiter found
call fillfcb0! jnz renerr2
;check for drive conflict
pop psw! mov b,a ;previous drive number
lxi h,sdisk! mov a,m! ora a! jz ren2
;drive name was specified. same one?
cmp b! mov m,b! jnz renerr2
ren2: mov m,b ;store the name in case drives switched
xra a! sta comfcb! call searchcom ;is old file there?
jz renerr1
;
;everything is ok, rename the file
lxi d,comfcb! call renam
jmp retcom
;
renerr1:; no file on disk
call nofile! jmp retcom
renerr2:; ambigous reference/name conflict
call resetdisk! jmp comerr
renerr3:; file already exists
lxi b,renmsg! call print! jmp retcom
renmsg: db 'FILE EXISTS',0
;
user:
;set user number
call getnumber; leaves the value in the accumulator
cpi 16! jnc comerr; must be between 0 and 15
mov e,a ;save for setuser call
lda comfcb+1! cpi ' '! jz comerr
call setuser ;new user number set
jmp endcom
;
userfunc:
call serialize ;check serialization
;load user function and set up for execution
lda comfcb+1! cpi ' '! jnz user0
;no file name, but may be disk switch
lda sdisk! ora a! jz endcom ;no disk name if 0
dcr a! sta cdisk! call setdiska ;set user/disk
call select! jmp endcom
user0: ;file name is present
lxi d,comfcb+9! ldax d! cpi ' '! jnz comerr ;type ' '
push d! call setdisk! pop d! lxi h,comtype ;.com
call movename ;file type is set to .com
call openc! jz userer
;file opened properly, read it into memory
lxi h,tran ;transient program base
load0: push h ;save dma address
xchg! call setdma
lxi d,comfcb! call diskread! jnz load1
;sector loaded, set new dma address and compare
pop h! lxi d,128! dad d
lxi d,tranm ;has the load overflowed?
mov a,l! sub e! mov a,h! sbb d! jnc loaderr
jmp load0 ;for another sector
;
load1: pop h! dcr a! jnz loaderr ;end file is 1
call resetdisk ;back to original disk
call fillfcb0! lxi h,sdisk! push h
mov a,m! sta comfcb ;drive number set
mvi a,16! call fillfcb ;move entire fcb to memory
pop h! mov a,m! sta comfcb+16
xra a! sta comrec ;record number set to zero
lxi d,fcb! lxi h,comfcb! mvi b,33! call move0
;move command line to buff
lxi h,combuf
bmove0: mov a,m! ora a! jz bmove1! cpi ' '! jz bmove1
inx h! jmp bmove0 ;for another scan
;first blank position found
bmove1: mvi b,0! lxi d,buff+1! ;ready for the move
bmove2: mov a,m! stax d! ora a! jz bmove3
;more to move
inr b! inx h! inx d! jmp bmove2
bmove3: ;b has character count
mov a,b! sta buff
call crlf
;now go to the loaded program
call setdmabuff ;default dma
call saveuser ;user code saved
;low memory diska contains user code
call tran ;gone to the loaded program
lxi sp,stack ;may come back here
call setdiska! call select
jmp ccp
;
userer: ;arrive here on command error
call resetdisk! jmp comerr
;
loaderr:;cannot load the program
lxi b,loadmsg! call print
jmp retcom
loadmsg: db 'BAD LOAD',0
comtype: db 'COM' ;for com files
;
;
retcom: ;reset disk before end of command check
call resetdisk
;
endcom: ;end of intrinsic command
call fillfcb0 ;to check for garbage at end of line
lda comfcb+1! sui ' '! lxi h,sdisk! ora m
;0 in accumulator if no disk selected, and blank fcb
jnz comerr
jmp ccp
;
;
;
; data areas
ds 16 ;8 level stack
stack:
;
; 'submit' file control block
submit: db 0 ;00 if no submit file, ff if submitting
subfcb: db 0,'$$$ ' ;file name is $$$
db 'SUB',0,0 ;file type is sub
submod: db 0 ;module number
subrc: ds 1 ;record count filed
ds 16 ;disk map
subcr: ds 1 ;current record to read
;
; command file control block
comfcb: ds 32 ;fields filled in later
comrec: ds 1 ;current record to read/write
dcnt: ds 1 ;disk directory count (used for error codes)
cdisk: ds 1 ;current disk
sdisk: ds 1 ;selected disk for current operation
;none=0, a=1, b=2 ...
bptr: ds 1 ;buffer pointer
end ccploc

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,504 @@
; MDS-800 I/O Drivers for CP/M 2.2
; (four drive single density version)
;
; Version 2.2 February, 1980
;
vers equ 22 ;version 2.2
;
; Copyright (c) 1980
; Digital Research
; Box 579, Pacific Grove
; California, 93950
;
;
true equ 0ffffh ;value of "true"
false equ not true ;"false"
test equ false ;true if test bios
;
if test
bias equ 03400h ;base of CCP in test system
endif
if not test
bias equ 0000h ;generate relocatable cp/m system
endif
;
patch equ 1600h
;
org patch
cpmb equ $-patch ;base of cpm console processor
bdos equ 806h+cpmb ;basic dos (resident portion)
cpml equ $-cpmb ;length (in bytes) of cpm system
nsects equ cpml/128 ;number of sectors to load
offset equ 2 ;number of disk tracks used by cp/m
cdisk equ 0004h ;address of last logged disk on warm start
buff equ 0080h ;default buffer address
retry equ 10 ;max retries on disk i/o before error
;
; perform following functions
; boot cold start
; wboot warm start (save i/o byte)
; (boot and wboot are the same for mds)
; const console status
; reg-a = 00 if no character ready
; reg-a = ff if character ready
; conin console character in (result in reg-a)
; conout console character out (char in reg-c)
; list list out (char in reg-c)
; punch punch out (char in reg-c)
; reader paper tape reader in (result to reg-a)
; home move to track 00
;
; (the following calls set-up the io parameter block for the
; mds, which is used to perform subsequent reads and writes)
; seldsk select disk given by reg-c (0,1,2...)
; settrk set track address (0,...76) for subsequent read/write
; setsec set sector address (1,...,26) for subsequent read/write
; setdma set subsequent dma address (initially 80h)
;
; (read and write assume previous calls to set up the io parameters)
; read read track/sector to preset dma address
; write write track/sector from preset dma address
;
; jump vector for indiviual routines
jmp boot
wboote: jmp wboot
jmp const
jmp conin
jmp conout
jmp list
jmp punch
jmp reader
jmp home
jmp seldsk
jmp settrk
jmp setsec
jmp setdma
jmp read
jmp write
jmp listst ;list status
jmp sectran
;
maclib diskdef ;load the disk definition library
disks 4 ;four disks
diskdef 0,1,26,6,1024,243,64,64,offset
diskdef 1,0
diskdef 2,0
diskdef 3,0
; endef occurs at end of assembly
;
; end of controller - independent code, the remaining subroutines
; are tailored to the particular operating environment, and must
; be altered for any system which differs from the intel mds.
;
; the following code assumes the mds monitor exists at 0f800h
; and uses the i/o subroutines within the monitor
;
; we also assume the mds system has four disk drives
revrt equ 0fdh ;interrupt revert port
intc equ 0fch ;interrupt mask port
icon equ 0f3h ;interrupt control port
inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor)
;
; mds monitor equates
mon80 equ 0f800h ;mds monitor
rmon80 equ 0ff0fh ;restart mon80 (boot error)
ci equ 0f803h ;console character to reg-a
ri equ 0f806h ;reader in to reg-a
co equ 0f809h ;console char from c to console out
po equ 0f80ch ;punch char from c to punch device
lo equ 0f80fh ;list from c to list device
csts equ 0f812h ;console status 00/ff to register a
;
; disk ports and commands
base equ 78h ;base of disk command io ports
dstat equ base ;disk status (input)
rtype equ base+1 ;result type (input)
rbyte equ base+3 ;result byte (input)
;
ilow equ base+1 ;iopb low address (output)
ihigh equ base+2 ;iopb high address (output)
;
readf equ 4h ;read function
writf equ 6h ;write function
recal equ 3h ;recalibrate drive
iordy equ 4h ;i/o finished mask
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;
signon: ;signon message: xxk cp/m vers y.y
db cr,lf,lf
if test
db '32' ;32k example bios
endif
if not test
db '00' ;memory size filled by relocator
endif
db 'k CP/M vers '
db vers/10+'0','.',vers mod 10+'0'
db cr,lf,0
;
boot: ;print signon message and go to ccp
; (note: mds boot initialized iobyte at 0003h)
lxi sp,buff+80h
lxi h,signon
call prmsg ;print message
xra a ;clear accumulator
sta cdisk ;set initially to disk a
jmp gocpm ;go to cp/m
;
;
wboot:; loader on track 0, sector 1, which will be skipped for warm
; read cp/m from disk - assuming there is a 128 byte cold start
; start.
;
lxi sp,buff ;using dma - thus 80 thru ff available for stack
;
mvi c,retry ;max retries
push b
wboot0: ;enter here on error retries
lxi b,cpmb ;set dma address to start of disk system
call setdma
mvi c,0 ;boot from drive 0
call seldsk
mvi c,0
call settrk ;start with track 0
mvi c,2 ;start reading sector 2
call setsec
;
; read sectors, count nsects to zero
pop b ;10-error count
mvi b,nsects
rdsec: ;read next sector
push b ;save sector count
call read
jnz booterr ;retry if errors occur
lhld iod ;increment dma address
lxi d,128 ;sector size
dad d ;incremented dma address in hl
mov b,h
mov c,l ;ready for call to set dma
call setdma
lda ios ;sector number just read
cpi 26 ;read last sector?
jc rd1
; must be sector 26, zero and go to next track
lda iot ;get track to register a
inr a
mov c,a ;ready for call
call settrk
xra a ;clear sector number
rd1: inr a ;to next sector
mov c,a ;ready for call
call setsec
pop b ;recall sector count
dcr b ;done?
jnz rdsec
;
; done with the load, reset default buffer address
gocpm: ;(enter here from cold start boot)
; enable rst0 and rst7
di
mvi a,12h ;initialize command
out revrt
xra a
out intc ;cleared
mvi a,inte ;rst0 and rst7 bits on
out intc
xra a
out icon ;interrupt control
;
; set default buffer address to 80h
lxi b,buff
call setdma
;
; reset monitor entry points
mvi a,jmp
sta 0
lxi h,wboote
shld 1 ;jmp wboot at location 00
sta 5
lxi h,bdos
shld 6 ;jmp bdos at location 5
if not test
sta 7*8 ;jmp to mon80 (may have been changed by ddt)
lxi h,mon80
shld 7*8+1
endif
; leave iobyte set
; previously selected disk was b, send parameter to cpm
lda cdisk ;last logged disk number
mov c,a ;send to ccp to log it in
ei
jmp cpmb
;
; error condition occurred, print message and retry
booterr:
pop b ;recall counts
dcr c
jz booter0
; try again
push b
jmp wboot0
;
booter0:
; otherwise too many retries
lxi h,bootmsg
call prmsg
jmp rmon80 ;mds hardware monitor
;
bootmsg:
db '?boot',0
;
;
const: ;console status to reg-a
; (exactly the same as mds call)
jmp csts
;
conin: ;console character to reg-a
call ci
ani 7fh ;remove parity bit
ret
;
conout: ;console character from c to console out
jmp co
;
list: ;list device out
; (exactly the same as mds call)
jmp lo
;
listst:
;return list status
xra a
ret ;always not ready
;
punch: ;punch device out
; (exactly the same as mds call)
jmp po
;
reader: ;reader character in to reg-a
; (exactly the same as mds call)
jmp ri
;
home: ;move to home position
; treat as track 00 seek
mvi c,0
jmp settrk
;
seldsk: ;select disk given by register c
lxi h,0000h ;return 0000 if error
mov a,c
cpi ndisks ;too large?
rnc ;leave HL = 0000
;
ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3
sta dbank ;to select drive bank
mov a,c ;00, 01, 10, 11
ani 1b ;mds has 0,1 at 78, 2,3 at 88
ora a ;result 00?
jz setdrive
mvi a,00110000b ;selects drive 1 in bank
setdrive:
mov b,a ;save the function
lxi h,iof ;io function
mov a,m
ani 11001111b ;mask out disk number
ora b ;mask in new disk number
mov m,a ;save it in iopb
mov l,c
mvi h,0 ;HL=disk number
dad h ;*2
dad h ;*4
dad h ;*8
dad h ;*16
lxi d,dpbase
dad d ;HL=disk header table address
ret
;
;
settrk: ;set track address given by c
lxi h,iot
mov m,c
ret
;
setsec: ;set sector number given by c
lxi h,ios
mov m,c
ret
sectran:
;translate sector bc using table at de
mvi b,0 ;double precision sector number in BC
xchg ;translate table address to HL
dad b ;translate(sector) address
mov a,m ;translated sector number to A
sta ios
mov l,a ;return sector number in L
ret
;
setdma: ;set dma address given by regs b,c
mov l,c
mov h,b
shld iod
ret
;
read: ;read next disk record (assuming disk/trk/sec/dma set)
mvi c,readf ;set to read function
call setfunc
call waitio ;perform read function
ret ;may have error set in reg-a
;
;
write: ;disk write function
mvi c,writf
call setfunc ;set to write function
call waitio
ret ;may have error set
;
;
; utility subroutines
prmsg: ;print message at h,l to 0
mov a,m
ora a ;zero?
rz
; more to print
push h
mov c,a
call conout
pop h
inx h
jmp prmsg
;
setfunc:
; set function for next i/o (command in reg-c)
lxi h,iof ;io function address
mov a,m ;get it to accumulator for masking
ani 11111000b ;remove previous command
ora c ;set to new command
mov m,a ;replaced in iopb
; the mds-800 controller requires disk bank bit in sector byte
; mask the bit from the current i/o function
ani 00100000b ;mask the disk select bit
lxi h,ios ;address the sector select byte
ora m ;select proper disk bank
mov m,a ;set disk select bit on/off
ret
;
waitio:
mvi c,retry ;max retries before perm error
rewait:
; start the i/o function and wait for completion
call intype ;in rtype
call inbyte ;clears the controller
;
lda dbank ;set bank flags
ora a ;zero if drive 0,1 and nz if 2,3
mvi a,iopb and 0ffh ;low address for iopb
mvi b,iopb shr 8 ;high address for iopb
jnz iodr1 ;drive bank 1?
out ilow ;low address to controller
mov a,b
out ihigh ;high address
jmp wait0 ;to wait for complete
;
iodr1: ;drive bank 1
out ilow+10h ;88 for drive bank 10
mov a,b
out ihigh+10h
;
wait0: call instat ;wait for completion
ani iordy ;ready?
jz wait0
;
; check io completion ok
call intype ;must be io complete (00) unlinked
; 00 unlinked i/o complete, 01 linked i/o complete (not used)
; 10 disk status changed 11 (not used)
cpi 10b ;ready status change?
jz wready
;
; must be 00 in the accumulator
ora a
jnz werror ;some other condition, retry
;
; check i/o error bits
call inbyte
ral
jc wready ;unit not ready
rar
ani 11111110b ;any other errors? (deleted data ok)
jnz werror
;
; read or write is ok, accumulator contains zero
ret
;
wready: ;not ready, treat as error for now
call inbyte ;clear result byte
jmp trycount
;
werror: ;return hardware malfunction (crc, track, seek, etc.)
; the mds controller has returned a bit in each position
; of the accumulator, corresponding to the conditions:
; 0 - deleted data (accepted as ok above)
; 1 - crc error
; 2 - seek error
; 3 - address error (hardware malfunction)
; 4 - data over/under flow (hardware malfunction)
; 5 - write protect (treated as not ready)
; 6 - write error (hardware malfunction)
; 7 - not ready
; (accumulator bits are numbered 7 6 5 4 3 2 1 0)
;
; it may be useful to filter out the various conditions,
; but we will get a permanent error message if it is not
; recoverable. in any case, the not ready condition is
; treated as a separate condition for later improvement
trycount:
; register c contains retry count, decrement 'til zero
dcr c
jnz rewait ;for another try
;
; cannot recover from error
mvi a,1 ;error code
ret
;
; intype, inbyte, instat read drive bank 00 or 10
intype: lda dbank
ora a
jnz intyp1 ;skip to bank 10
in rtype
ret
intyp1: in rtype+10h ;78 for 0,1 88 for 2,3
ret
;
inbyte: lda dbank
ora a
jnz inbyt1
in rbyte
ret
inbyt1: in rbyte+10h
ret
;
instat: lda dbank
ora a
jnz insta1
in dstat
ret
insta1: in dstat+10h
ret
;
;
;
; data areas (must be in ram)
dbank: db 0 ;disk bank 00 if drive 0,1
; 10 if drive 2,3
iopb: ;io parameter block
db 80h ;normal i/o operation
iof: db readf ;io function, initial read
ion: db 1 ;number of sectors to read
iot: db offset ;track number
ios: db 1 ;sector number
iod: dw buff ;io address
;
;
; define ram areas for bdos operation
endef
end

View File

@@ -0,0 +1,14 @@
; PIP INTERFACE TO BDOS (CAN BE USED FOR OTHER TRANSIENTS)
PUBLIC BOOT,IOBYTE,BDISK,BDOS,MON1,MON2,MON3
PUBLIC MAXB,FCB,BUFF
BOOT EQU 0000H ;WARM START
IOBYTE EQU 0003H ;IO BYTE
BDISK EQU 0004H ;BOOT DISK #
BDOS EQU 0005H ;BDOS ENTRY
MON1 EQU 0005H ;BDOS ENTRY
MON2 EQU 0005H ;BDOS ENTRY
MON3 EQU 0005H ;BDOS ENTRY
MAXB EQU 0006H ;MAX MEM BASE
FCB EQU 005CH ;DEFAULT FCB
BUFF EQU 0080H ;DEFAULT BUFFER
END

View File

@@ -0,0 +1,218 @@
0000 PIP#
0000 PIPMOD#
07E6 14 07EA 16 07F2 17 07F3 18 07F3 19
07FB 20 07FF 21 07FF 22 07FF 23 0804 24
0809 25 080A 42 080A 43 0813 44 0813 45
0813 46 081C 47 081C 49 0820 51 082D 52
082E 53 082E 54 0833 55 0838 56 0839 57
083F 59 0842 60 084B 61 084C 63 084C 64
0855 65 0855 66 0855 67 085D 68 085E 69
0862 71 086D 72 086E 73 0874 75 0880 76
0881 77 0887 79 0893 80 0894 81 089A 83
08A6 84 08A7 85 08A7 86 08B2 87 08B3 88
08B9 90 08C2 91 08C3 92 08C9 94 08D3 95
08D3 96 08D9 98 08E3 99 08E3 100 08E9 102
08F5 103 08F6 104 08FC 106 0905 107 0906 109
090C 111 0915 112 0916 113 0916 114 091F 115
091F 116 0923 118 092E 119 092F 120 092F 121
0936 122 0937 123 0937 124 093E 125 093F 126
0945 128 094F 129 094F 130 0955 132 095F 133
095F 134 0965 136 096E 137 096F 140 096F 141
0974 142 097C 143 097D 145 097D 146 0986 147
0986 149 098C 151 0995 152 0996 153 0996 155
099A 156 099E 157 09A7 158 09AA 159 09AF 160
09AF 162 09B5 164 09B8 165 09C0 166 09C5 167
09CA 168 09DA 169 09E4 170 09F1 171 09F8 172
09FD 173 0A03 174 0A0B 175 0A11 176 0A14 177
0A17 178 0A18 179 0A27 182 0A33 183 0A3D 184
0A44 185 0A4B 186 0A4E 187 0A4F 188 0A4F 190
0A55 191 0A5C 192 0A5F 193 0A6E 194 0A7B 195
0A89 197 0A91 198 0A97 199 0A9D 200 0AA4 201
0AAA 202 0AAD 203 0AB7 204 0ABE 205 0AC4 206
0AC7 207 0AC8 208 0AC8 212 0ADA 213 0ADB 214
0AE1 215 0AE8 216 0AEE 217 0AFD 218 0B07 219
0B0F 220 0B1A 221 0B20 222 0B2A 223 0B31 224
0B38 226 0B3E 227 0B44 228 0B53 229 0B61 230
0B68 231 0B6D 232 0B7B 233 0B9B 234 0B9F 235
0BA2 236 0BAC 237 0BB3 238 0BB9 239 0BC0 240
0BC9 241 0BC9 242 0BCF 243 0BD0 244 0BD4 246
0BDC 248 0BE0 249 0BE9 251 0BF3 252 0BF4 253
0BF4 254 0BF4 255 0BFA 256 0C0A 257 0C0A 258
0C16 259 0C19 260 0C24 261 0C2B 262 0C2E 263
0C31 264 0C34 265 0C37 266 0C3A 267 0C3D 268
0C46 269 0C50 270 0C50 271 0C55 272 0C58 273
0C5B 274 0C5B 275 0C60 276 0C63 277 0C66 278
0C66 279 0C6B 280 0C6E 281 0C71 282 0C7F 283
0C7F 284 0C84 285 0C87 286 0C8A 287 0C8A 288
0C8F 289 0C92 290 0C95 291 0C95 292 0C9A 293
0C9D 294 0CA0 295 0CAE 296 0CAE 297 0CB3 298
0CB6 299 0CB9 300 0CB9 301 0CBE 302 0CC1 303
0CC4 304 0CC4 305 0CC9 306 0CCC 307 0CCF 308
0CDD 309 0D05 310 0D0B 311 0D0C 312 0D10 314
0D18 315 0D22 316 0D2A 317 0D34 319 0D3A 320
0D44 321 0D4E 322 0D51 323 0D59 324 0D62 325
0D66 326 0D6B 327 0D6E 328 0D6E 329 0D76 330
0D7B 331 0D7C 332 0D80 334 0D91 335 0D99 336
0DA2 337 0DA3 338 0DA7 340 0DB4 341 0DBD 342
0DBE 343 0DBE 345 0DC3 346 0DCE 347 0DD6 348
0DDF 349 0DE8 350 0DEF 351 0DF6 352 0DFD 353
0E05 355 0E0A 356 0E0F 357 0E12 358 0E17 359
0E18 360 0E18 363 0E21 364 0E2A 365 0E2D 366
0E3C 367 0E44 368 0E45 369 0E49 371 0E50 373
0E58 374 0E59 375 0E59 376 0E60 378 0E68 380
0E73 382 0E7B 383 0E80 384 0E8E 386 0E93 387
0E98 388 0E98 389 0E98 390 0EA1 391 0EA4 392
0EA9 393 0EA9 394 0EA9 395 0EB0 397 0EC8 399
0ECB 400 0ECC 401 0ECC 402 0ECC 403 0ED4 404
0ED9 405 0EE0 406 0EE8 407 0EED 408 0EEE 409
0EF2 411 0F09 412 0F11 413 0F15 414 0F15 415
0F19 417 0F30 418 0F38 419 0F3C 420 0F3C 421
0F3C 423 0F47 425 0F59 427 0F61 428 0F64 429
0F6A 430 0F6D 431 0F6D 432 0F6D 433 0F72 434
0F78 435 0F88 436 0F88 437 0F94 438 0F97 439
0FA3 440 0FAA 441 0FAD 442 0FB6 443 0FBF 444
0FBF 445 0FC4 446 0FC7 447 0FCA 448 0FCA 449
0FCF 450 0FD2 451 0FD5 452 0FD5 453 0FDA 454
0FDD 455 0FE0 456 0FF0 457 0FF3 458 0FF6 459
0FF9 460 0FFC 461 0FFF 462 1002 463 1005 464
1008 465 1008 466 100E 467 1011 468 1011 469
1016 470 1019 471 101C 472 101C 473 1021 474
1024 475 1027 476 1027 477 102C 478 102F 479
1032 480 1032 481 1037 482 1042 483 1045 484
106D 485 1073 486 107A 488 1080 489 1085 490
108C 491 1092 492 1092 493 1099 495 10A0 496
10B2 497 10BD 498 10C4 500 10CB 502 10D3 503
10D6 504 10DC 505 10DC 506 10DC 507 10DC 508
10E3 509 10EB 510 10F2 511 10FA 512 1101 513
1109 514 110D 515 110D 516 11AD 518 11B1 520
11C9 522 11D6 523 11D9 524 11D9 525 11E3 526
11EA 527 11EF 528 11F2 529 110D 530 1116 532
1122 533 1125 534 1128 535 1128 536 1128 537
1131 539 1135 540 1141 541 1145 542 1146 543
1146 544 1151 545 1154 546 115D 548 1168 550
116E 551 1173 552 117A 553 117A 554 117D 555
1186 557 1191 559 1196 560 119B 561 119E 562
119E 563 11A2 564 11A5 565 11A9 566 11AC 567
11F2 569 11F2 570 1200 571 1203 572 1211 573
1211 574 1211 575 121C 576 121F 577 1220 578
1438 581 143C 584 144A 585 145A 586 145D 587
1464 588 1467 589 1467 590 1467 591 1479 592
1481 593 1486 594 1487 595 148B 597 1490 598
149A 599 149D 600 14A0 601 14A1 602 14A5 604
14B1 605 14B1 606 14B1 608 14B6 609 14BC 610
14C2 611 14DA 612 14E9 614 14F1 615 14FA 616
1500 617 1503 619 151B 621 1522 622 153D 623
1540 624 1546 625 1549 626 155B 627 1563 628
1575 629 158A 630 158D 631 159A 632 15A2 634
15AB 635 15B1 636 15B7 637 15B7 638 15B7 639
15BA 640 15C0 641 15C1 642 15C1 643 15C9 644
15CE 645 1226 646 122B 647 1230 648 1233 649
1238 650 1240 651 1248 652 124D 653 1250 654
1253 655 1256 656 125C 657 1267 659 126A 660
126F 661 1270 662 1270 663 1275 664 1283 665
128E 666 1295 667 129A 668 12A5 669 12A5 670
12AA 671 12B5 672 12BD 673 12BE 674 12C6 675
12CE 676 12D1 677 12D7 678 12DA 679 12E2 681
12EA 682 12EB 683 12F3 685 1305 686 1306 687
1309 688 1314 690 131C 691 131F 692 1323 693
1328 694 1329 695 1329 696 132C 697 1334 698
1335 701 133A 702 1346 703 134B 704 137B 705
137E 706 1386 708 138B 709 1393 710 1396 711
139A 712 13A0 713 13A1 714 13A1 715 13A9 716
13B0 717 13B1 718 13B1 719 13B9 720 13BC 721
13BF 723 13C7 724 13C8 725 13CD 726 13D5 727
13E3 728 13EB 729 13EC 730 13F4 731 13FC 732
13FF 733 1402 734 140A 735 140D 736 1411 737
1416 738 141E 739 1425 740 1433 741 1434 742
1434 743 1437 744 15CF 745 15CF 747 15DD 748
15E2 749 15E9 750 15EA 752 15F0 754 15FC 755
15FD 756 1607 758 1610 759 1623 760 1626 761
162D 762 1634 763 1637 764 163A 765 163A 766
163A 767 1640 768 1647 769 1652 770 165B 771
165B 772 1712 775 1718 777 171F 779 1724 780
172C 781 172C 782 172D 783 172D 784 1734 786
1739 787 173C 788 173C 789 173D 790 173D 792
1744 794 174F 795 1754 796 1757 797 1764 798
1770 799 1776 800 177A 801 177A 802 177D 803
177D 805 177D 807 178C 808 1792 809 179E 810
17A4 811 17AC 812 17AC 813 17AC 814 17BB 815
17BB 816 17BB 817 17C4 818 17C4 819 17C4 820
17DA 821 165B 822 1660 823 1665 824 1670 825
1675 826 167D 828 1683 829 168B 830 168E 831
1693 832 1693 833 1696 834 1699 835 169E 836
16A9 838 16B4 839 16B7 840 16BA 841 16C1 842
16C4 843 16C7 844 16C7 845 16CD 846 16D3 847
16E3 848 16E7 849 16ED 850 16F0 851 16FC 852
1702 853 1705 854 170C 855 170F 856 1712 857
17DA 858 17DA 860 17DA 861 17E7 862 17F7 863
1806 864 1815 865 181C 866 1821 867 1826 868
182E 869 182F 870 1832 871 1835 872 1840 873
1846 874 184C 875 184F 876 1857 877 1858 878
185B 879 185C 880 185C 881 1862 882 1863 883
1863 884 186A 885 1876 886 1882 887 188A 888
1892 889 1898 890 189E 891 18A4 892 18AC 893
18B2 894 18BD 895 18BE 896 18BE 897 18C4 898
18C7 899 18CE 900 18D4 901 18D7 902 18E7 903
18EC 904 18F4 905 18FA 906 18FF 907 190B 908
1911 909 1912 910 1912 911 191B 912 1921 913
192A 914 1930 915 1931 916 1935 918 193C 919
1945 920 194A 921 1955 922 1959 923 195E 924
1961 925 1964 926 1967 927 196E 928 1974 929
197C 930 1982 931 1988 932 198D 933 1993 934
199B 936 19A3 938 19AA 940 19B0 941 19BC 943
19C2 944 19C5 945 19CB 946 19D1 947 19D2 948
19D2 949 19D5 950 19D5 951 19DD 952 19E3 953
19E3 954 19E9 955 19E9 956 19F5 957 19FB 958
1A01 959 1A02 960 1A02 961 1A15 962 1A16 963
1A16 964 1A1C 965 1A28 966 1A31 967 1A3C 968
1A3F 969 1A40 970 1A40 971 1A56 972 1A68 973
1A6B 974 1A6C 975 1A6C 977 1A7F 978 1A82 979
1A8D 980 1A93 981 1A9A 982 1AA1 983 1AA4 984
1AAB 986 1AAE 987 1AB1 988 1AB1 989 1AB2 990
1B6A 992 1B6A 993 1B78 994 1AB2 995 1AB5 996
1ABB 997 1ABE 998 1AC1 999 1AC6 1000 1AD2 1001
1AE1 1003 1B1D 1004 1B22 1005 1B22 1006 1B29 1007
1B30 1009 1B33 1010 1B3A 1011 1B3D 1012 1B44 1013
1B4D 1014 1B53 1015 1B56 1016 1B59 1017 1B5C 1018
1B5F 1019 1B62 1020 1B69 1021 1B78 1022 1C49 1024
1C49 1026 1C4C 1027 1C5A 1028 1C6C 1030 1C74 1031
1C79 1032 1C80 1033 1C80 1034 1C87 1035 1B78 1036
1B81 1037 1B81 1038 1B84 1039 1B8B 1040 1B91 1041
1B97 1042 1B9D 1043 1BB7 1044 1BBE 1045 1BC1 1046
1BC4 1047 1BC7 1048 1BCF 1050 1BDB 1051 1BE1 1052
1BE4 1053 1BE5 1054 1BE5 1055 1BEC 1056 1C06 1057
1C0B 1058 1C10 1059 1C1C 1060 1C29 1062 1C39 1063
1C3F 1064 1C42 1065 1C45 1066 1C45 1067 1C48 1068
1C88 1069 1C88 1070 1C91 1071 1C9B 1072 1CA1 1073
1CA2 1074 1CA2 1075 1CA9 1076 1CAC 1077 1CB5 1078
1CBF 1079 1CC5 1080 1CC6 1081 1CC6 1082 1CD0 1083
1CD1 1084 1CDB 1085 1CDE 1086 1CDF 1087 1CDF 1088
1CE2 1089 1CEA 1090 1CED 1091 1CEE 1092 1CF4 1094
1CF7 1095 1CFA 1096 1D08 1097 1D0B 1098 1D0C 1099
1D0C 1100 1D12 1101 1D2A 1102 1D2D 1103 1D33 1104
04CE 1105 04DD 1106 04E8 1107 04F4 1109 04FA 1110
04FD 1111 04FD 1112 0503 1113 050E 1114 0514 1115
0514 1116 051A 1117 0525 1118 052A 1119 0532 1120
0535 1121 053C 1123 0541 1124 0544 1125 0547 1126
0547 1127 054C 1128 0554 1130 055B 1131 055E 1132
055E 1133 0570 1134 0576 1135 057E 1136 0581 1137
0589 1139 0590 1140 0593 1141 0599 1142 05A1 1143
05A4 1144 05AB 1146 05B1 1147 05B4 1148 05B7 1150
05BD 1151 05C0 1152 05C0 1153 05C3 1154 05C3 1155
05D3 1156 05D6 1157 05D9 1158 05DC 1159 05E2 1160
05EA 1162 05ED 1163 05F0 1164 05FC 1165 05FF 1166
0602 1167 0605 1168 0605 1169 060D 1171 0610 1172
0618 1173 061B 1174 061E 1175 0621 1176 0624 1177
0624 1178 0629 1179 062F 1180 063D 1181 0643 1182
0648 1183 0650 1185 0653 1186 0656 1187 065B 1188
065E 1189 0675 1190 067B 1191 0687 1192 068A 1193
0690 1194 06A8 1195 06AE 1196 06B3 1197 06BA 1198
06C0 1199 06C6 1200 06CB 1201 06DF 1203 06E2 1204
06E5 1205 06EA 1206 06ED 1207 070D 1208 0713 1209
071B 1210 0722 1211 072A 1212 0730 1213 0738 1214
0740 1216 074E 1217 0753 1218 075B 1220 0760 1221
0768 1222 076D 1223 0775 1224 077A 1225 077A 1226
077D 1227 077D 1228 0780 1229 0786 1230 07AA 1231
07B0 1232 07BB 1233 07BE 1234 07C6 1236 07CB 1237
07CE 1238 07CE 1239 07D6 1240 07DB 1241 07E1 1242
07E4 1243

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
This is the original source for CP/M 2.2. The source for CP/M 2.2 is in assembler, for an Intel MDS-800 development system. The only files that are in PLM are the Utilities such as PIP, STAT, etc.
/README.TXT
Comparison of Caldera's PLM.ZIP file (215.462 bytes, 1997-10-14 21:22,
CRC 65A8) and this very archive reveals the following difference:
- One particular file OS3BDOS.ASM has the same file length in both issues,
but different checksums. Both files differ in a single short sequence
of code, but they do differ, and hence the Caldera issue should be
preserved as well.
It has been added to this archive under the name of "OS3BDOS1.ASM".

/README.PIP
Command: PIP22 A:=B:*.*[R
This function copies all files from drive b: to drive a:
It also copies any hidden/System files from b: to a: (This
is what the [R is for.


View File

@@ -0,0 +1,9 @@
Command: PIP22 A:=B:*.*[R
This function copies all files from drive b: to drive a:
It also copies any hidden/System files from b: to a: (This
is what the [R is for.

View File

@@ -0,0 +1,9 @@
Comparison of Caldera's PLM.ZIP file (215.462 bytes, 1997-10-14 21:22,
CRC 65A8) and this very archive reveals the following difference:
- One particular file OS3BDOS.ASM has the same file length in both issues,
but different checksums. Both files differ in a single short sequence
of code, but they do differ, and hence the Caldera issue should be
preserved as well.
It has been added to this archive under the name of "OS3BDOS1.ASM".


View File

@@ -0,0 +1,116 @@
0000 STAT#
0000 STAT#
0433 16 0490 20 0494 22 049F 23 04A0 24
04A0 25 04A5 26 04AA 27 04AB 28 04AB 29
04B0 30 04B1 31 04B7 34 04C0 35 04C7 36
04CE 37 04D1 38 04D2 39 04D8 41 04DB 42
04E3 43 04E4 44 04E4 45 04ED 46 04ED 48
04ED 49 04F6 50 04F6 51 04FA 53 0505 54
0506 55 050C 57 0518 58 0519 59 051F 61
052B 62 052C 63 052C 64 0537 65 0538 66
0538 67 0541 68 0541 69 0547 71 0550 72
0551 73 0551 74 055A 75 055A 76 055A 77
0563 78 0563 79 0563 80 056B 81 056C 82
056C 83 0575 84 0575 85 0575 86 057D 87
057E 88 057E 89 0589 90 058A 91 058A 92
0593 93 0593 94 0597 96 05A2 97 05A3 98
05A9 100 05B2 101 05B3 105 05B3 106 05B6 107
05CB 108 05CC 109 05D0 111 05D7 112 05DA 113
05DB 114 05E1 116 05FE 117 05FE 119 0604 123
0612 124 062C 125 062F 126 0636 127 0639 128
0639 129 06EB 131 06EF 133 06FC 134 0700 135
0639 136 0648 137 064C 138 064F 139 0654 140
065C 141 0670 142 067A 143 067F 144 06D1 145
06DF 146 06E3 147 06E6 148 06EA 149 0701 150
070B 152 0710 153 071C 154 072A 155 0734 156
0740 157 075B 158 0761 160 0766 161 076F 162
076F 163 0772 164 0773 165 077D 169 078C 170
0799 171 07A8 172 07B3 173 07B6 174 07B7 175
07BB 178 07C4 179 07C8 180 07DF 181 07E6 182
07F1 183 07F8 184 0801 185 080E 186 0812 187
0812 188 0812 189 0818 190 0819 191 0819 195
081F 196 082B 197 0831 198 083F 199 084A 200
0851 201 0857 202 085D 203 0865 204 087F 205
088D 206 0890 207 0893 208 08A1 209 08AF 210
08BB 211 08C2 212 08C3 213 09C0 215 09C6 217
09C9 218 09D4 219 09D9 220 09DC 221 08C3 222
08C9 223 08D2 224 08D7 225 08DD 226 08EC 227
091C 228 0925 229 092D 230 0933 231 093D 232
0943 233 0951 234 0957 235 0969 236 096F 237
0986 238 098C 239 0994 240 099A 241 09A3 242
09A9 243 09B6 244 09BC 245 09BF 246 09DD 247
09DD 249 09E3 250 09E8 251 09F4 252 09FC 254
0A03 255 0A06 256 0A06 257 0A13 258 0A15 259
0A18 260 0A19 261 0A21 264 0A2B 265 0A37 266
0A3C 267 0A4A 268 0A64 269 0A69 270 0A6D 271
0A72 272 0A79 273 0A7D 274 0A84 275 0A87 276
0A87 278 0C69 281 0C6F 283 0C78 284 0C7F 285
0C86 286 0C89 287 0C8E 288 0A87 289 0A8C 290
0A8C 291 0A8F 292 0A9F 293 0AA8 294 0AAC 295
0AB4 297 0ABA 298 0ABF 299 0ACB 300 0ADC 301
0AE2 302 0AF9 303 0B01 304 0B0B 305 0B0E 306
0B15 307 0B18 308 0B20 310 0B26 311 0B2C 312
0B32 313 0B38 314 0B3E 315 0B4C 316 0B4F 317
0B60 318 0B66 319 0B85 320 0B8A 321 0BA1 322
0BA4 323 0BAB 324 0BAE 325 0BB6 327 0BB9 328
0BBC 329 0BBF 330 0BC7 331 0BCD 333 0BDB 334
0BDE 335 0BE6 337 0BEC 338 0BEF 339 0BEF 340
0BF2 341 0C0B 343 0C11 344 0C14 345 0C14 346
0C19 347 0C25 348 0C2D 349 0C35 350 0C38 351
0C46 352 0C46 353 0C49 354 0C51 355 0C54 356
0C5C 358 0C62 359 0C65 360 0C65 361 0C68 362
0C8F 363 0C95 365 0C9B 366 0CA0 367 0CAC 368
0CBA 369 0CC4 370 0CD0 371 0CEB 373 0CF0 374
0CF9 375 0CF9 376 0CFC 377 0D01 378 0D04 379
0D05 380 0D05 381 0D0B 382 0D14 383 0D1A 384
0D1B 385 0D1B 386 0D25 387 0D26 388 0D26 389
0D2C 390 0D2F 391 0D32 392 0D33 393 0D33 396
0D39 397 0D3F 398 0D44 399 0D50 400 0D58 402
0D5F 403 0D62 404 0D68 405 0D70 406 0D78 407
0D7D 408 0D83 409 0D86 410 0D86 411 0D93 412
0DA0 413 0DA2 414 0DA5 415 0DA8 416 0DA9 417
0DA9 418 0DB1 419 0DB9 420 0DBA 421 135D 425
135D 426 136B 427 136C 430 136C 432 1374 433
1377 434 1387 435 139F 436 13A7 437 13B7 438
13BD 439 13C0 440 13C0 441 13C0 443 13CE 444
13E3 446 13EB 447 13F0 448 13F7 449 13F7 450
1401 451 0DBA 452 0DBD 453 0DC0 454 0DC5 455
0DCA 456 0DD1 458 0DD9 459 0DDA 460 0DE1 461
0DE4 462 0DEC 464 0DEF 465 0DF0 466 0DF0 467
0DFA 468 0E04 469 0E0A 470 0E12 471 0E24 472
0E29 473 0E2F 474 0E45 475 0E48 476 0E56 477
0E71 478 0E79 479 0E84 480 0E8E 481 0E95 482
0E98 483 0E9F 484 0EA9 486 0EB3 487 0EB6 488
0ED8 490 0EDE 491 0EE4 492 0EEA 493 0EED 494
0EED 495 0EFE 496 0F0C 497 0F24 498 0F2E 499
0F60 500 0F60 501 0F79 502 0FB9 503 0FBE 504
0FCD 505 0FD2 506 0FF1 507 0FFF 508 1007 509
101C 510 1024 511 103A 512 103D 513 1040 514
1043 515 104F 516 1058 517 1060 519 106B 521
1071 522 107C 523 1082 524 1097 525 10A6 526
10A9 527 10AF 528 10BE 529 10C1 530 10CF 531
10F3 533 1102 534 111B 535 112C 536 1133 537
1138 538 113B 539 1145 540 114A 541 1154 542
1161 543 1164 544 1164 545 116B 546 1174 547
1177 548 117D 549 1183 550 118F 551 119E 552
11A1 553 11A4 554 11B8 555 11BD 556 11C4 558
11CA 559 11D2 560 11DB 561 11E6 562 11E9 563
11E9 564 11FA 565 11FD 566 120E 567 1213 568
1216 569 1227 570 122A 571 122F 572 1234 573
1241 574 1249 575 124E 576 1251 577 125A 578
125F 579 126F 580 1274 581 1277 582 127E 583
1283 584 128A 585 128D 586 1290 587 1293 588
1293 589 1299 590 12A5 591 12AC 593 12AF 594
12B0 595 12B0 596 12B6 597 12B9 598 12BC 599
12BF 600 12CF 601 12E1 602 12F3 603 1305 604
1317 605 131F 606 1333 607 1338 608 133B 609
1341 610 1352 611 1359 612 135C 613 135C 614
1402 615 1402 616 1405 617 1408 618 1410 620
1413 621 141D 623 1420 624 1423 625 1426 626
142C 627 142F 629 1432 630 143F 631 1445 632
1448 633 1448 634 0433 635 043A 636 043E 637
0446 638 044F 640 0454 641 046C 642 0472 644
047A 645 0480 647 0488 648 048B 649 048B 650
048B 651 048B 652 048F 653
0000 MODULE#

View File

@@ -0,0 +1,893 @@
stat:
do;
declare
cpmversion literally '20h'; /* requires 2.0 cp/m */
/* c p / m s t a t u s c o m m a n d (s t a t) */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/* status status status status status status */
/*
copyright(c) 1975, 1976, 1977, 1978, 1979
digital research
box 579
pacific grove, ca
93950
*/
/* modified 10/30/78 to fix the space computation */
/* modified 01/28/79 to remove despool dependencies */
/* modified 07/26/79 to operate under cp/m 2.0 */
declare jump byte data(0c3h),
jadr address data (.status);
/* jump to status */
/* function call 32 returns the address of the disk parameter
block for the currently selected disk, which consists of:
scptrk (2 by) number of sectors per track
blkshf (1 by) log2 of blocksize (2**blkshf=blksize)
blkmsk (1 by) 2**blkshf-1
extmsk (1 by) logical/physical extents
maxall (2 by) max alloc number
dirmax (2 by) size of directory-1
dirblk (2 by) reservation bits for directory
chksiz (2 by) size of checksum vector
offset (2 by) offset for operating system
*/
declare
/* fixed locations for cp/m */
bdosa literally '0006h', /* bdos base */
buffa literally '0080h', /* default buffer */
fcba literally '005ch', /* default file control block */
dolla literally '006dh', /* dollar sign position */
parma literally '006eh', /* parameter, if sent */
rreca literally '007dh', /* random record 7d,7e,7f */
rreco literally '007fh', /* high byte of random overflow */
ioba literally '0003h', /* iobyte address */
sectorlen literally '128', /* sector length */
memsize address at(bdosa), /* end of memory */
rrec address at(rreca), /* random record address */
rovf byte at(rreco), /* overflow on getfile */
doll byte at(dolla), /* dollar parameter */
parm byte at(parma), /* parameter */
sizeset byte, /* true if displaying size field */
dpba address, /* disk parameter block address */
dpb based dpba structure
(spt address, bls byte, bms byte, exm byte, mxa address,
dmx address, dbl address, cks address, ofs address),
scptrk literally 'dpb.spt',
blkshf literally 'dpb.bls',
blkmsk literally 'dpb.bms',
extmsk literally 'dpb.exm',
maxall literally 'dpb.mxa',
dirmax literally 'dpb.dmx',
dirblk literally 'dpb.dbl',
chksiz literally 'dpb.cks',
offset literally 'dpb.ofs';
boot: procedure external;
/* reboot */
end boot;
mon1: procedure(f,a) external;
declare f byte, a address;
end mon1;
mon2: procedure(f,a) byte external;
declare f byte, a address;
end mon2;
mon3: procedure(f,a) address external;
declare f byte, a address;
end mon3;
status: procedure;
declare copyright(*) byte data (
' Copyright (c) 1979, Digital Research');
/* dummy outer procedure 'status' will start at 100h */
/* determine status of currently selected disk */
declare alloca address,
/* alloca is the address of the disk allocation vector */
alloc based alloca (1024) byte; /* allocation vector */
declare
true literally '1',
false literally '0',
forever literally 'while true',
cr literally '13',
lf literally '10';
printchar: procedure(char);
declare char byte;
call mon1(2,char);
end printchar;
crlf: procedure;
call printchar(cr);
call printchar(lf);
end crlf;
printb: procedure;
/* print blank character */
call printchar(' ');
end printb;
printx: procedure(a);
declare a address;
declare s based a byte;
do while s <> 0;
call printchar(s);
a = a + 1;
end;
end printx;
print: procedure(a);
declare a address;
/* print the string starting at address a until the
next 0 is encountered */
call crlf;
call printx(a);
end print;
break: procedure byte;
return mon2(11,0); /* console ready */
end break;
declare dcnt byte;
version: procedure byte;
/* returns current cp/m version # */
return mon2(12,0);
end version;
select: procedure(d);
declare d byte;
call mon1(14,d);
end select;
open: procedure(fcb);
declare fcb address;
dcnt = mon2(15,fcb);
end open;
search: procedure(fcb);
declare fcb address;
dcnt = mon2(17,fcb);
end search;
searchn: procedure;
dcnt = mon2(18,0);
end searchn;
cselect: procedure byte;
/* return current disk number */
return mon2(25,0);
end cselect;
setdma: procedure(dma);
declare dma address;
call mon1(26,dma);
end setdma;
getalloca: procedure address;
/* get base address of alloc vector */
return mon3(27,0);
end getalloca;
getlogin: procedure address;
/* get the login vector */
return mon3(24,0);
end getlogin;
writeprot: procedure;
/* write protect the current disk */
call mon1(28,0);
end writeprot;
getrodisk: procedure address;
/* get the read-only disk vector */
return mon3(29,0);
end getrodisk;
setind: procedure;
/* set file indicators for current fcb */
call mon1(30,fcba);
end setind;
set$dpb: procedure;
/* set disk parameter block values */
dpba = mon3(31,0); /* base of dpb */
end set$dpb;
getuser: procedure byte;
/* return current user number */
return mon2(32,0ffh);
end getuser;
setuser: procedure(user);
declare user byte;
call mon1(32,user);
end setuser;
getfilesize: procedure(fcb);
declare fcb address;
call mon1(35,fcb);
end getfilesize;
declare oldsp address, /* sp on entry */
stack(16) address; /* this program's stack */
declare
fcbmax literally '512', /* max fcb count */
fcbs literally 'memory',/* remainder of memory */
fcb(33) byte at (fcba), /* default file control block */
buff(128) byte at (buffa), /* default buffer */
ioval byte at (ioba); /* io byte */
declare bpb address; /* bytes per block */
set$bpb: procedure;
call set$dpb; /* disk parameters set */
bpb = shl(double(1),blkshf) * sectorlen;
end set$bpb;
select$disk: procedure(d);
declare d byte;
/* select disk and set bpb */
call select(d);
call set$bpb; /* bytes per block */
end select$disk;
getalloc: procedure(i) byte;
/* return the ith bit of the alloc vector */
declare i address;
return
rol(alloc(shr(i,3)), (i and 111b) + 1);
end getalloc;
declare
accum(4) byte, /* accumulator */
ibp byte; /* input buffer pointer */
compare: procedure(a) byte;
/* compare accumulator with four bytes addressed by a */
declare a address;
declare (s based a) (4) byte;
declare i byte;
do i = 0 to 3;
if s(i) <> accum(i) then return false;
end;
return true;
end compare;
scan: procedure;
/* fill accum with next input value */
declare (i,b) byte;
setacc: procedure(b);
declare b byte;
accum(i) = b; i = i + 1;
end setacc;
/* deblank input */
do while buff(ibp) = ' '; ibp=ibp+1;
end;
/* initialize accum length */
i = 0;
do while i < 4;
if (b := buff(ibp)) > 1 then /* valid */
call setacc(b); else /* blank fill */
call setacc(' ');
if b <= 1 or b = ',' or b = ':' or
b = '*' or b = '.' or b = '>' or
b = '<' or b = '=' then buff(ibp) = 1;
else
ibp = ibp + 1;
end;
ibp = ibp + 1;
end scan;
pdecimal: procedure(v,prec);
/* print value v with precision prec (10,100,1000)
with leading zero suppression */
declare
v address, /* value to print */
prec address, /* precision */
zerosup byte, /* zero suppression flag */
d byte; /* current decimal digit */
zerosup = true;
do while prec <> 0;
d = v / prec ; /* get next digit */
v = v mod prec;/* get remainder back to v */
prec = prec / 10; /* ready for next digit */
if prec <> 0 and zerosup and d = 0 then call printb; else
do; zerosup = false; call printchar('0'+d);
end;
end;
end pdecimal;
add$block: procedure(ak,ab);
declare (ak, ab) address;
/* add one block to the kilobyte accumulator */
declare kaccum based ak address; /* kilobyte accum */
declare baccum based ab address; /* byte accum */
baccum = baccum + bpb;
do while baccum >= 1024;
baccum = baccum - 1024;
kaccum = kaccum + 1;
end;
end add$block;
count: procedure(mode) address;
declare mode byte; /* true if counting 0's */
/* count kb remaining, kaccum set upon exit */
declare
ka address, /* kb accumulator */
ba address, /* byte accumulator */
i address, /* local index */
bit byte; /* always 1 if mode = false */
ka, ba = 0;
bit = 0;
do i = 0 to maxall;
if mode then bit = getalloc(i);
if not bit then call add$block(.ka,.ba);
end;
return ka;
end count;
abortmsg: procedure;
call print(.('** Aborted **',0));
end abortmsg;
userstatus: procedure;
/* display active user numbers */
declare i byte;
declare user(32) byte;
declare ufcb(*) byte data ('????????????',0,0,0);
call print(.('Active User :',0));
call pdecimal(getuser,10);
call print(.('Active Files:',0));
do i = 0 to last(user);
user(i) = false;
end;
call setdma(.fcbs);
call search(.ufcb);
do while dcnt <> 255;
if (i := fcbs(shl(dcnt and 11b,5))) <> 0e5h then
user(i and 1fh) = true;
call searchn;
end;
do i = 0 to last(user);
if user(i) then call pdecimal(i,10);
end;
end userstatus;
drivestatus: procedure;
declare
rpb address,
rpd address;
pv: procedure(v);
declare v address;
call crlf;
call pdecimal(v,10000);
call printchar(':');
call printb;
end pv;
/* print the characteristics of the currently selected drive */
call print(.(' ',0));
call printchar(cselect+'A');
call printchar(':');
call printx(.(' Drive Characteristics',0));
rpb = shl(double(1),blkshf); /* records/block=2**blkshf */
if (rpd := (maxall+1) * rpb) = 0 and (rpb <> 0) then
call print(.('65536: ',0)); else
call pv(rpd);
call printx(.('128 Byte Record Capacity',0));
call pv(count(false));
call printx(.('Kilobyte Drive Capacity',0));
call pv(dirmax+1);
call printx(.('32 Byte Directory Entries',0));
call pv(shl(chksiz,2));
call printx(.('Checked Directory Entries',0));
call pv((extmsk+1) * 128);
call printx(.('Records/ Extent',0));
call pv(rpb);
call printx(.('Records/ Block',0));
call pv(scptrk);
call printx(.('Sectors/ Track',0));
call pv(offset);
call printx(.('Reserved Tracks',0));
call crlf;
end drivestatus;
diskstatus: procedure;
/* display disk status */
declare login address, d byte;
login = getlogin; /* login vector set */
d = 0;
do while login <> 0;
if low(login) then
do; call select$disk(d);
call drivestatus;
end;
login = shr(login,1);
d = d + 1;
end;
end diskstatus;
match: procedure(va,vl) byte;
/* return index+1 to vector at va if match */
declare va address,
v based va (16) byte,
vl byte;
declare (i,j,match,sync) byte;
j,sync = 0;
do sync = 1 to vl;
match = true;
do i = 0 to 3;
if v(j) <> accum(i) then match=false;
j = j + 1;
end;
if match then return sync;
end;
return 0; /* no match */
end match;
declare devl(*) byte data
('CON:RDR:PUN:LST:DEV:VAL:USR:DSK:');
devreq: procedure byte;
/* process device request, return true if found */
/* device tables */
declare
devr(*) byte data
(/* console */ 'TTY:CRT:BAT:UC1:',
/* reader */ 'TTY:PTR:UR1:UR2:',
/* punch */ 'TTY:PTP:UP1:UP2:',
/* listing */ 'TTY:CRT:LPT:UL1:');
declare
(i,j,iobyte,items) byte;
prname: procedure(a);
declare a address,
x based a byte;
/* print device name at a */
do while x <> ':';
call printchar(x); a=a+1;
end;
call printchar(':');
end prname;
items = 0;
do forever;
call scan;
if (i:=match(.devl,8)) = 0 then return items<>0;
items = items+1; /* found first/next item */
if i = 5 then /* device status request */
do;
iobyte = ioval; j = 0;
do i = 0 to 3;
call prname(.devl(shl(i,2)));
call printx(.(' is ',0));
call prname(.devr(shl(iobyte and 11b,2)+j));
j = j + 16; iobyte = shr(iobyte,2);
call crlf;
end;
end; else /* not dev: */
if i = 6 then /* list possible assignment */
do;
call print(.('Temp R/O Disk: d:=R/O',0));
call print(.('Set Indicator: d:filename.typ ',
'$R/O $R/W $SYS $DIR',0));
call print(.('Disk Status : DSK: d:DSK:',0));
call print(.('User Status : USR:',0));
call print(.('Iobyte Assign:',0));
do i = 0 to 3; /* each line shows one device */
call crlf;
call prname(.devl(shl(i,2)));
call printx(.(' =',0));
do j = 0 to 12 by 4;
call printchar(' ');
call prname(.devr(shl(i,4)+j));
end;
end;
end; else
if i = 7 then /* list user status values */
do; call userstatus;
return true;
end; else
if i = 8 then /* show the disk device status */
call diskstatus; else
/* scan item i-1 in device table */
do; /* find base of destination */
j = shl(i:=i-1,4);
call scan;
if accum(0) <> '=' then
do; call print(.('Bad Delimiter',0));
return true;
end;
call scan;
if (j:=match(.devr(j),4)-1) = 255 then
do; call print(.('Invalid Assignment',0));
return true;
end;
iobyte = 1111$1100b; /* construct mask */
do while (i:=i-1) <> 255;
iobyte = rol(iobyte,2);
j = shl(j,2);
end;
ioval = (ioval and iobyte) or j;
end;
/* end of current item, look for more */
call scan;
if accum(0) = ' ' then return true;
if accum(0) <> ',' then
do; call print(.('Bad Delimiter',0));
return true;
end;
end; /* of do forever */
end devreq;
pvalue: procedure(v);
declare (d,zero) byte,
(k,v) address;
k = 10000;
zero = false;
do while k <> 0;
d = low(v/k); v = v mod k;
k = k / 10;
if zero or k = 0 or d <> 0 then
do; zero = true; call printchar('0'+d);
end;
end;
call printchar('k');
call crlf;
end pvalue;
comp$alloc: procedure;
alloca = getalloca;
call printchar(cselect+'A');
call printx(.(': ',0));
end comp$alloc;
prcount: procedure;
/* print the actual byte count */
call pvalue(count(true));
end prcount;
pralloc: procedure;
/* print allocation for current disk */
call print (.('Bytes Remaining On ',0));
call comp$alloc;
call prcount;
end pralloc;
prstatus: procedure;
/* print the status of the disk system */
declare (login, rodisk) address;
declare d byte;
login = getlogin; /* login vector set */
rodisk = getrodisk; /* read only disk vector set */
d = 0;
do while login <> 0;
if low(login) then
do; call select$disk(d);
call comp$alloc;
call printx(.('R/',0));
if low(rodisk) then
call printchar('O'); else
call printchar('W');
call printx(.(', Space: ',0));
call prcount;
end;
login = shr(login,1); rodisk = shr(rodisk,1);
d = d + 1;
end;
call crlf;
end prstatus;
setdisk: procedure;
if fcb(0) <> 0 then call select$disk(fcb(0)-1);
end setdisk;
getfile: procedure;
/* process file request */
declare
fnam literally '11', fext literally '12',
fmod literally '14',
frc literally '15', fln literally '15',
fdm literally '16', fdl literally '31',
ftyp literally '9',
rofile literally '9', /* read/only file */
infile literally '10'; /* invisible file */
declare
fcbn address, /* number of fcb's collected so far */
finx(fcbmax) address, /* index vector used during sort */
fcbe(fcbmax) address, /* extent counts */
fcbb(fcbmax) address, /* byte count (mod kb) */
fcbk(fcbmax) address, /* kilobyte count */
fcbr(fcbmax) address, /* record count */
bfcba address, /* index into directory buffer */
fcbsa address, /* index into fcbs */
bfcb based bfcba (32) byte, /* template over directory */
fcbv based fcbsa (16) byte; /* template over fcbs entry */
declare
i address, /* fcb counter during collection and display */
l address, /* used during sort and display */
k address, /* " */
m address, /* " */
kb byte, /* byte counter */
lb byte, /* byte counter */
mb byte, /* byte counter */
(b,f) byte, /* counters */
matched byte; /* used during fcbs search */
multi16: procedure;
/* utility to compute fcbs address from i */
fcbsa = shl(i,4) + .fcbs;
end multi16;
declare
scase byte; /* status case # */
declare
fstatlist(*) byte data('R/O',0,'R/W',0,'SYS',0,'DIR',0);
setfilestatus: procedure byte;
/* eventually, scase set r/o=0,r/w=1,dat=2,sys=3 */
declare
fstat(*) byte data('R/O R/W SYS DIR ');
if doll = ' ' then return false;
call move(4,.parm,.accum); /* $???? */
if accum(0) = 'S' and accum(1) = ' ' then
return not (sizeset := true);
/* must be a parameter */
if (scase := match(.fstat,4)) = 0 then
call print(.('Invalid File Indicator',0));
return true;
end setfilestatus;
printfn: procedure;
declare (k, lb) byte;
/* print file name */
do k = 1 to fnam;
if (lb := fcbv(k) and 7fh) <> ' ' then
do; if k = ftyp then call printchar('.');
call printchar(lb);
end;
end;
end printfn;
call set$bpb; /* in case default disk */
call setdisk;
sizeset = false;
scase = 255;
if setfilestatus then
do; if scase = 0 then return;
scase = scase - 1;
end; else
if fcb(1) = ' ' then /* no file named */
do; call pralloc;
return;
end;
/* read the directory, collect all common file names */
fcbn,fcb(0) = 0;
fcb(fext),fcb(fmod) = '?'; /* question mark matches all */
call search(fcba); /* fill directory buffer */
collect: /* label for debug */
do while dcnt <> 255;
/* another item found, compare it for common entry */
bfcba = shl(dcnt and 11b,5)+buffa; /* dcnt mod 4 * 32 */
matched = false; i = 0;
do while not matched and i < fcbn;
/* compare current entry */
call multi16;
do kb = 1 to fnam;
if bfcb(kb) <> fcbv(kb) then kb = fnam; else
/* complete match if at end */
matched = kb = fnam;
end;
i = i + 1;
end;
checkmatched: /* label for debug */
if matched then i = i - 1; else
do; /* copy to new position in fcbs */
fcbn = (i := fcbn) + 1;
call multi16;
/* fcbsa set to next to fill */
if (fcbn > fcbmax) or (fcbsa + 16) >= memsize then
do; call print(.('** Too Many Files **',0));
i = 0; fcbn = 1;
call multi16;
end;
/* save index to element for later sort */
finx(i) = i;
do kb = 0 to fnam;
fcbv(kb) = bfcb(kb);
end;
fcbe(i),fcbb(i),fcbk(i),fcbr(i) = 0;
end;
/* entry is at, or was placed at location i in fcbs */
fcbe(i) = fcbe(i) + 1; /* extent incremented */
/* record count */
fcbr(i) = fcbr(i) + bfcb(frc)
+ (bfcb(fext) and extmsk) * 128;
/* count kilobytes */
countbytes: /* label for debug */
lb = 1;
if maxall > 255 then lb = 2; /* double precision inx */
do kb = fdm to fdl by lb;
mb = bfcb(kb);
if lb = 2 then /* double precision inx */
mb = mb or bfcb(kb+1);
if mb <> 0 then /* allocated */
call add$block(.fcbk(i),.fcbb(i));
end;
call searchn; /* to next entry in directory */
end; /* of do while dcnt <> 255 */
display: /* label for debug */
/* now display the collected data */
if fcbn = 0 then call print(.('File Not Found',0)); else
if scase = 255 then /* display collected data */
do;
/* sort the file names in ascending order */
if fcbn > 1 then /* requires at least two to sort */
do; l = 1;
do while l > 0; /* bubble sort */
l = 0;
do m = 0 to fcbn - 2;
i = finx(m+1); call multi16; bfcba = fcbsa; i = finx(m);
call multi16; /* sets fcbsa, basing fcbv */
do kb = 1 to fnam; /* compare for less or equal */
if (b:=bfcb(kb)) < (f:=fcbv(kb)) then /* switch */
do; k = finx(m); finx(m) = finx(m + 1);
finx(m + 1) = k; l = l + 1; kb = fnam;
end;
else if b > f then kb = fnam; /* stop compare */
end;
end;
end;
end;
if sizeset then
call print(.(' Size ',0)); else
call crlf;
call printx(.(' Recs Bytes Ext Acc',0));
l = 0;
do while l < fcbn;
i = finx(l); /* i is the index to next in order */
call multi16; call crlf;
/* print the file length */
call move(16,.fcbv(0),fcba);
fcb(0) = 0;
if sizeset then
do; call getfilesize(fcba);
if rovf <> 0 then call printx(.('65536',0)); else
call pdecimal(rrec,10000);
call printb;
end;
call pdecimal(fcbr(i),10000); /* rrrrr */
call printb; /* blank */
call pdecimal(fcbk(i),10000); /* bbbbbk */
call printchar('k'); call printb;
call pdecimal(fcbe(i),1000); /* eeee */
call printb;
call printchar('R');
call printchar('/');
if rol(fcbv(rofile),1) then
call printchar('O'); else
call printchar('W');
call printb;
call printchar('A'+cselect); call printchar(':');
/* print filename.typ */
if (mb:=rol(fcbv(infile),1)) then call printchar('(');
call printfn;
if mb then call printchar(')');
l = l + 1;
end;
call pralloc;
end; else
setfileatt: /* label for debug */
/* set file attributes */
do;
l = 0;
do while l < fcbn;
if break then
do; call abortmsg; return;
end;
i = l;
call multi16;
call crlf;
call printfn;
do case scase;
/* set to r/o */
fcbv(rofile) = fcbv(rofile) or 80h;
/* set to r/w */
fcbv(rofile) = fcbv(rofile) and 7fh;
/* set to sys */
fcbv(infile) = fcbv(infile) or 80h;
/* set to dir */
fcbv(infile) = fcbv(infile) and 7fh;
end;
/* place name into default fcb location */
call move(16,fcbsa,fcba);
fcb(0) = 0; /* in case matched user# > 0 */
call setind; /* indicators set */
call printx(.(' set to ',0));
call printx(.fstatlist(shl(scase,2)));
l = l + 1;
end;
end;
end getfile;
setdrivestatus: procedure;
/* handle possible drive status assignment */
call scan; /* remove drive name */
call scan; /* check for = */
if accum(0) = '=' then
do; call scan; /* get assignment */
if compare(.('R/O ')) then
do; call setdisk; /* a: ... */
call writeprot;
end; else
call print(.('Invalid Disk Assignment',0));
end;
else /* not a disk assignment */
do; call setdisk;
if match(.devl,8) = 8 then call drive$status; else
call getfile;
end;
end setdrivestatus;
/* save stack pointer and reset */
oldsp = stackptr;
stackptr = .stack(length(stack));
/* process request */
if version < cpmversion then
call print(.('Wrong CP/M Version (Requires 2.0)',0));
else
do;
/* size display if $S set in command */
ibp = 1; /* initialize buffer pointer */
if fcb(0) = 0 and fcb(1) = ' ' then /* stat only */
call prstatus; else
do;
if fcb(0) <> 0 then
call setdrivestatus; else
do;
if not devreq then /* must be file name */
call getfile;
end;
end;
end;
/* restore old stack before exit */
stackptr = oldsp;
end status;
end;

View File

@@ -0,0 +1,35 @@
0000 SUBMIT#
0000 SUB#
01DF 15 01F7 18 01FD 20 0206 21 0207 23
020D 25 0219 26 021A 27 0220 29 022C 30
022D 31 0233 33 023C 34 023D 35 0243 37
024D 38 024D 39 0253 41 025D 42 025D 43
0263 45 026F 46 0270 47 027F 50 028B 51
0295 52 029C 53 02A3 54 02A6 55 02A7 57
02AD 59 02B3 60 02B9 61 02BF 62 02C7 63
02CB 64 02CC 66 02CC 67 02D8 68 02E3 69
02EF 70 02F5 71 02FD 72 0303 73 0308 74
0309 75 0309 77 0312 79 031D 80 0320 81
0325 82 0325 83 033D 85 034B 87 0350 88
035B 90 0360 91 0362 92 0362 93 0362 94
0362 95 036C 96 0374 97 0378 98 0378 99
0378 100 0383 101 0389 102 038A 104 0481 106
0481 107 04A3 109 04A7 110 04AA 111 04AA 112
04AD 113 04AD 114 04AD 115 04BC 116 04C0 117
04C3 118 04C4 119 04C8 121 04D8 122 04DE 123
04E9 124 04F7 125 04FD 126 038A 128 0395 129
039A 130 03A1 131 03A6 132 03C1 133 03C9 135
03D1 137 03DC 138 03E6 139 03F5 140 03FE 142
0403 143 0406 144 040E 145 0412 146 0419 147
041C 148 041F 149 0422 150 0429 151 0430 152
0433 153 0433 154 0436 155 043E 157 044D 158
0456 159 045E 160 0461 161 0468 162 0468 163
046B 164 0476 165 047D 166 0480 167 04FE 168
057A 170 057A 171 0587 172 04FE 173 0504 174
0509 175 050F 176 0517 177 051D 178 0528 179
052E 180 0537 181 0542 182 054B 183 0558 184
055C 185 055F 186 0562 187 0565 188 056B 189
0573 190 0579 191 01DF 193 01E6 194 01EA 195
01ED 196 01F0 197 01F3 198 01F6 199
0000 MODULE#

View File

@@ -0,0 +1,293 @@
sub:
do;
/* modified 7/26/79 to work with cpm 2.0, module number not zero */
declare
wboot literally '0000h', /* warm start entry point */
bdos literally '0005h', /* jmp bdos */
dfcba literally '005ch', /* default fcb address */
dbuff literally '0080h'; /* default buffer address */
declare jump byte data(0c3h); /* c3 = jmp */
declare jadr address data(.submit);
/* jmp to submit is placed at the beginning of the module */
boot: procedure external;
/* system reboot */
end boot;
mon1: procedure(f,a) external;
declare f byte, a address;
/* bdos interface, no returned value */
end mon1;
mon2: procedure(f,a) byte external;
declare f byte, a address;
/* bdos interface, return byte value */
end mon2;
declare
copyright(*) byte data
(' copyright(c) 1977, digital research ');
declare
ln(5) byte initial('001 $'),
ln1 byte at(.ln(0)),
ln2 byte at(.ln(1)),
ln3 byte at(.ln(2)),
dfcb(33) byte initial(0,'$$$ SUB',0,0,0),
drec byte at(.dfcb(32)), /* current record */
buff(128) byte at(dbuff), /* default buffer */
sfcb(33) byte at(dfcba); /* default fcb */
submit: procedure;
/* t h e c p / m 's u b m i t' f u n c t i o n
copyright (c) 1976, 1977, 1978
digital research
box 579
pacific grove, ca.
93950
*/
declare lit literally 'literally',
dcl lit 'declare',
proc lit 'procedure',
addr lit 'address',
ctll lit '0ch',
lca lit '110$0001b', /* lower case a */
lcz lit '111$1010b', /* lower case z */
endfile lit '1ah'; /* cp/m end of file */
declare
true literally '1',
false literally '0',
forever literally 'while true',
cr literally '13',
lf literally '10',
what literally '63';
print: procedure(a);
declare a address;
/* print the string starting at address a until the
next dollar sign is encountered */
call mon1(9,a);
end print;
declare dcnt byte;
open: procedure(fcb);
declare fcb address;
dcnt = mon2(15,fcb);
end open;
close: procedure(fcb);
declare fcb address;
dcnt = mon2(16,fcb);
end close;
delete: procedure(fcb);
declare fcb address;
call mon1(19,fcb);
end delete;
diskread: procedure(fcb) byte;
declare fcb address;
return mon2(20,fcb);
end diskread;
diskwrite: procedure(fcb) byte;
declare fcb address;
return mon2(21,fcb);
end diskwrite;
make: procedure(fcb);
declare fcb address;
dcnt = mon2(22,fcb);
end make;
move: procedure(s,d,n);
declare (s,d) address, n byte;
declare a based s byte, b based d byte;
do while (n := n - 1) <> 255;
b = a; s = s + 1; d = d + 1;
end;
end move;
declare oldsp address; /* calling program's stack pointer */
error: procedure(a);
declare a address;
call print(.(cr,lf,'$'));
call print(.('Error On Line $'));
call print(.ln1);
call print(a);
stackptr = oldsp;
/* return to ccp */
end error;
declare sstring(128) byte, /* substitute string */
sbp byte; /* source buffer pointer (0-128) */
setup: procedure;
/* move buffer to substitute string */
call move(.buff(1),.sstring(0),127);
sstring(buff(0))=0; /* mark end of string */
call move(.('SUB'),.sfcb(9),3); /* set file type to sub */
call open(.sfcb(0));
if dcnt = 255 then
call error(.('No ''SUB'' File Present$'));
/* otherwise file is open - read subsequent data */
sbp = 128; /* causes read below */
end setup;
getsource: procedure byte;
/* read the next source character */
declare b byte;
if sbp > 127 then
do; if diskread(.sfcb(0)) <> 0 then
return endfile;
sbp = 0;
end;
if (b := buff((sbp:=sbp+1)-1)) = cr then
do; /* increment line */
if (ln3 := ln3 + 1) > '9' then
do; ln3 = '0';
if (ln2 := ln2 + 1) > '9' then
do; ln2 = '0';
ln1 = ln1 + 1;
end;
end;
end;
/* translate to upper case */
if (b-61h) < 26 then /* lower case alpha */
b = b and 5fh; /* change to upper case */
return b;
end getsource;
writebuff: procedure;
/* write the contents of the buffer to disk */
if diskwrite(.dfcb) <> 0 then /* error */
call error(.('Disk Write Error$'));
end writebuff;
declare rbuff(2048) byte, /* jcl buffer */
rbp address, /* jcl buffer pointer */
rlen byte; /* length of current command */
fillrbuff: procedure;
declare (s,ssbp) byte; /* sub string buffer pointer */
notend: procedure byte;
/* look at next character in sstring, return
true if not at the end of the string - char passed
back in 's' */
if not ((s := sstring(ssbp)) = ' ' or s = 0) then
do;
ssbp = ssbp + 1;
return true;
end;
return false;
end notend;
deblankparm: procedure;
/* clear to next non blank substitute string */
do while sstring(ssbp) = ' ';
ssbp = ssbp + 1;
end;
end deblankparm;
putrbuff: procedure(b);
declare b byte;
if (rbp := rbp + 1) > last(rbuff) then
call error(.('Command Buffer Overflow$'));
rbuff(rbp) = b;
/* len: c1 ... c125 :00:$ = 128 chars */
if (rlen := rlen + 1) > 125 then
call error(.('Command Too Long$'));
end putrbuff;
declare (reading,b) byte;
/* fill the jcl buffer */
rbuff(0),rbp = 0;
reading = true;
do while reading;
rlen = 0; /* reset command length */
do while (b:=getsource) <> endfile and b <> cr;
if b <> lf then
do; if b = '$' then /* copy substitute string */
do; if (b:=getsource) = '$' then
/* $$ replaced by $ */
call putrbuff(b); else
if (b := b - '0') > 9 then
call error(.('Parameter Error$')); else
do; /* find string 'b' in sstring */
ssbp = 0; call deblankparm; /* ready to scan sstring */
do while b <> 0; b = b - 1;
/* clear next parameter */
do while notend;
end;
call deblankparm;
end;
/* ready to copy substitute string from position ssbp */
do while notend;
call putrbuff(s);
end;
end;
end; else /* not a '$' */
if b = '^' then /* control character */
do; /* must be ^a ... ^z */
if (b:=getsource - 'a') > 25 then
call error(.('Invalid Control Character$'));
else
call putrbuff(b+1);
end; else /* not $ or ^ */
call putrbuff(b);
end;
end; /* of line or input file - compute length */
reading = b = cr;
call putrbuff(rlen); /* store length */
end;
/* entire file has been read and processed */
end fillrbuff;
makefile: procedure;
/* write resulting command file */
declare i byte;
getrbuff: procedure byte;
return rbuff(rbp := rbp - 1);
end getrbuff;
call delete(.dfcb);
drec = 0; /* zero the next record to write */
call make(.dfcb);
if dcnt = 255 then call error(.('Directory Full$'));
do while (i := getrbuff) <> 0;
/* copy i characters to buffer */
/* 00 $ at end of line gives 1.3 & 1.4 compatibility */
buff(0) = i; buff(i+1) = 00; buff(i+2) = '$';
do while i > 0;
buff(i) = getrbuff; i=i-1;
end;
/* buffer filled to $ */
call writebuff;
end;
call close(.dfcb);
if dcnt = 255 then call error(.('Cannot Close, Read/Only?$'));
end makefile;
/* enter here from the ccp with the fcb set */
declare stack(10) address; /* working stack */
oldsp = stackptr;
stackptr = .stack(length(stack));
call setup;
call fillrbuff;
call makefile;
call boot; /* reboot causes commands to be executed */
end submit;
end;

View File

@@ -0,0 +1,439 @@
TITLE 'SYSGEN - SYSTEM GENERATION PROGRAM 8/79'
; SYSTEM GENERATION PROGRAM, VERSION FOR MDS
VERS EQU 20 ;X.X
;
; COPYRIGHT (C) DIGITAL RESEARCH
; 1976, 1977, 1978, 1979
;
NSECTS EQU 26 ;NO. OF SECTORS PER TRACK
NTRKS EQU 2 ;NO. OF OPERATING SYSTEM TRACKS
NDISKS EQU 4 ;NUMBER OF DISK DRIVES
SECSIZ EQU 128 ;SIZE OF EACH SECTOR
LOG2SEC EQU 7 ;LOG 2 SECSIZ
SKEW EQU 1 ;SECTOR SKEW FACTOR
;
FCB EQU 005CH ;DEFAULT FCB LOCATION
FCBCR EQU FCB+32 ;CURRENT RECORD LOCATION
TPA EQU 0100H ;TRANSIENT PROGRAM AREA
LOADP EQU 900H ;LOAD POINT FOR SYSTEM DURING LOAD/STORE
BDOS EQU 5H ;DOS ENTRY POINT
BOOT EQU 0 ;JMP TO 'BOOT' TO REBOOT SYSTEM
CONI EQU 1 ;CONSOLE INPUT FUNCTION
CONO EQU 2 ;CONSOLE OUTPUT FUNCTION
SELF EQU 14 ;SELECT DISK
OPENF EQU 15 ;DISK OPEN FUNCTION
DREADF EQU 20 ;DISK READ FUNCTION
;
MAXTRY EQU 10 ;MAXIMUM NUMBER OF RETRIES ON EACH READ/WRITE
CR EQU 0DH ;CARRIAGE RETURN
LF EQU 0AH ;LINE FEED
STACKSIZE EQU 16 ;SIZE OF LOCAL STACK
;
WBOOT EQU 1 ;ADDRESS OF WARM BOOT (OTHER PATCH ENTRY
; POINTS ARE COMPUTED RELATIVE TO WBOOT)
SELDSK EQU 24 ;WBOOT+24 FOR DISK SELECT
SETTRK EQU 27 ;WBOOT+27 FOR SET TRACK FUNCTION
SETSEC EQU 30 ;WBOOT+30 FOR SET SECTOR FUNCTION
SETDMA EQU 33 ;WBOOT+33 FOR SET DMA ADDRESS
READF EQU 36 ;WBOOT+36 FOR READ FUNCTION
WRITF EQU 39 ;WBOOT+39 FOR WRITE FUNCTION
;
ORG TPA ;TRANSIENT PROGRAM AREA
JMP START
DB 'COPYRIGHT (C) 1978, DIGITAL RESEARCH '
;
; TRANSLATE TABLE - SECTOR NUMBERS ARE TRANSLATED
; HERE TO DECREASE THE SYSGEN TIME FOR MISSED SECTORS
; WHEN SLOW CONTROLLERS ARE INVOLVED. TRANSLATION TAKES
; PLACE ACCORDING TO THE "SKEW" FACTOR SET ABOVE.
;
OST: DB NTRKS ;OPERATING SYSTEM TRACKS
SPT: DB NSECTS ;SECTORS PER TRACK (CAN BE PATCHED)
TRAN: ;BASE OF TRANSLATE TABLE
TRELT SET 1 ;FIRST/NEXT TRAN ELEMENT
TRBASE SET 1 ;BASE FOR WRAPAROUND
REPT NSECTS ;ONCE FOR EACH SECTOR ON A TRACK
DB TRELT ;GENERATE FIRST/NEXT SECTOR
TRELT SET TRELT+SKEW
IF TRELT GT NSECTS
TRBASE SET TRBASE+1
TRELT SET TRBASE
ENDIF
ENDM
;
; NOW LEAVE SPACE FOR EXTENSIONS TO TRANSLATE TABLE
IF NSECTS LT 64
REPT 64-NSECTS
DB 0
ENDM
;
;
;
;
; UTILITY SUBROUTINES
MULTSEC:
;MULTIPLY THE SECTOR NUMBER IN A BY THE SECTOR SIZE
MOV L,A! MVI H,0 ;SECTOR NUMBER IN HL
REPT LOG2SEC ;LOG 2 OF SECTOR SIZE
DAD H
ENDM
RET ;WITH HL = SECTOR * SECTOR SIZE
;
GETCHAR:
; READ CONSOLE CHARACTER TO REGISTER A
MVI C,CONI! CALL BDOS!
; CONVERT TO UPPER CASE BEFORE RETURN
CPI 'A' OR 20H ! RC ;RETURN IF BELOW LOWER CASE A
CPI ('Z' OR 20H) + 1
RNC ;RETURN IF ABOVE LOWER CASE Z
ANI 5FH! RET
;
PUTCHAR:
; WRITE CHARACTER FROM A TO CONSOLE
MOV E,A! MVI C,CONO! CALL BDOS! RET
;
CRLF: ;SEND CARRIAGE RETURN, LINE FEED
MVI A,CR
CALL PUTCHAR
MVI A,LF
CALL PUTCHAR
RET
;
CRMSG: ;PRINT MESSAGE ADDRESSED BY H,L TIL ZERO
;WITH LEADING CRLF
PUSH H! CALL CRLF! POP H ;DROP THRU TO OUTMSG0
OUTMSG:
MOV A,M! ORA A! RZ
; MESSAGE NOT YET COMPLETED
PUSH H! CALL PUTCHAR! POP H! INX H
JMP OUTMSG
;
SEL:
; SELECT DISK GIVEN BY REGISTER A
MOV C,A! LHLD WBOOT! LXI D,SELDSK! DAD D! PCHL
;
TRK: ;SET UP TRACK
LHLD WBOOT ;ADDRESS OF BOOT ENTRY
LXI D,SETTRK ;OFFSET FOR SETTRK ENTRY
DAD D
PCHL ;GONE TO SETTRK
;
SEC: ;SET UP SECTOR NUMBER
LHLD WBOOT
LXI D,SETSEC
DAD D
PCHL
;
DMA: ;SET DMA ADDRESS TO VALUE OF B,C
LHLD WBOOT
LXI D,SETDMA
DAD D
PCHL
;
READ: ;PERFORM READ OPERATION
LHLD WBOOT
LXI D,READF
DAD D
PCHL
;
WRITE: ;PERFORM WRITE OPERATON
LHLD WBOOT
LXI D,WRITF
DAD D
PCHL
;
DREAD: ;DISK READ FUNCTION
MVI C,DREADF
JMP BDOS
;
OPEN: ;FILE OPEN FUNCTION
MVI C,OPENF ! JMP BDOS
;
GETPUT:
; GET OR PUT CP/M (RW=0 FOR READ, 1 FOR WRITE)
; DISK IS ALREADY SELECTED
;
LXI H,LOADP ;LOAD POINT IN RAM FOR CP/M DURING SYSGEN
SHLD DMADDR
;
; CLEAR TRACK TO 00
MVI A,-1 ;START WITH TRACK EQUAL -1
STA TRACK
;
RWTRK: ;READ OR WRITE NEXT TRACK
LXI H,TRACK
INR M ;TRACK = TRACK + 1
LDA OST ;NUMBER OF OPERATING SYSTEM TRACKS
CMP M ;= TRACK NUMBER ?
JZ ENDRW ;END OF READ OR WRITE
;
; OTHERWISE NOTDONE, GO TO NEXT TRACK
MOV C,M ;TRACK NUMBER
CALL TRK ;TO SET TRACK
MVI A,-1 ;COUNTS 0, 1, 2, . . . 25
STA SECTOR ;SECTOR INCREMENTED BEFORE READ OR WRITE
;
RWSEC: ;READ OR WRITE SECTOR
LDA SPT ;SECTORS PER TRACK
LXI H,SECTOR
INR M ;TO NEXT SECTOR
CMP M ;A=26 AND M=0 1 2...25 (USUALLY)
JZ ENDTRK ;
;
; READ OR WRITE SECTOR TO OR FROM CURRENT DMA ADDR
LXI H,SECTOR
MOV E,M ;SECTOR NUMBER
MVI D,0 ;TO DE
LXI H,TRAN
MOV B,M ;TRAN(0) IN B
DAD D ;SECTOR TRANSLATED
MOV C,M ;VALUE TO C READY FOR SELECT
PUSH B ;SAVE TRAN(0),TRAN(SECTOR)
CALL SEC ;SET UP SECTOR NUMBER
POP B ;RECALL TRAN(0),TRAN(SECTOR)
MOV A,C ;TRAN(SECTOR)
SUB B ;-TRAN(0)
CALL MULTSEC ;*SECTOR SIZE
XCHG ;TO DE
LHLD DMADDR ;BASE DMA ADDRESS FOR THIS TRACK
DAD D ;+(TRAN(SECTOR)-TRAN(0))*SECSIZ
MOV B,H
MOV C,L ;TO BC FOR SEC CALL
CALL DMA ;DMA ADDRESS SET FROM B,C
; DMA ADDRESS SET, CLEAR RETRY COUNT
XRA A
STA RETRY ;SET TO ZERO RETRIES
;
TRYSEC: ;TRY TO READ OR WRITE CURRENT SECTOR
LDA RETRY
CPI MAXTRY ;TOO MANY RETRIES?
JC TRYOK
;
; PAST MAXTRIES, MESSAGE AND IGNORE
LXI H,ERRMSG
CALL OUTMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
;
; TYPED A CR, OK TO IGNORE
CALL CRLF
JMP RWSEC
;
TRYOK:
; OK TO TRY READ OR WRITE
INR A
STA RETRY ;RETRY=RETRY+1
LDA RW ;READ OR WRITE?
ORA A
JZ TRYREAD
;
; MUST BE WRITE
CALL WRITE
JMP CHKRW ;CHECK FOR ERROR RETURNS
TRYREAD:
CALL READ
CHKRW:
ORA A
JZ RWSEC ;ZERO FLAG IF R/W OK
;
; ERROR, RETRY OPERATION
JMP TRYSEC
;
; END OF TRACK
ENDTRK:
LDA SPT ;SECTORS PER TRACK
CALL MULTSEC ;*SECSIZ
XCHG ;TO DE
LHLD DMADDR ;BASE DMA FOR THIS TRACK
DAD D ;+SPT*SECSIZ
SHLD DMADDR ;READY FOR NEXT TRACK
JMP RWTRK ;FOR ANOTHER TRACK
;
ENDRW: ;END OF READ OR WRITE, RETURN TO CALLER
RET
;
;
START:
;
LXI SP,STACK ;SET LOCAL STACK POINTER
LXI H,SIGNON
CALL OUTMSG
;
; CHECK FOR DEFAULT FILE LOAD INSTEAD OF GET
;
LDA FCB+1 ;BLANK IF NO FILE
CPI ' '
JZ GETSYS ;SKIP TO GET SYSTEM MESSAGE IF BLANK
LXI D,FCB ;TRY TO OPEN IT
CALL OPEN ;
INR A ;255 BECOMES 00
JNZ RDOK ;OK TO READ IF NOT 255
;
; FILE NOT PRESENT, ERROR AND REBOOT
;
LXI H,NOFILE
CALL CRMSG
JMP REBOOT
;
; FILE PRESENT
; READ TO LOAD POINT
;
RDOK:
XRA A
STA FCBCR ;CURRENT RECORD = 0
;
; PRE-READ AREA FROM TPA TO LOADP
;
MVI C,(LOADP-TPA)/SECSIZ
; PRE-READ FILE
PRERD:
PUSH B ;SAVE COUNT
LXI D,FCB ;INPUT FILE CONTROL COUNT
CALL DREAD ;ASSUME SET TO DEFAULT BUFFER
POP B ;RESTORE COUNT
ORA A
JNZ BADRD ;CANNOT ENCOUNTER END-OF FILE
DCR C ;COUNT DOWN
JNZ PRERD ;FOR ANOTHER SECTOR
;
; SECTORS SKIPPED AT BEGINNING OF FILE
;
LXI H,LOADP
RDINP:
PUSH H
MOV B,H
MOV C,L ;READY FOR DMA
CALL DMA ;DMA ADDRESS SET
LXI D,FCB ;READY FOR READ
CALL DREAD ;
POP H ;RECALL DMA ADDRESS
ORA A ;00 IF READ OK
JNZ PUTSYS ;ASSUME EOF IF NOT.
; MORE TO READ, CONTINUE
LXI D,SECSIZ
DAD D ;HL IS NEW LOAD ADDRESS
JMP RDINP
;
BADRD: ;EOF ENCOUNTERED IN INPUT FILE
LXI H,BADFILE
CALL CRMSG
JMP REBOOT
;
;
GETSYS:
LXI H,ASKGET ;GET SYSTEM?
CALL CRMSG
CALL GETCHAR
CPI CR
JZ PUTSYS ;SKIP IF CR ONLY
;
SUI 'A' ;NORMALIZE DRIVE NUMBER
CPI NDISKS ;VALID DRIVE?
JC GETC ;SKIP TO GETC IF SO
;
; INVALID DRIVE NUMBER
CALL BADDISK
JMP GETSYS ;TO TRY AGAIN
;
GETC:
; SELECT DISK GIVEN BY REGISTER A
ADI 'A'
STA GDISK ;TO SET MESSAGE
SUI 'A'
CALL SEL ;TO SELECT THE DRIVE
; GETSYS, SET RW TO READ AND GET THE SYSTEM
CALL CRLF
LXI H,GETMSG
CALL OUTMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
CALL CRLF
;
XRA A
STA RW
CALL GETPUT
LXI H,DONE
CALL OUTMSG
;
; PUT SYSTEM
PUTSYS:
LXI H,ASKPUT
CALL CRMSG
CALL GETCHAR
CPI CR
JZ REBOOT
SUI 'A'
CPI NDISKS
JC PUTC
;
; INVALID DRIVE NAME
CALL BADDISK
JMP PUTSYS ;TO TRY AGAIN
;
PUTC:
; SET DISK FROM REGISTER C
ADI 'A'
STA PDISK ;MESSAGE SET
SUI 'A'
CALL SEL ;SELECT DEST DRIVE
; PUT SYSTEM, SET RW TO WRITE
LXI H,PUTMSG
CALL CRMSG
CALL GETCHAR
CPI CR
JNZ REBOOT
CALL CRLF
;
LXI H,RW
MVI M,1
CALL GETPUT ;TO PUT SYSTEM BACK ON DISKETTE
LXI H,DONE
CALL OUTMSG
JMP PUTSYS ;FOR ANOTHER PUT OPERATION
;
REBOOT:
MVI A,0
CALL SEL
CALL CRLF
JMP BOOT
BADDISK:
;BAD DISK NAME
LXI H,QDISK
CALL CRMSG
RET
;
;
;
; DATA AREAS
; MESSAGES
SIGNON: DB 'SYSGEN VER '
DB VERS/10+'0','.',VERS MOD 10+'0'
DB 0
ASKGET: DB 'SOURCE DRIVE NAME (OR RETURN TO SKIP)',0
GETMSG: DB 'SOURCE ON '
GDISK: DS 1 ;FILLED IN AT GET FUNCTION
DB ', THEN TYPE RETURN',0
ASKPUT: DB 'DESTINATION DRIVE NAME (OR RETURN TO REBOOT)',0
PUTMSG: DB 'DESTINATION ON '
PDISK: DS 1 ;FILLED IN AT PUT FUNCTION
DB ', THEN TYPE RETURN',0
ERRMSG: DB 'PERMANENT ERROR, TYPE RETURN TO IGNORE',0
DONE: DB 'FUNCTION COMPLETE',0
QDISK: DB 'INVALID DRIVE NAME (USE A, B, C, OR D)',0
NOFILE: DB 'NO SOURCE FILE ON DISK',0
BADFILE:
DB 'SOURCE FILE INCOMPLETE',0
;
; VARIABLES
SDISK: DS 1 ;SELECTED DISK FOR CURRENT OPERATION
TRACK: DS 1 ;CURRENT TRACK
SECTOR: DS 1 ;CURRENT SECTOR
RW: DS 1 ;READ IF 0, WRITE IF 1
DMADDR: DS 2 ;CURRENT DMA ADDRESS
RETRY: DS 1 ;NUMBER OF TRIES ON THIS SECTOR
DS STACKSIZE*2
STACK:
END

View File

@@ -0,0 +1,134 @@
; xsub relocator version 2.2
version equ 20h
; xsub relocator program, included with the module
; to perform the move from 200h to the destination address
;
; copyright (c) 1979, 1980
; digital research
; box 579
; pacific grove, ca.
; 93950
;
org 100h
db (lxi or (b shl 3)) ;lxi b,module size
org $+2 ;skip address field
jmp start
db ' Extended Submit Vers '
db version/16+'0','.',version mod 16+'0'
nogo: db 'Xsub Already Present$'
badver: db 'Requires CP/M Version 2.0 or later$'
;
bdos equ 0005h ;bdos entry point
print equ 9 ;bdos print function
vers equ 12 ;get version number
ccplen equ 0800h ;size of ccp
module equ 200h ;module address
;
start:
; ccp's stack used throughout
push b ;save the module's length
lda bdos+1 ;xsub already present?
cpi 06h ;low address must be 06h
jnz loaderr
lhld bdos+1
inx h
inx h
inx h
lxi d,xsubcon
mvi c,4
present:
ldax d
cmp m
jnz continue
inx h
inx d
dcr c
jz loaderr
jmp present
;
loaderr:
; bdos or xsub not lowest module in memory, return to ccp
mvi c,print
lxi d,nogo ;already present message
call bdos ;to print the message
pop b ;recall length
ret ;to the ccp
;
continue:
mvi c,vers
call bdos ;version number?
cpi version ;2.0 or greater
jnc versok
;
; wrong version
mvi c,print
lxi d,badver
call bdos
pop b
ret ;to ccp
;
versok:
lxi h,bdos+2;address field of jump to bdos (top memory)
mov a,m ;a has high order address of memory top
dcr a ;page directly below bdos
sui (ccplen shr 8) ;-ccp pages
pop b ;recall length of module
push b ;and save it again
sub b ;a has high order address of reloc area
mov d,a
mvi e,0 ;d,e addresses base of reloc area
push d ;save for relocation below
;
lxi h,module;ready for the move
move: mov a,b ;bc=0?
ora c
jz reloc
dcx b ;count module size down to zero
mov a,m ;get next absolute location
stax d ;place it into the reloc area
inx d
inx h
jmp move
;
reloc: ;storage moved, ready for relocation
; hl addresses beginning of the bit map for relocation
pop d ;recall base of relocation area
pop b ;recall module length
push h ;save bit map base in stack
mov h,d ;relocation bias is in d
;
rel0: mov a,b ;bc=0?
ora c
jz endrel
;
; not end of the relocation, may be into next byte of bit map
dcx b ;count length down
mov a,e
ani 111b ;0 causes fetch of next byte
jnz rel1
; fetch bit map from stacked address
xthl
mov a,m ;next 8 bits of map
inx h
xthl ;base address goes back to stack
mov l,a ;l holds the map as we process 8 locations
rel1: mov a,l
ral ;cy set to 1 if relocation necessary
mov l,a ;back to l for next time around
jnc rel2 ;skip relocation if cy=0
;
; current address requires relocation
ldax d
add h ;apply bias in h
stax d
rel2: inx d ;to next address
jmp rel0 ;for another byte to relocate
;
endrel: ;end of relocation
pop d ;clear stacked address
; h has the high order 8-bits of relocated module address
mvi l,0
pchl ;go to relocated program
xsubcon:
db 'xsub'
end

View File

@@ -0,0 +1,195 @@
; xsub 'Extended Submit Facility' version 2.2
;
;
;
; xsub loads below ccp, and feeds command lines to
; programs which read buffered input
;
bias equ 0000h ;bias for relocation
base equ 0ffffh ;no intercepts below here
wboot equ 0000h
bdos equ 0005h
bdosl equ bdos+1
dbuff equ 0080h
;
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
modnum equ 14 ;module number position
pbuff equ 9 ;print buffer
rbuff equ 10 ;read buffer
openf equ 15 ;open file
closef equ 16 ;close file
delf equ 19 ;delete file
dreadf equ 20 ;disk read
dmaf equ 26 ;set dma function
;
;
org 0000h+bias
; initialize jmps to include xsub module
jmp start
ds 3
trapjmp:
jmp trap
db 'xsub'
start:
lhld wboot+1
shld savboot
lxi h,wstart
shld wboot+1
lhld bdosl
shld rbdos+1 ;real bdos entry
lxi h,trapjmp ;address to fill
shld bdosl ;jmp @0005 leads to trap
pop h ;ccp return address
shld ccpret
pchl ;back to ccp
;
rbdos: jmp 0000h ;filled in at initialization
savboot:
ds 2 ;warm boot saved and restored at end
;of submit file
;
wstart:
lxi sp,stack
mvi c,pbuff ;print message
lxi d,actmsg
call rbdos
lxi h,dbuff ;restore default buffer
shld udma
call rsetdma
lxi h,trapjmp
shld bdosl ;fixup low jump address
lhld ccpret ;back to ccp
pchl
actmsg: db cr,lf,'(xsub active)$'
;
trap: ;arrive here at each bdos call
pop h ;return address
push h ;back to stack
mov a,h ;high address
cpi base shr 8
jnc rbdos ;skip calls on bdos above here
mov a,c ;function number
cpi rbuff
jz rnbuff ;read next buffer
cpi dmaf ;set dma address?
jnz rbdos ;skip if not
xchg ;dma to hl
shld udma ;save it
xchg
jmp rbdos
;
setdma:
mvi c,dmaf
lxi d,combuf
call rbdos
ret
;
rsetdma:
mvi c,dmaf
lhld udma
xchg
call rbdos
ret
;
fbdos:
push b
push d
call setdma
pop d
pop b
call rbdos
push psw
call rsetdma
pop psw
ret
;
cksub: ;check for sub file present
mvi c,openf
lxi d,subfcb
call fbdos ;submit file present?
inr a ;00 if not present
ret
;
rnbuff:
push d ;command address
call cksub ;sub file present?
pop d
mvi c,rbuff
jz restor ;no sub file
;
push d
lda subrc ;length of file
ora a ;zero?
jz rbdos ;skip if so
dcr a ;length - 1
sta subcr ;next to read
mvi c,dreadf
lxi d,subfcb
call fbdos ;read record
; now print the buffer with cr,lf
lxi h,combuf
mov e,m ;length
mvi d,0 ;high order 00
dad d ;to last character position
inx h
mvi m,cr
inx h
mvi m,lf
inx h
mvi m,'$'
mvi c,pbuff
lxi d,combuf+1
call rbdos ;to print it
pop h ;.max length
lxi d,combuf
ldax d ;how long?
cmp m ;cy if ok
jc movlin
mov a,m ;max length
stax d ;truncate length
movlin:
mov c,a ;length to c
inr c ;+1
inx h ;to length of line
rdloop:
ldax d ;next char
mov m,a
inx h
inx d
dcr c
jnz rdloop ;loop til copied
mvi c,closef
lxi d,subfcb
lxi h,modnum
dad d ;hl=fcb(modnum)
mvi m,0 ;=0 so acts as if written
lda subcr ;length of file
dcr a ;incremented by read op
sta subrc ;decrease file length
ora a ;at zero?
jnz fileop
mvi c,delf ;delete if at end
fileop: call fbdos
ret
restor:
lhld savboot
shld wboot+1
jmp rbdos
;
subfcb:
db 1 ;a:
db '$$$ '
db 'SUB'
db 0,0,0
subrc:
ds 1
ds 16 ;map
subcr: ds 1
;
combuf: ds 131
udma: dw dbuff
ccpret: ds 2 ;ccp return address
ds 32 ;16 level stack
stack:
end

Some files were not shown because too many files have changed in this diff Show More