TITLE 'SYSGEN - SYSTEM GENERATION PROGRAM 8/79' ; SYSTEM GENERATION PROGRAM, VERSION FOR ROMWBW VERS EQU 20 ; X.X ; ; COPYRIGHT (C) DIGITAL RESEARCH ; 1976, 1977, 1978, 1979 ; NDISKS EQU 16 ; NUMBER OF DISK DRIVES SECSIZ EQU 128 ; SIZE OF EACH SECTOR LOG2SEC EQU 7 ; LOG 2 SECSIZ ; FCB EQU 05CH ; 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 5 ; DOS ENTRY POINT BOOT EQU 0 ; JMP TO 'BOOT' TO REBOOT SYSTEM CONI EQU 1 ; CONSOLE INPUT FUNCTION CONO EQU 2 ; CONSOLE OUTPUT FUNCTION OPENF EQU 15 ; DISK OPEN FUNCTION DREADF EQU 20 ; DISK READ FUNCTION ; CR EQU 0DH ; CARRIAGE RETURN LF EQU 0AH ; LINE FEED STKSIZE EQU 16 ; SIZE OF LOCAL STACK ; WBOOT EQU 1 ; ADDRESS OF WARM BOOT (OTHER PATCH ENTRY ; ORG TPA ; TRANSIENT PROGRAM AREA JP START DB 'COPYRIGHT (C) 1978, DIGITAL RESEARCH ' ; ; UTILITY SUBROUTINES ; GETCHAR: ; READ CONSOLE CHARACTER TO REGISTER A LD C,CONI CALL BDOS ; CONVERT TO UPPER CASE BEFORE RETURN CP 'A' OR 20H RET C ; RETURN IF BELOW LOWER CASE A CP ('Z' OR 20H) + 1 RET NC ; RETURN IF ABOVE LOWER CASE Z AND 5FH RET ; PUTCHAR: ; WRITE CHARACTER FROM A TO CONSOLE LD E,A LD C,CONO CALL BDOS RET ; CRLF: ; SEND CARRIAGE RETURN, LINE FEED LD A,CR CALL PUTCHAR LD A,LF CALL PUTCHAR RET ; CRMSG: ; PRINT MESSAGE ADDRESSED BY H,L TIL ZERO ; WITH LEADING CRLF PUSH HL CALL CRLF POP HL ; DROP THRU TO OUTMSG0 OUTMSG: LD A,(HL) OR A RET Z ; MESSAGE NOT YET COMPLETED PUSH HL CALL PUTCHAR POP HL INC HL JP OUTMSG ; DREAD: ; DISK READ FUNCTION VIA BDOS LD C,DREADF JP BDOS ; OPEN: ; FILE OPEN FUNCTION VIA BDOS LD C,OPENF JP BDOS ; ; READ IMAGE DIRECTLY FROM DISK SYSTEM TRACKS USING CBIOS ; DISK NUMBER MUST BE IN (ACTDSK) ; RDDSK: ; FORCE RETURN TO GO THROUGH DISK RESET LD HL,RESDSK ; LOAD ADDRESS OF RESET DISK ROUTINE PUSH HL ; AND PUT IT ON THE STACK ; SET DRIVE FOR SUBSEQUENT READS CALL SETDSK ; SETUP DISK SPECIFIED IN A RET NZ ; ABORT ON ERROR ; SET FUNCTION TO READ LD HL,(CBFTBL) ; GET ADDRESS OF CBIOS FUNCTION TABLE LD A,027H ; $27 IS CBIOS READ ENTRY OFFSET CALL ADDHL ; SET HL TO RESULTANT ENTRY POINT LD (ACTFNC),HL ; SAVE IT ; READ THE HEADER LD A,12 ; START WITH 1536 BYTE HEADER (12 RECORDS) LD (RECCNT),A ; INITIALIZE RECORD COUNTER CALL RWDSK ; READ THE HEADER RET NZ ; ABORT ON ERROR ; CHECK HEADER AND GET IMAGE SIZE CALL CHKHDR ; CHECK INTEGRITY, HL = IMAGE SIZE ON RETURN RET NZ ; ABORT ON ERROR ; CONVERT IMAGE SIZE TO COUNT OF 128-BYTE RECORDS LD B,7 ; RIGHT SHIFT 7 BITS TO GET 128 BYTE RECORD COUNT RDDSK1: SRL H ; SHIFT RIGHT MSB RR L ; SHIFT LSB W/ CARRY FROM MSB DJNZ RDDSK1 ; LOOP TILL DONE ; SET THE NUMBER OF RECORDS PENDING TO READ LD A,L ; RECORD COUNT TO A LD (RECCNT),A ; SET REMAINING RECORDS TO READ ; SAVE THE TOTAL IMAGE SIZE (INCLUDING HEADER) FOR LATER ADD A,12 ; ADD THE HEADER RECORDS BACK LD (IMGSIZ),A ; AND SAVE THE TOTAL IMAGE SIZE (IN RECORDS) ; READ THE REMAINING SYSTEM IMAGE RECORDS CALL RWDSK ; FINISH UP RET NZ ; ABORT ON ERROR ; PERFORM BDOS DISK RESET (CRITICAL SINCE WE MUCKED WITH CBIOS) LD C,0DH ; BDOS RESET DISK CALL BDOS ; DO IT ; RETURN XOR A ; SIGNAL SUCCESS RET ; DONE ; ; WRITE IMAGE DIRECTLY TO DISK SYSTEM TRACKS USING CBIOS ; DISK NUMBER MUST BE IN (ACTDSK) ; WRDSK: ; FORCE RETURN TO GO THROUGH DISK RESET LD HL,RESDSK ; LOAD ADDRESS OF RESET DISK ROUTINE PUSH HL ; AND PUT IT ON THE STACK ; SET DRIVE FOR SUBSEQUENT WRITES CALL SETDSK ; SETUP DISK SPECIFIED IN A RET NZ ; ABORT ON ERROR ; SET FUNCTION TO WRITE LD HL,(CBFTBL) ; GET ADDRESS OF CBIOS FUNCTION TABLE LD A,02AH ; $2A IS CBIOS WRITE ENTRY OFFSET CALL ADDHL ; SET HL TO RESULTANT ENTRY POINT LD (ACTFNC),HL ; SAVE IT ; SETUP THE RECORD COUNT TO WRITE LD A,(IMGSIZ) ; GET PREVIOUSLY RECORDED IMAGE SIZE LD (RECCNT),A ; SAVE IT AS PENDING RECORD COUNT ; WRITE THE IMAGE CALL RWDSK ; WRITE THE IMAGE RET NZ ; ABORT ON ERROR ; RETURN XOR A ; SIGNAL SUCCESS RET ; DONE ; ; PERFORM BDOS DISK RESET ; REQUIRED AFTER MAKING DIRECT CBIOS DISK CALLS ; RESDSK: ; PERFORM BDOS DISK RESET PUSH AF ; PRESERVE STATUS LD C,0DH ; BDOS RESET DISK CALL BDOS ; DO IT POP AF ; RESTORE STATUS RET ; ; SETUP FOR CBIOS DISK ACCESS ; SETDSK: ; SELECT DISK LD A,(ACTDSK) ; GET ACTIVE DISK LD C,A ; MOVE TO C LD E,0 ; TREAT AS FIRST SELECT CALL CBIOS ; INVOKE CBIOS WITH... DB 01BH ; SELDSK ENTRY OFFSET ; CHECK RETURN (SETS HL TO DPH ADDRESS) LD A,H OR L JP Z,ERRSEL ; HL == 0 IS SELECT ERROR ; SET HL TO DPB ADDRESS LD DE,10 ; DPB ADDRESS IS 10 BYTES INTO DPH ADD HL,DE ; HL := ADDRESS OF DPB POINTER LD A,(HL) ; DEREFERENCE... INC HL LD H,(HL) LD L,A ; HL := ADDRESS OF DPB ; EXTRACT SECTORS PER TRACK FROM FIRST WORD OF DPB LD C,(HL) INC HL LD B,(HL) ; BC := SECTORS PER TRACK LD (ACTSPT),BC ; SAVE IT ; ENSURE THERE ARE SYSTEM TRACKS (VERIFY THAT OFFSET FIELD IN DPB IS NOT ZERO) LD DE,12 ; OFFSET FIELD IS 12 BYTES INTO DPB ADD HL,DE ; POINT TO OFFSET FIELD IN DPB LD A,(HL) ; LOAD FIRST BYTE IN A INC HL ; POINT TO SECOND BYTE OR (HL) ; OR WITH FIRST BYTE JP Z,ERRSYS ; IF ZERO, ABORT (NO SYSTEM TRACKS) ; INITIALIZE FOR I/O LD HL,0 LD (ACTTRK),HL ; ACTIVE TRACK := 0 LD (ACTSEC),HL ; ACTIVE SECTOR := 0 LD HL,LOADP LD (BUFPTR),HL ; RESET BUFFER POINTER ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ; READ OR WRITE (RECCNT) SECTORS TO/FROM DISK VIA CBIOS ; RWDSK: ; SETUP TO READ/WRITE A SECTOR LD BC,(ACTTRK) ; GET ACTIVE TRACK CALL CBIOS ; INVOKE CBIOS WITH... DB 01EH ; SETTRK ENTRY OFFSET LD BC,(ACTSEC) ; GET ACTIVE SECTOR CALL CBIOS ; INVOKE CBIOS WITH... DB 021H ; SETSEC ENTRY OFFSET LD BC,(BUFPTR) ; GET ACTIVE BUFFER POINTER CALL CBIOS ; INVOKE CBIOS WITH... DB 024H ; SETDMA ENTRY OFFSET ; READ/WRITE SECTOR LD A,(RECCNT) ; GET THE PENDING RECORD COUNT DEC A ; LAST RECORD? LD C,2 ; ALLOW CACHED WRITES BY DEFAULT JR NZ,RWDSK1 ; NOT LAST RECORD, CONTINUE LD C,1 ; LAST RECORD, NO CACHING PLEASE RWDSK1: LD HL,(ACTFNC) ; LOAD THE CBIOS FUNCTION VECTOR CALL JPHL ; INDIRECT CALL (READ OR WRITE) OR A ; SET FLAGS ON RETURN CODE JP NZ,ERRIO ; IF NOT ZERO, ERROR ABORT ; ADJUST BUFFER POINTER LD HL,(BUFPTR) ; GET BUFFER POINTER LD DE,128 ; RECORD LENGTH IS 128 BYTES ADD HL,DE ; ADJUST BUFFER PTR FOR NEXT RECORD LD (BUFPTR),HL ; SAVE IT ; NEXT SECTOR LD HL,(ACTSEC) ; CURRENT SECTOR INC HL ; INCREMENT SECTOR LD (ACTSEC),HL ; SAVE IT ; CHECK FOR END OF TRACK LD DE,(ACTSPT) ; GET CURRENT SECTORS PER TRACK OR A ; CLEAR CF SBC HL,DE ; CURRENT TRACK == SECTORS PER TRACK? JR NZ,RWDSK2 ; NO, SKIP TRACK CHANGE ; NEXT TRACK LD HL,0 LD (ACTSEC),HL ; CURRENT SECTOR := 0 LD HL,ACTTRK ; POINT TO TRACK VARIABLE INC (HL) ; INCREMENT TRACK ; CHECK PENDING RECORD COUNT AND LOOP OR RETURN RWDSK2: LD HL,RECCNT DEC (HL) ; DECREMENT PENDING RECORD COUNT RET Z ; IF ZERO, DONE, RETURN WITH Z SET JR RWDSK ; OTHERWISE, LOOP ; JPHL: JP (HL) ; INDIRECT JUMP ; ; VERIFY SYSTEM IMAGE HEADER IN BUF BY CHECKING THE EXPECTED SIGNATURE. ; COMPUTE AND RETURN IMAGE SIZE (BASED ON HEADER VALUES) IN HL. ; NZ SET IF SIGNATURE ERROR. ; CHKHDR: ; CHECK SIGNATURE LD HL,(LOADP+580H) ; GET SIGNATURE LD DE,0A55AH ; SIGNATURE VALUE OR A ; CLEAR CF SBC HL,DE ; COMPARE JP NZ,ERRSIG ; INVALID SIGNATURE ; COMPUTE THE IMAGE SIZE (DOES NOT INCLUDE SIZE OF HEADER) LD HL,(LOADP+5FCH) ; GET CPM_END LD DE,(LOADP+5FAH) ; GET CPM_LOC OR A ; CLEAR CF SBC HL,DE ; IMAGE SIZE := CPM_END - CPM_LOC XOR A ; SIGNAL SUCCESS RET ; DONE ; ; INVOKE CBIOS FUNCTION ; THE CBIOS FUNCTION OFFSET MUST BE STORED IN THE BYTE ; FOLLOWING THE CALL INSTRUCTION. EX: ; CALL CBIOS ; DB 0CH ; OFFSET OF CONOUT CBIOS FUNCTION ; CBIOS: EX (SP),HL LD A,(HL) ; GET THE FUNCTION OFFSET INC HL ; POINT PAST VALUE FOLLOWING CALL INSTRUCTION EX (SP),HL ; PUT ADDRESS BACK AT TOP OF STACK AND RECOVER HL LD HL,(CBFTBL) ; ADDRESS OF CBIOS FUNCTION TABLE TO HL CALL ADDHL ; DETERMINE SPECIFIC FUNCTION ADDRESS JP (HL) ; INVOKE CBIOS ; ; ADD THE VALUE IN A TO HL (HL := HL + A) ; ADDHL: ADD A,L ; A := A + L LD L,A ; PUT RESULT BACK IN L RET NC ; IF NO CARRY, WE ARE DONE INC H ; IF CARRY, INCREMENT H RET ; AND RETURN ; ; START OF PROGRAM ; START: LD SP,STACK ; SET LOCAL STACK POINTER LD HL,SIGNON CALL CRMSG ; LOCATE CBIOS FUNCTION TABLE ADDRESS LD HL,(BOOT+1) ; LOAD ADDRESS OF CP/M RESTART VECTOR LD DE,-3 ; ADJUSTMENT FOR START OF TABLE ADD HL,DE ; HL NOW HAS START OF TABLE LD (CBFTBL),HL ; SAVE IT ; CHECK FOR DEFAULT FILE LOAD INSTEAD OF GET LD A,(FCB+1); BLANK IF NO FILE CP ' ' JP Z,GETSYS ; SKIP TO GET SYSTEM MESSAGE IF BLANK LD DE,FCB ; TRY TO OPEN IT CALL OPEN ; INC A ; 255 BECOMES 00 JP NZ,RDOK ; OK TO READ IF NOT 255 ; FILE NOT PRESENT, ERROR AND REBOOT LD HL,NOFILE CALL CRMSG JP REBOOT ; ; FILE PRESENT - READ TO LOAD POINT ; RDOK: XOR A LD (FCBCR),A; CURRENT RECORD = 0 ; PRE-READ AREA FROM TPA TO LOADP LD C,(LOADP-TPA)/SECSIZ PRERD: ; PRE-READ FILE PUSH BC ; SAVE COUNT LD DE,FCB ; INPUT FILE CONTROL COUNT CALL DREAD ; ASSUME SET TO DEFAULT BUFFER POP BC ; RESTORE COUNT OR A JP NZ,BADRD ; CANNOT ENCOUNTER END-OF FILE DEC C ; COUNT DOWN JP NZ,PRERD ; FOR ANOTHER SECTOR ; ; SECTORS SKIPPED AT BEGINNING OF FILE ; LD HL,LOADP RDINP: PUSH HL LD B,H LD C,L ; READY FOR DMA CALL CBIOS ; INVOKE CBIOS WITH... DB 024H ; SETDMA ENTRY OFFSET LD DE,FCB ; READY FOR READ CALL DREAD ; POP HL ; RECALL DMA ADDRESS OR A ; 00 IF READ OK JP NZ,PUTSYS ; ASSUME EOF IF NOT. ; MORE TO READ, CONTINUE LD DE,SECSIZ ADD HL,DE ; HL IS NEW LOAD ADDRESS JP RDINP ; BADRD: ; EOF ENCOUNTERED IN INPUT FILE LD HL,BADFILE CALL CRMSG JP REBOOT ; GETSYS: CALL CRLF LD HL,ASKGET ; GET SYSTEM? CALL CRMSG CALL GETCHAR CP CR JP Z,PUTSYS ; SKIP IF CR ONLY ; SUB 'A' ; NORMALIZE DRIVE NUMBER CP NDISKS ; VALID DRIVE? JP C,GETC ; SKIP TO GETC IF SO ; INVALID DRIVE NUMBER CALL BADDISK JP GETSYS ; TO TRY AGAIN ; GETC: ; SELECT DISK GIVEN BY REGISTER A ADD A,'A' LD (GDISK),A; TO SET MESSAGE SUB 'A' LD (ACTDSK),A ; SAVE ACTIVE DISK NO ; ; GETSYS, SET RW TO READ AND GET THE SYSTEM CALL CRLF LD HL,GETMSG CALL OUTMSG CALL GETCHAR CP CR JP NZ,REBOOT CALL CRLF CALL RDDSK JP NZ,GETSYS LD HL,DONE CALL OUTMSG ; ; PUT SYSTEM ; PUTSYS: CALL CRLF LD HL,ASKPUT CALL CRMSG CALL GETCHAR CP CR JP Z,REBOOT SUB 'A' CP NDISKS JP C,PUTC ; INVALID DRIVE NAME CALL BADDISK JP PUTSYS ; TO TRY AGAIN ; PUTC: ; SET DISK FROM REGISTER C ADD A,'A' LD (PDISK),A ; MESSAGE SET SUB 'A' LD (ACTDSK),A ; SAVE ACTIVE DISK NO ; PUT SYSTEM LD HL,PUTMSG CALL CRMSG CALL GETCHAR CP CR JP NZ,REBOOT CALL CRLF CALL WRDSK JP NZ,PUTSYS LD HL,DONE CALL OUTMSG JP PUTSYS ; FOR ANOTHER PUT OPERATION ; REBOOT: CALL CRLF JP BOOT ; ERRSEL: LD HL,SELMSG JP ERR ; ERRSYS: LD HL,SYSMSG JP ERR ; ERRIO: LD HL,IOMSG JP ERR ; ERRSIG: LD HL,SIGMSG JP ERR ; ERR: CALL OUTMSG OR A,0FFH RET ; BADDISK:;BAD DISK NAME LD HL,QDISK CALL CRMSG RET ; ; DATA AREAS ; MESSAGES ; SIGNON: DB 'ROMWBW 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-P)',0 NOFILE: DB 'NO SOURCE FILE ON DISK',0 BADFILE: DB 'SOURCE FILE INCOMPLETE',0 SELMSG: DB 'DISK SELECTION ERROR',0 SYSMSG: DB 'NON-SYSTEM DISK ERROR',0 IOMSG: DB 'FATAL DISK I/O ERROR',0 SIGMSG: DB 'INVALID SYSTEM IMAGE (BAD SIGNATURE)',0 ; ; VARIABLES ; CBFTBL DW 0 ; ADDRESS OF CBIOS FUNCTION TABLE IMGSIZ DB 0 ; IMAGE SIZE (COUNT OF 128 BYTE RECORDS) ; RWFUN DB 0 ; ACTIVE READ/WRITE FUNCTION RECCNT DB 0 ; ACTIVE REMAINING RECORDS TO READ/WRITE BUFPTR DW 0 ; ACTIVE POINTER INTO BUFFER ; ACTDSK DB 0 ; ACTIVE DISK NO ACTTRK DW 0 ; ACTIVE TRACK ACTSEC DW 0 ; ACTIVE SECTOR ACTSPT DW 0 ; ACTIVE SECTORS PER TRACK ACTFNC DW 0 ; ACTIVE FUNCTION (READ OR WRITE) DS STKSIZE*2 STACK: ; END