TITLE 'NSGEN V3.4 - WRITE CP/M 2.2 TO NORTH STAR DISK' ; PAGE 44 ; ; These routines copyright (c) 1980, 1981, 1982 by Steve Bogolub, ; 2338 S. Scoville Ave., Berwyn, IL 60402. This software may be ; used freely for non-commercial purposes only, and may not be sold. ; ;************************************************************ ; ; THIS PROGRAM IS SET UP TO PROVIDE THE FUNCTIONS ; OF THE DIGITAL RESEARCH STANDARD CP/M PROGRAM ; 'SYSGEN', BUT FOR A NORTH STAR DOUBLE DENSITY ; VERSION OF CP/M. SINCE THE NORTH STAR HAS 10 ; SECTORS PER TRACK, WITH 512 BYTES PER SECTOR ; USING DOUBLE DENSITY, THE STANDARD SYSGEN PROGRAM ; IS WORTHLESS. USING THIS VERSION, THE CCP AND ; BDOS ARE WRITTEN OUT TO CONSECTIVE SECTORS OF ; TRACK ONE, 0-9 INCLUSIVE. ELEVEN 512-BYTE ; SECTORS ARE REQUIRED, SO THE LAST ONE IS ; WRITTEN OUT TO TRACK ZERO, SECTOR THREE. THE ; CCP/BDOS CODE IS ASSUMED TO BE LOADED INTO ; CONTIGUOUS MEMORY LOCATIONS STARTING AT 0980H. ; THE CONTROL CODE FOR THE JADE DOUBLE D FLOPPY ; DISK CONTROLLER IS EXPECTED AT ADDRESS 1F80H, ; EXTENDING FOR 1024 BYTES. THIS CODE IS WRITTEN ; OUT TO TRACK ZERO, SECTORS ONE AND TWO. THE ; NORTH STAR BIOS IS ASSUMED TO RESIDE IN MEMORY ; FROM 2380H TO 2F7FH INCLUSIVE. THE LAST 512 BYTES ; OF BIOS (2D80H - 2F7FH) PERFORM THE FUNCTION ; OF DISK BOOT, AND ARE WRITTEN OUT TO TRACK ZERO, ; SECTOR FOUR, WHERE THE NORTH STAR PROM BOOT ; EXPECTS TO FIND THE SYSTEM BOOT CODE. THE REST ; OF BIOS (1ST 3K, 2380H - 2D7FH) IS WRITTEN OUT ; TO TRACK ZERO, SECTORS 5-9 INCLUSIVE. TRACK ; ZERO, SECTOR ZERO IS RESERVED FOR A LIFEBOAT- ; COMPATIBLE ID AND FUTURE ADDITIONS. ; ; IN ORDER TO FIND THE RIGHT SECTORS, WE ASSUME ; THAT THERE ARE 40 LOGICAL SECTORS PER TRACK, ; NUMBERED 1-40 INCLUSIVE. IN ORDER TO WRITE AT ; HIGH SPEED, WE ASSUME THAT THERE ARE 4 LOGICAL ; SECTORS PER PHYSICAL SECTOR, AND LOAD THE C-REG ; WITH THE APPROPRIATE DEBLOCKING FLAG BEFORE ; CALLING BIOS TO WRITE A SECTOR. IN ADDITION, ; WE READ OR WRITE EVERY 3RD NORTH STAR SECTOR. ; ORG 0100H ;ORG TO TPA ; ; BDOS EQUATES ; BDOS EQU 0005H ;BDOS ENTRY ADDRESS CONIN EQU 1 ;CONSOLE INPUT CONOUT EQU 2 ;CONSOLE OUTPUT ; CR EQU 0DH ;ASCII CR LF EQU 0AH ;ASCII LF ; ; BIOS OFFSET EQUATES ; WARMB EQU 0000H ;BIOS WARM BOOT VECTOR BIOS EQU WARMB+1 ;PTR TO BIOS VECTOR TABLE ; SELDSK EQU 1BH-3 ;SELECT DISK DRIVE SETTRK EQU SELDSK+3 ;SET TRACK NUMBER SETSEC EQU SETTRK+3 ;SET SECTOR NUMBER SETDMA EQU SETSEC+3 ;SET DMA ADDRESS READ EQU SETDMA+3 ;READ SELECTED SECTOR WRITE EQU READ+3 ;WRITE SELECTED SECTOR ; NDRVS EQU 2 ;# OF DRIVES WE CAN USE ;(ONLY A: AND B: ARE N*) ; ; CP/M IMAGE ADDRESS (WHERE CCP LEFT BY MOVCPM) ; CPMIA EQU 0980H ; ; PROGRAM START. SET UP STACK PTR AND GET SOURCE DISK. ; NSGEN: LXI SP,NSGEN ;SET STACK PTR LXI H,HELLO ;PRINT OUT SIGNON CALL MSGOT ; GETSRC: LXI H,SRCMSG ;ASK FOR SOURCE DISK LETTER CALL MSGOT CALL CHARIN ;GET SINGLE CHAR FOLDED CPI CR ;IS ANSWER ? JZ GETDST ;SKIP SOURCE GET IF SO STA SRCLET ;SAVE LETTER IF NOT SUI 'A' ;MAP TO BINARY VALUE FROM 0 CPI NDRVS ;MAKE SURE NOT TOO BIG JC SRCOK ;PASS IF OK LXI H,BADNAM ;FLAG ERROR IF NOT CALL MSGOT JMP GETSRC ; AND TRY AGAIN ; SRCOK: CALL BSEL ;CALL BIOS TO SELECT DISK LXI H,SRCON ;PROMPT FOR SOURCE DISK CALL MSGOT CALL CHARIN ;WAIT FOR CPI CR JNZ REBOOT ;REBOOT IF ANYTHING ELSE TYPED ; ; READ THE SYSTEM FROM THE SPECIFIED DRIVE ; XRA A ;IF OK, FLAG DISK READ OPS STA DFLAG CALL XFRSYS ;READ SYSTEM INTO MEMORY JNZ GETSRC ;IF ABORTED, TRY AGAIN LXI H,FNCDUN ;FUNCTION DONE CALL MSGOT ; ; GET THE DESTINATION DISK ; GETDST: LXI H,DSTMSG ;GET DESTINATION NAME CALL MSGOT CALL CHARIN CPI CR ;SEE IF DONE JZ REBOOT ;GET OUT IF SO STA DSTLET ;IF NOT, SAVE DEST LETTER SUI 'A' ;MAKE SURE IN RANGE CPI NDRVS JC DSTOK ;PASS IF SO LXI H,BADNAM ;FLAG BAD NAME IF NOT CALL MSGOT JMP GETDST ; THEN ASK AGAIN ; DSTOK: CALL BSEL ;CALL BIOS TO SELECT DISK LXI H,DSTON ;PROMPT FOR SOURCE DISK CALL MSGOT CALL CHARIN ;WAIT FOR CPI CR JNZ REBOOT ;REBOOT IF ANYTHING ELSE TYPED ; ; WRITE TO THE DESTINATION DISK ; MVI A,1 ;FLAG DISK WRITE STA DFLAG CALL XFRSYS ;WRITE OUT SYSTEM JNZ GETDST ;NO MSG IF ABORTED LXI H,FNCDUN ;INDICATE DONE CALL MSGOT JMP GETDST ;ASK ABOUT WRITING AGAIN ; ; HERE WHEN DONE TO SELECT DRIVE A AND REBOOT ; REBOOT: XRA A ;SELECT DRIVE A CALL BSEL JMP WARMB ; THEN REBOOT CP/M ; ; SUBROUTINE XFRSYS TRANSFERS THE SYSTEM IMAGE FROM ; OR TO THE SELECTED DISK, BASED ON THE CONTENTS OF ; 'DFLAG'. IF 'DFLAG' CONTAINS ZERO, THE SYSTEM IS ; READ IN. IF 'DFLAG' CONTAINS ONE, THE SYSTEM IS ; WRITTEN OUT. BIOS DISK READ AND WRITE ARE CALLED ; DIRECTLY TO DO I/O. IF AN ERROR IS RETURNED FROM ; BIOS, IT IS REPORTED TO THE OPERATOR, WHO IS GIVEN ; THE OPTION OF IGNORING THE ERROR, OR ABORTING THE ; XFER. IF THE XFER WAS ABORTED, WE RETURN NON-ZERO ; IN ACC. BECAUSE THE HOST BUFFER CONTENTS ARE ; SCRAPPED ON I/O ERROR, WE CANNOT RETRY THE I/O. ; BESIDES, THE BIOS HAS ALREADY RETRIED IT FOR US. ; XFRSYS: MVI A,MAXSEC ;GET # OF CP/M SECTORS TO XFER STA SCOUNT ; AND SET COUNT TO DO LXI H,SECTBL ;PT TO SECTOR TABLE SHLD SECPTR ;INIT THE SECTOR ADDRESS PTR ; ; GET NEXT SECTOR ADDRESS FROM TABLE, AND SET BIOS PTRS ; NXTSEC: LHLD SECPTR ;GET NEXT SECTOR ADDRESS MOV A,M ; INTO ACC RLC ;BRING TRACK BIT INTO POSITION ANI 1 ;TRACK IS ZERO OR ONE MOV C,A ;PUT TRK # IN C FOR BIOS CALL BTRK ;CALL BIOS TO SET TRACK # LHLD SECPTR ;GET SECTOR ADDRESS AGAIN MOV A,M ANI 7FH ;STRIP TRACK BIT MOV C,A ;GET INTO CORRECT REG INX H ;BOP SECTOR TABLE PTR SHLD SECPTR ; AND UPDATE CALL BSEC ;CALL BIOS TO SET SECTOR # LHLD SECPTR ;GET TABLE PTR AGAIN MOV A,M ;GET LOGICAL SECTOR # RRC ;CALC MEM OFFSET HIGH BYTE ANI 7FH MOV B,A ;PUT FINAL VALUE IN BC MOV A,M ;NOW CALC LOW BYTE RRC ANI 80H MOV C,A INX H ;BOP PTR AGAIN SHLD SECPTR LXI H,CPMIA ;CALC MEM ADDR DAD B MOV B,H ;NEED IT IN BC MOV C,L CALL BDMA ;CALL BIOS TO SET DMA ADDR ; ; TIME TO DO THE SECTOR READ OR WRITE. CHECK DFLAG TO DECIDE. ; DOIO: LDA DFLAG ;ARE WE READING OR WRITING? ORA A ;IF ZERO, READING JNZ WRTSEC ;BRANCH IF WRITING CALL BREAD ;IF READING, CALL BIOS TO DO IT JMP CHKSEC ;NOW GO CHECK FOR ERRORS ; WRTSEC: CALL BWRITE ;CALL BIOS TO WRITE SECTOR ; CHKSEC: ORA A ;ERROR IF BIOS RETURNS NON-ZERO JZ XFROK ;PASS IF I/O OK ; ; I/O ERROR. ASK OPERATOR FOR A RULING. ; IOERR: LXI H,IOEMSG ;REPORT ERROR, AND ASK CALL MSGOT ; WHAT ACTION TO TAKE CALL CHARIN ;GET REPLY CPI 'I' ;IGNORE THE ERROR? JZ XFROK ;GO ON IF SO SUI 'A' ;ABORT THE XFER? JNZ IOERR ;ASK AGAIN IF NEITHER OF THE ABOVE INR A ;IF ABORT, RET ; RETURN NON-ZERO TO CALLER ; ; COUNT OFF LAST SECTOR TO SEE IF DONE ; XFROK: LDA SCOUNT DCR A ;COUNT OFF LAST SECTOR STA SCOUNT JNZ NXTSEC ;IF MORE TO DO, GO BACK RET ; ELSE RET ZERO TO CALLER ; ; ; BIOS I/O ROUTINES -- DISK SELECT ; BSEL: MOV C,A ;MOVE DISK # TO BIOS REG LXI D,SELDSK ;SELECT DISK JMP GOBIOS ; ; -- SET TRACK ; BTRK: LXI D,SETTRK ;SET TRACK C JMP GOBIOS ; ; -- SET SECTOR ; BSEC: LXI D,SETSEC ;SET SECTOR C JMP GOBIOS ; ; -- SET DMA ADDRESS ; BDMA: LXI D,SETDMA ;SET DMA ADDR BC JMP GOBIOS ; ; -- READ SECTOR ; BREAD: LXI D,READ ;READ SETUP SECTOR JMP GOBIOS ; ; -- WRITE SECTOR ; BWRITE: LXI D,WRITE ;WRITE SETUP SECTOR ; ; SINCE WE KNOW THAT THE NORTH STAR I/O IS BEING ; DEBLOCKED, LOAD C-REG WITH A VALUE OF 2 TO PREVENT ; PRE-READ FOR EVERY SECTOR BUT THE LAST ONE. FOR THAT ; SECTOR, LOAD C-REG WITH A VALUE OF 1 TO FORCE A WRITE ; TO FLUSH THE BIOS DEBLOCKING BUFFER BEFORE WE LEAVE, ; OR A REBOOT MAY LOSE THE LAST PHYSICAL SECTOR WE ; WANTED TO WRITE OUT. ; MVI C,2 ;WRITE TO UNALLOCATED LDA SCOUNT ;CHECK FOR WRITING TO DCR A ; LAST SECTOR JNZ GOBIOS ;JUMP IF NOT DCR C ;FORCE WRITE IF LAST ; ; XFER TO BIOS VIA VECTOR WHOSE OFFSET IS IN DE ; GOBIOS: LHLD BIOS ;PT TO BIOS WARM BOOT VECTOR DAD D ;CALC DESIRED VECTOR ADDR PCHL ;GO THERE ; ; ; OUTPUT MESSAGE PT'ED AT BY HL TO CONSOLE. MESSAGE ; IS A STRING OF CHARACTERS TERMINATED BY A ZERO BYTE. ; MSGOT: MOV A,M ;GET NEXT BYTE ORA A RZ ;IF NULL, DONE PUSH H ;IF NOT, SAVE PTR MOV E,A ;CHAR TO BDOS REG MVI C,CONOUT ;FUNCTION CALL BDOS ;GO OUTPUT CHAR POP H ;RESTORE PTR INX H ;PT TO NEXT BYTE JMP MSGOT ;GO BACK FOR MORE ; ; CONSOLE INPUT CHAR FUNCTION. LOWER CASE IS FOLDED ; TO UPPER ON RETURN. ; CHARIN: MVI C,CONIN ;CONSOLE INPUT FUNCTION CALL BDOS ;GET CHAR FROM CONSOLE CPI 'A'+20H ;FOLD LOWER CASE RC CPI 'Z'+20H+1 RNC SUI 20H RET ; ; MESSAGES ; HELLO: DB 'NSGEN V3.4',0 SRCMSG: DB CR,LF,'Enter source drive name (A-','A'+NDRVS-1 DB ') or to skip: ',0 DSTMSG: DB CR,LF,'Enter destination drive name (A-' DB 'A'+NDRVS-1,') or to reboot: ',0 BADNAM: DB CR,LF,'Invalid drive name.',0 SRCON: DB CR,LF,'Source on ' SRCLET: DB ' :, then type : ',0 DSTON: DB CR,LF,'Destination on ' DSTLET: DB ' :, then type : ',0 FNCDUN: DB CR,LF,'Function complete.',0 IOEMSG: DB CR,LF,'Disk I/O error. Type "I" to ignore or' DB ' "A" to abort transfer: ',0 ; ; SECTOR ADDRESS TABLE. EACH ENTRY CONSISTS ; OF TWO BYTES. THE FIRST BYTE REPRESENTS THE ; SECTOR'S DISK LOCATION. IF HIGH BIT IS SET, ; SECTOR IS ON TRACK ONE. IF NOT, SECTOR IS ; ON TRACK ZERO. LOW SEVEN BITS REPRESENT SECTOR ; NUMBER WITHIN TRACK. THE SECOND BYTE OF THE ; ENTRY IS THE LOGICAL SECTOR OFFSET FROM THE ; START OF THE CP/M IMAGE IN MEMORY, WHICH IS ; USED TO CALCULATE THE ACTUAL MEMORY ADDRESS ; OF THAT SECTOR SO THAT I/O CAN BE DONE. ; ; MAXSEC REPRESENTS THE TOTAL NUMBER OF ; SECTORS IN THE TABLE. REASSEMBLE TO CHANGE ; THE NUMBER OF SECTORS INVOLVED IN A TRANSFER. ; SECTBL: ;SECTOR TABLE ; ; NORTH STAR TRK, SEC ; DB 01+80H,00,02+80H,01,03+80H,02,04+80H,03 ; 1,0 DB 13+80H,12,14+80H,13,15+80H,14,16+80H,15 ; 1,3 DB 25+80H,24,26+80H,25,27+80H,26,28+80H,27 ; 1,6 DB 37+80H,36,38+80H,37,39+80H,38,40+80H,39 ; 1,9 DB 09+80H,08,10+80H,09,11+80H,10,12+80H,11 ; 1,2 DB 21+80H,20,22+80H,21,23+80H,22,24+80H,23 ; 1,5 DB 33+80H,32,34+80H,33,35+80H,34,36+80H,35 ; 1,8 DB 05+80H,04,06+80H,05,07+80H,06,08+80H,07 ; 1,1 DB 17+80H,16,18+80H,17,19+80H,18,20+80H,19 ; 1,4 DB 29+80H,28,30+80H,29,31+80H,30,32+80H,31 ; 1,7 DB 13+00H,40,14+00H,41,15+00H,42,16+00H,43 ; 0,3 DB 25+00H,56,26+00H,57,27+00H,58,28+00H,59 ; 0,6 DB 37+00H,68,38+00H,69,39+00H,70,40+00H,71 ; 0,9 DB 09+00H,48,10+00H,49,11+00H,50,12+00H,51 ; 0,2 DB 21+00H,52,22+00H,53,23+00H,54,24+00H,55 ; 0,5 DB 33+00H,64,34+00H,65,35+00H,66,36+00H,67 ; 0,8 DB 05+00H,44,06+00H,45,07+00H,46,08+00H,47 ; 0,1 DB 17+00H,72,18+00H,73,19+00H,74,20+00H,75 ; 0,4 DB 29+00H,60,30+00H,61,31+00H,62,32+00H,63 ; 0,7 ; MAXSEC EQU ($-SECTBL)/2 ;# OF SECTORS IN TABLE ; ; VARIABLE DATA ; DFLAG: DS 1 ;=0, READ SYS. =1, WRITE SYS. SECPTR: DS 2 ;PTR INTO SECTBL SCOUNT: DS 1 ;COUNT OF SECTORS LEFT TO XFER ; END NSGEN