;
;
; 'PASCAL' FIRST READS IN AND SCANS THE DIRECTORY FOR THE 8080/
; Z80 INTERPRETER (SYSTEM.MICRO). THEN THE INTERPRETER IS
; LOADED INTO MEMORY AND STARTED AT THE SYSTEM.PASCAL BOOT VECTOR.
;
; THIS PROGRAM PROVIDED COURTESY OF NORTHWEST MICROCOMPUTER SYSTEMS, INC.
;MODIFIED
; 10/11/78 BY WINK SAVILLE TO READ ANY SIZE INTERPETER
;
;
;
BOOT EQU 0H ;LOCATION OF CP/M BOOT VECTOR
BDOS EQU 5H ;CP/M ENTRY VECTOR
TPA EQU 100H ;START OF USER AREA
;
RDCON EQU 1
WRBUF EQU 9
;
NBLOCKS EQU 32 ;MAXIMUM # OF BLOCKS FOR THE
;INTERPETER USED TO CALCULATE
;START
START EQU TPA+NBLOCKS*512 ;LOCATION OF THIS PROGRAM
INTERP$BASE EQU TPA ;FIRST LOC USED BY THE INTERPRETER
PBEGIN EQU INTERP$BASE+100H;ENTRY TO THE PASCAL BOOTER
FIRSTSP EQU INTERP$BASE+103H;PASCAL INITIAL STACK POINTER
DENTSZ EQU 1AH ;DIR ENTRY SIZE IN BYTES
DTITLE EQU 06H ;OFFSET TO ENTRY TITLE
DIRTOP EQU PBEGIN ;TOP OF TEMP RAM DISK DIRECTORY
;
CR EQU 0DH
LF EQU 0AH
EOM EQU '$'
;
;
;
ORG TPA
;
;
JMP START
;
;
;
ORG START
;
;
LXI SP,100H
MAIN: ;LET'S BOOT SYSTEM.MICRO
CALL INIT$IO ;RESET I/O SYSTEM
;
CALL REQUEST$DISK ;GET PASCAL DISK ON DRIVE A
MVI C,0 ; THEN SELECT THE DRIVE
CALL SELDSK
;
LXI B,DIRTOP ;READ THE DIRECTORY INTO DIRTOP
CALL READ$DIR
;
LXI H,DIRTOP ;SET THE DIRECTORY ENTRY POINTER
LXI D,DENTSZ ; TO FIRST ENTRY AFTER THE VOLUME NAME
DAD D
SHLD DENTP
;
CALL FIND$INTERP ;THEN FIND THE INTERPRETER
CALL SAY$LOADING ;GOT IT SAY WHAT WE'RE UP TO
CALL READ$INTERP ; AND READ IT IN
;
LHLD BOOT+1 ;NOTE: LOC 2 MUST HAVE CURRENT BIOS PAGE
MVI L,0 ; FOR PROPER SYSTEM OPERATION
SHLD FIRSTSP
;
MVI C,WRBUF ; REBOOT CPM
LXI D,REBOOTMSG
CALL BDOS
MVI C,RDCON ; WAIT FOR CR
CALL BDOS
JP BOOT
;
;
;
INIT$IO: ;INITIALIZE SYSTEM
RET ;THAT'S IT
;
;
REQUEST$DISK: ;ASK FOR PASCAL
MVI C,WRBUF
LXI D,DSKMSG
CALL BDOS
RD$LOOP: ;THEN WAIT FOR A CR
MVI C,RDCON
CALL BDOS
CPI CR
JNZ RD$LOOP
RET
;
DSKMSG: DB CR,LF,'INSERT PASAL DISK IN DRIVE A, THEN TYPE RETURN',EOM
;
;
READ$DIR: ;READ DIRECTORY'S 4 BLOCKS TO BUFFER
;BUFFER ADDRESS IS ALREADY IN BC-REG
MVI E,4 ;DIR IS 4 BLOCKS LONG
LXI H,2 ;AND STARTS AT BLOCK #2
CALL SYSRD ;GO GET IT
RET
;
;
FIND$INTERP: ;FIND 'SYSTEM.MICRO'
MVI C,77 ;STOP AFTER THE 77'TH ENTRY
LHLD DENTP ;GET STARTING ENTRY
FI$SCH$LP:
LXI D,DTITLE ;ADVANCE TO TITLE STRING
DAD D
LXI D,SYSTLE ;SET DE-REG TO COMPARISON STRING
MVI B,LENGTH+1 ;COMPARISON LENGTH
FI$CMP$LP: ;START COMPARING
LDAX D
CMP M
JNZ FI$CONT ;IT'S NOT THIS ONE
INX D ;HEY, WE'VE STILL GOT A CHANCE
INX H
DCR B ;IS THIS THE END OF THE STRING
JNZ FI$CMP$LP
JMP FI$FOUND ;I THINK WE FOUND IT
FI$CONT:
LHLD DENTP ;ON TO THE NEXT ENTRY
LXI D,DENTSZ
DAD D
SHLD DENTP
DCR C ;WAIT, IS THERE ANY DIR LEFT?
JNZ FI$SCH$LP
;
MVI C,WRBUF ;NO INTERP THERE
LXI D,NOTFNDMSG
CALL BDOS
;
;
REBOOT:
MVI C,WRBUF ;TRY TO REBOOT CP/M
LXI D,REBOOTMSG
CALL BDOS
MVI C,RDCON
CALL BDOS ;WAIT FOR ANY CHAR
JMP BOOT
;
FI$FOUND: ;WE'VE GOT IT
RET
;
NOTFNDMSG: DB CR,LF,'INTERPRETER NOT FOUND',CR,LF,EOM
REBOOTMSG: DB CR,LF,'REBOOTING CP/M',EOM
;
LENGTH EQU 12 ;TITLE LENGTH
SYSTLE DB LENGTH,'SYSTEM.MICRO'
;
;
SAY$LOADING: ;WE'RE GOING TO LOAD THE INTERPRETER
MVI C,WRBUF
LXI D,LOADINGMSG
CALL BDOS
RET
;
LOADINGMSG: DB CR,LF,'LOADING...',EOM
;
;
READ$INTERP: ;PUT INTERP IN ITS PLACE
LHLD DENTP ;GET STARTING BLOCK
MOV E,M ; INTO HL-REG
INX H
MOV D,M
;
;COMPUTE THE LENGTH OF THE INTERPETER
PUSH D ;SAVE FIRST BLOCK ON STACK
;TAKE 2'S COMPLIMENT OF FIRST BLOCK
MOV A,E
CMA
MOV E,A
MOV A,D
CMA
MOV D,A
INX D ;DE=2'S COMP OF FIRST BLOCK
PUSH D ;SAVE ON THE STACK
;GET NEXT AVAIL BLOCK
INX H
MOV E,M
INX H
MOV D,M
XCHG
;
POP D ;HL=NXT BLOCK,DE=-(FIRST BLOCK)
;SO HL+DE=LENGTH OF SYSTEM.MICRO
DAD D ;HL=LENGTH
XCHG ;DE=LENGTH
POP H ;HL=FIRST BLOCK , DE=LENGTH
;
;CHECK THAT WE WON'T OVERWRITE OURSELVES
LXI B,NBLOCKS
MOV A,C
SUB E
MOV A,B
SBB D
JNC OK ;JIF OK
;ELSE TELL OPERATOR AND REBOOT
LXI D,INTERP$TO$LARGE
MVI C,WRBUF
CALL BDOS ;PRINT THE MESSAGE
JMP REBOOT ;REBOOT CPM
INTERP$TO$LARGE:
DB CR,LF,'INTERPETER TO LARGE IT WILL OVER WRITE'
DB CR,LF,'THIS PROGRAM. REASSEMBLE THIS PROGRAM'
DB CR,LF,'WITH A HIGHER STARTING ADDRESS',CR,LF,EOM
;
OK:
LXI B,INTERP$BASE ;AND SET IT LOAD POINT
CALL SYSRD ;THEN READ IT
RET
;
;
SYSRD:
PUSH D ;SAVE BLOCK COUNT
PUSH H ;AND BLOCK NUMBER
CALL READ$RX ;BUFFER IS ADVANCED BY 512 BYTES
POP H
POP D
INX H ;ADVANCE TO NEXT BLOCK
DCR E ;BUT, BEFORE WE GO ON
JNZ SYSRD ; SEE IF WE'RE DONE
RET
;
;
READ$RX: ;READ A PASCAL BLOCK
DAD H ;THERE ARE 4 IBM SECTORS TO A PASCAL BLOCK
DAD H ; SO MULT LOGICAL BLOCK BY 4 TO GET 1ST SEC
MVI E,4
RR$LP: ;THIS GETS CONFUSING
PUSH B ;SET BUFFER ADDRESS
PUSH D
PUSH H
CALL SETDMA
POP H ;NOW COMPUTE PHYSICAL TRACK-SECTOR
PUSH H
CALL MAP ;MAP CONVERTS LOGICAL SECTOR IN HL-REG
MOV C,H ; INTO PHYSICAL TRACK, H-REG, SECTOR, L-REG
PUSH H
CALL SETTRK
POP H
MOV C,L
CALL SETSEC
CALL READ ;AND READ THE DATA
POP H
POP D
POP B
PUSH H ;ADVANCE THE BUFFER ADDRESS
LXI H,128
DAD B
MOV B,H
MOV C,L
POP H
INX H ;ADVANCE BLOCK COUNT
DCR E ;THEN SEE IF WE CONTINUE
JNZ RR$LP
RET ;LEAVE, WHEN DONE
;
;
DENTP DS 2
;
;
HOME: ;HOME SELECTED DISK TO TRACK 00
LHLD BOOT+1
MVI L,18H
PCHL
;
SELDSK: ;SELECT DISK (C-REG)
LHLD BOOT+1
MVI L,1BH
PCHL
;
SETTRK: ;SET TRACK (C-REG)
LHLD BOOT+1
MVI L,1EH
PCHL
;
SETSEC: ;SET SECTOR (C-REG)
LHLD BOOT+1
MVI L,21H
PCHL
;
SETDMA: ;SET DATA TRANSFER ADDRESS (BC-REG)
LHLD BOOT+1
MVI L,24H
PCHL
;
READ: ;READ A SECTOR TO THE DATA AREA
LHLD BOOT+1
MVI L,27H
PCHL
;
;
MAP: ;TURN LSN INTO IBM TRACK-SECTOR
;
; NOTE: TRACK 00 IS NOT USED SO BLOCK 0
; IS AT TRACK 01 SECTOR 1
;
; ON ENTRY: HL-REG HAS LOGICAL SECTOR NO.
; ON EXIT: H-REG HAS PHYSICAL TRACK
; L-REG HAS PHYSICAL SECTOR
;
;
PUSH B
PUSH D
;
CALL DIV26
MOV A,L
ADD A
MOV B,A
MVI A,12
CMP L
JNC MAPC
INR B
MAPC:
MOV C,E
XRA A
MOV D,A
MOV H,A
MOV L,B
MVI A,6
MAP$LOOP:
DAD D
DCR A
JNZ MAP$LOOP
PUSH B
CALL DIV26
POP B
INR L
MOV H,C
INR H
POP D
POP B
RET
;
;
DIV26:
LXI B,-26
MVI E,0FFH
DIVL:
INR E
DAD B
MOV A,H
ORA A
JP DIVL
LXI B,26
DAD B
RET
;
;
END START