* * * * * * * * * * * * * * * * * * * * * * * * * * SYSTEM RE-GENERATION UTILITY * * COPYRIGHT (C) 1984 * * AMPRO COMPUTERS, INC. * * * * * * * * * * * * * * * * * * * * * * * * * * ; assemble with asm.com or equivalent. there is no z80 code. VER EQU 33 ; ;--------------------------------------------------------------------- ; ; SYSTEM GENERATION UTILITY SYSGEN.ASM ; ; This utility copies the system images from the Source ; disk(ette) onto the Destination disk(ette). ; ; The system images moved consist of CCP BDOS BIOS and ZCPR ; if currently active on the source drive. ; ; For AMPRO diskettes, the disk layout is as follows: ; ; Track 0 sector 0 Boot loader ; ; Track 0 sector 1 thru 39 CCP BDOS ; Track 1 sector 0 thru 4 BDOS continued. ; ; Track 1 sector 5 thru 39 BIOS ; ; For the AMPRO hard disk systems, the disk layout is as follows: ; ; Track 0 sector 0 Boot loader ; ; Track 0 sector 1 thru 44 CCP BDOS ; ; Track 0 sector 45 thru 63 BIOS ; ; Track 1 sector 0 thru 11 BIOS ; ; All unused sectors on the hard disk tracks 0 and 1 are reserved. ; ; ; NOTE: This utility will support any source or destination ; device, either floppy or hard disk (or partition). ; ; The single requirement is that the target device must ; have 80 CP/M sectors available in the reserved area ; beginning at CP/M Track 0 Sector 0. Track incrementing ; is automatically done when required. ; ; This includes mixture of single and double-sided devices. ; ;------------------------------------------------------------------------- ; Revision History: ; ; Ver Date Who Description ; --- ----- --- ---------------------------------------------- ; 3.3 E6.17 RJB Removed HD controller type from SCSI drive ; letter listing ; ; 3.2 E2.22 RJB Added message to display the floppy and hard ; disk CP/M drive letters, switched input from ; BIOS calls to BDOS calls & allowed '.'=, ; ','= in prompt (to make SUBMIT-able). ; ; 3.1 E2.12 RJB Added a "don't care" read to flush the last ; written sector to disk. ; ; 3.0 DC.10 RLD Massive changes to allow disk A-P floppy or ; hard disks. Removed all primitive hardware- ; dependant code since already exists with the ; system BIOS. Almost a total re-write. ; ; 2.2 D5.08 Cleaned up responses. ; 2.1 D5.03 Add 10 ms delay after line feeds. ; 2.0 Release version. CTLC EQU 3 ; control c CR EQU 13 ; carriage return LF EQU 10 ; line feed ESC EQU 27 ; escape key UPCASE EQU 5FH ; upper case mask BDOS EQU 5 ; bdos entry point FCB EQU 5CH ; default file control block OPEN EQU 15 ; bdos open file READS EQU 20 ; bdos read sequential STDMA EQU 26 ; bdos set dma address IMAGE EQU 900H ; 'sysgen' image location BUFFER EQU IMAGE TBUF EQU IMAGE+(80*128) ; default disk buffer and kbd buffer ONDSKS EQU 5CH ;BIOS OFFET TO (NDSKS) PARAMETER OFCOPY EQU 98H ;OFFSET TO COPYRIGHT STRING ORG 100H JMP START CURCNT DB 0 CURPNT DW 0 OPER DB 0 SECTOR DW 0 TRACK DB 0 MAXSEC DB 0 SDRIV DB 0 DDRIV DB 0 DMAADR DW 0 clchr db 0 clptr dw 0 DFDEV: lda bvers cpi 20 rm LXI D,D$FDEV$HDR ; Print header mvi c,9 call bdos mvi a,0 ; starting unit # D$NEXT$FDEV: sta unit call bpaget ; Get address of unit id MOV A,M ; Get unit id CPI 01 ; Floppy? JNZ D$BUMP$PTR ; No -- go to the next device inx h ; Get drive # mov a,m ; . ani 03h ; mask out excess bits MOV l,a ; update floppy device number mvi h,0 ; . dad h ; x2 xchg LXI H,FNAMES ; . dad d ; x2 dad d ; x4 dad d ; x6 lxi d,d$fname ; lxi b,6 ; db 0edh,0b0h ; . (LDIR) lda unit ; adi 'A' ; sta d$current ; LXI D,D$FDEV$LIN ; and output the line mvi c,9 call bdos D$BUMP$PTR: lda unit inr a ; Bump to next unit cpi 16 ; Done yet? jm D$NEXT$FDEV ; No -- go do the next one RET unit: db 0 D$FDEV$HDR: DB cr,lf,lf,'FLOPPY DISK ASSIGNMENTS:',CR,LF DB 'CP/M drive ' DB 'Floppy disk',CR,LF DB '------------------------',CR,LF,'$' D$FDEV$LIN: DB ' ' D$CURRENT: DB 'x ' D$EDISK: DB ' ' D$EBLANK: DB ' ' D$FNAME: DB ' ' DB CR,LF,'$' D$FDEV$HLEN EQU $-D$FDEV$LIN ; Line length FNAMES: DB 'First ' DB 'Second' DB 'Third ' DB 'Fourth' DSDEV: lda bvers cpi 20 rm LXI D,HD$HEADER ; Display table header mvi c,9 CALL bdos mvi a,0 D$NEXT$SDEV: sta unit call bpaget mov a,m cpi 03 jnz d$next$unit inx h inx h mov a,m ; logical unit number ani 0e0h ; . RLC ; . (move bits 7-5 to 2-0) RLC ; . RLC ; . ANI 07H ; . (mask out other bits) ADI '0' ; . (convert to ascii 0-7) STA DRIVE$UNIT ; . inx h MOV A,M mvi b,0ffh ora a jz sc$conv sc$nxt$bit inr b rrc jnc sc$nxt$bit sc$conv mov a,b ADI '0' ; . (convert to ascii 0-7) STA DRIVE$ADDRESS ; . lda unit adi 'A' sta drive$letters lxi d,drive$info mvi c,9 call bdos D$NEXT$UNIT: LDA UNIT ; Get unit we're working on INR A ; Bump to next Cpi 16 ; Are we done? JM D$NEXT$SDEV ; No -- go do another RET HD$HEADER: DB cr,lf,lf,'HARD DISK ASSIGNMENTS:',CR,LF DB 'CP/M drive ' DB 'Addr Unit #',CR,LF DB '-------------------------------------' DB '',CR,LF,'$' DRIVE$INFO: DB ' ' DRIVE$LETTERS: DB ' ' DRIVE$ADDRESS: DB '0 ' DRIVE$UNIT: DB '0',CR,LF,'$' ; ; S T A R T . . . ; START: lxi sp,stack lxi h,80h mov a,m inx h mov c,a ora a jz nocmdline delimiter: mov a,m inx h dcr c jz nocmdline cpi '/' jnz delimiter shld clptr nocmdline: mov a,c sta clchr CALL CGET ;SET BIOS TABLES TO LOCAL JUMPS ;---------------------------------------------------------------------- ; ; IF ZERO SET ON RETURN, MODIFY THE MAX SOURCE AND DESTINATION ; MESSAGES AND COMPARES TO USE BIOS VARIABLE (NDSKS) ; ; This is done to prevent a system hang on pre-2.1 Bios where ; a non-existant floppy will hang. ; ; In the 2.1 Bios, a select error is returned ; ;---------------------------------------------------------------------- JNZ STT1 ;JUMP FOR VERSION 2.1 OR GREATER LHLD 1 ;GET BIOS ADDRESS BACK MVI L,0 ;POINT TO COLD ENTRY LXI D,ONDSKS ;OFFSET TO KNOW VARIABLES DAD D MOV A,M ;GET MAX DISK NUMBER ADI '@' ;SET ASCII BIAS STA SMXD STA DMXD INR A ;+1 FOR COMPARE STA SDXS ;SET DISPLAY VALUES STA DDXS STT1: CALL CLEAR ;CLEAN THE SCREEN LXI D,MSG1 CALL CMESS ;AND DISPLAY WE ARE HERE ;--------------------------------------------------------------------- ; ; TEST THE DEFAULT FCB FOR A FILENAME ENTRY ; ; If the first character of the default FCB is not a Space, ; then use the filename provided within that FCB as the source ; file in place of a source diskette. ; ; The entry format from CCP is: SYSGEN d:Fname.Ext ; ; If the first character of the 'filename' is an asterisk, ; then use the console buffer as input for the drive names. ; ;------------------------------------------------------------------- LDA FCB+1 ; first file name character cpi '/' ; star means use console input jz asksrc ; CPI ' ' ; check for space JNZ GETFIL ; read the named file ;------------------------------------------------------------------- ; ; GET SOURCE DISK ENTRY ; ; Get entry and then a Carriage Return key. When CR hit, go ; and read from the source drive. ; ;------------------------------------------------------------------ ASKSRC: call dfdev call dsdev asks2: LXI D,MSGS CALL CMESS ASKS: CALL crdc call switch ANI UPCASE CPI ESC JZ DCLR ;CLEAR SCREEN AND RETURN CPI CTLC JZ DCLR CPI CR ;IF CR THEN MEMORY IMAGE JZ RMIMAG CPI 'A' JC ASKS2 SDXS: EQU $+1 CPI 'P'+1 ;A THRU P ALLOWED JNC ASKS2 STA SDRIV STA SDR MOV C,A LXI D,MSG2 CALL CMESS SDRA: CALL CRDC call switch CPI CR JZ RDSRC ;NOW READ IN THE SOURCE CPI CTLC JZ DCLR CPI ESC JZ DCLR JMP SDRA ;------------------------------------------------------------------- ; ; GET DESTINATION DISK ENTRY ; ; Get entry and then a Carriage Return key. When CR hit, go ; and write to the source drive. ; ;------------------------------------------------------------------ ASKDES: call dfdev call dsdev askd2: LXI D,MSGD CALL CMESS ASKD: CALL crdc call switch ani upcase CPI ESC JZ DCLR CPI CTLC JZ DCLR CPI CR JZ DCLR CPI 'A' JC ASKD2 DDXS: EQU $+1 CPI 'P'+1 ;A THRU P ALLOWED JNC ASKD2 STA DDRIV STA DDR MOV C,A LXI D,MSG4 CALL CMESS DDRA: CALL CRDC call switch CPI CR JZ DDRB ; write destination disk CPI CTLC JZ DCLR CPI ESC JZ DCLR JMP DDRA DDRB: CALL CWTC JMP WRDES switch: cpi ',' jnz notcr mvi a,cr ret notcr: cpi '.' jnz notesc mvi a,esc ret notesc: cpi '!' rnz mvi a,3 ret ;--------------------------------------------------------------------- ; ; SOURCE ENTRY IS MEMORY ; ; Test to see if a system really there. ; ; This is done via a simple string compare starting at ; Buffer + OFCOPY looking for the Copyright string. ; ; If the system is in memory, then prompts for destination. ; ; If no system currently in memory, prompts for new source. ; ;--------------------------------------------------------------------- RMIMAG: LXI H,BUFFER+OFCOPY ;POINT TO WHERE STRING SHOULD BE LXI D,CMPSTG MVI B,CMPEND-CMPSTG ;FOR LENGTH RMI0: LDAX D CMP M JNZ RMI2 ;NOT THERE INX H INX D DCR B JNZ RMI0 ; RMI1: LXI D,MEM1 ;SHOW FROM MEMORY CALL CMESS JMP ASKDES ;AND GET THE DESTINATION RMI2: LXI D,MEM2 ;SHOW NO SYSTEM IN MEMORY CALL CMESS JMP ASKS2 ;AND GET NEW SOURCE ; CMPSTG: DB 'COPYRIGHT (C)' CMPEND: ;----------------------------------------------------------------- ; ; IF A SOURCE FILENAME WAS ENTERED, THEN READ THE FILE AS ; THE SOURCE DISK. ; ;----------------------------------------------------------------- GETFIL: LXI D,FCB+12 ;CLEAR FCB EXTENT BEFORE OPEN MVI B,23 XRA A GF0: STAX D INX D DCR B JNZ GF0 LXI D,FCB ;OPEN FILE MVI C,OPEN CALL BDOS INR A JZ NOFIL ; file cannot be found LXI D,TBUF MVI C,STDMA CALL BDOS MVI B,16 ; read 16 dummies GF1: PUSH B ; save count LXI D,FCB MVI C,READS CALL BDOS POP B DCR B JNZ GF1 LXI H,IMAGE SHLD DMAADR GF2: XCHG MVI C,STDMA CALL BDOS LXI D,FCB MVI C,READS CALL BDOS ORA A JNZ ASKDES ;FILE READ COMPLETED - GET DESTINATION LHLD DMAADR LXI D,128 DAD D SHLD DMAADR JMP GF2 NOFIL: LXI D,NFLM CALL CMESS JMP 0 NFLM: DB CR,LF,LF,'Cannot find source file!',CR,LF,'$' ;------------------------------------------------------------------- ; ; READ SYSTEM FROM SOURCE DISK ; ; Reads in 80 CP/M sectors starting at Trk 0 Sector 0, to ; to system ram at BUFFER. ; ;------------------------------------------------------------------ ; RDSRC: LXI H,0 ;START AT TRK 0 SECTOR 0 SHLD SECTOR MVI A,01H ;SET A READ OPERATION IN PROGRESS STA OPER LDA SDRIV ;GET SOURCE DRIVE CALL SELECT JNZ ASKSRC ;ASK FOR A NEW SOURCE MVI A,80 ;SET 80 SECTORS TO READ FOR CCP BDOS BIOS STA CURCNT ;SET COUNTER CALL MOVE ;AND DO IT... JP ASKDES ;NOW GET THE DESTINATION ;------------------------------------------------------------------- ; ; WRITE SYSTEM FROM RAM BUFFER ; ; Writes 80 CP/M sectors to the target destination disk from ; the system ram BUFFER, starting at Track 0 Sector 0. ; ;--------------------------------------------------------------------- ; WRDES: LXI H,0 ;START AT TRK 0 SECTOR 0 SHLD SECTOR MVI A,02H ;SET A WRITE OPERATION IN PROGRESS STA OPER LDA DDRIV ;GET DEST DRIVE CALL SELECT JNZ ASKDES ;ASK FOR A NEW DEST MVI A,80 ;SET 80 SECTORS TO WRITE FOR CCP BDOS STA CURCNT ;SET COUNTER CALL MOVE ;AND DO IT... call flush ; now read t0,s0 to flush write JP ASKDES ;NOW GET THE NEXT DESTINATION ; ;--------------------------------------------------------------------- ; ; SELECT DISK ; ; Selects the requested disk drive in (A) , and aquires the current ; Sectors-per-track entry from the DPB for this drive. ; ; If a select error, returns with NZ set. ; ;-------------------------------------------------------------------- SELECT: DCR A ;-1 ANI 0FH ;ISOLATE LUN MOV C,A MVI E,0 ;FORCE RE-TYPE ID THIS DRIVE CALL BSEL ;DO THE SELECT MOV A,H ORA L ;WATCH FOR SELECT ERROR JZ SELERR ;IF ERROR ON SOURCE SELECT LXI D,10 ;OFFSET TO CURRENT DPB THIS DRIVE DAD D MOV A,M ;GET THE DPB ADDRESS FROM THE DPB INX H MOV H,M MOV L,A MOV A,M ;THIS GIVES US THE SECTORS PER TRACK STA MAXSEC ;SAVE IT FOR LATER LXI H,BUFFER ;SET DMA TRANSFER ADDRESS SHLD CURPNT ;SET BUFFER TO START XCHG CALL BSDMA XRA A ;LEAVE WITH Z SET RET SELERR: LXI D,SELM ;ISSUE SELECT ERROR CALL CMESS MVI A,0FFH ORA A ;AND SET NZ RET SELM: DB 07H,CR,LF,LF,' DRIVE SELECT ERROR ',CR,'$' ;--------------------------------------------------------------------- ; ; MOVE SYSTEM ; ; This is the work code to Read or Write the number of sectors ; starting at (SECTOR) for (CURCNT) with data buffer at ; (CURPNT), and the drive sectors-per-track at (MAXSEC). ; ; Returns with Z set if done and no errors, else NZ set. ; ;--------------------------------------------------------------------- MOVE: LXI D,CRSTG ;CR LF STRING CALL CMESS MOV0: MVI A,'.' ;SHOW WE ARE BUSY CALL CWTC LHLD CURPNT ;GET CURRENT BUFFER POINTER XCHG CALL CDMA ;AND SET DMA ADDRESS LHLD SECTOR ;GET TRK AND SECTOR LDA OPER CALL CRDWR ;AND READ OR WRITE ONE SECTOR JNZ MOVERR ;DISK ERROR LHLD CURPNT LXI D,128 DAD D ;BUMP DMA ADDRESS SHLD CURPNT LHLD SECTOR INX H ;AND BUMP SECTOR +1 SHLD SECTOR LDA MAXSEC ;TEST AGAINST CURRENT MAX SECTOR CMP L JNZ MOV1 ;NOT THERE YET MVI L,0 ;RESET SECTOR TO 0 INR H ;AND BUMP TRACK +1 SHLD SECTOR MOV1: LDA CURCNT ;SECTOR COUNTER -1 DCR A STA CURCNT JNZ MOV0 ;DO NEXT RET ;ALL DONE HERE ; MOVERR: LXI D,MESER ;JUST ISSUE THE MESSAGE CALL CMESS JP 0 ;AND WARM BOOT ; MESER: DB CR,LF,LF,'R/W ERROR - ABORTED - ' DB CR,LF,'$' ; flush: ; flush data with a "don't care" read lhld curpnt ; set dma xchg ; . call cdma ; . lxi h,0 ; read track 0, sector 0 mvi a,01h ; . call crdwr ; . jnz moverr ; display any error ret ; and return ;-------------------------------------------------------------------- ; ; READ OR WRITE SECTOR ENTRY ; ; Enter with the operation in (A) READ = 01 WRITE = 02 ; Track in (H) Logical Sector in (L) ; ; Data is stored at (DMA) ; ; Exits with A and HL set as entered ; ; Returns with NZ set id R/W error ; ;------------------------------------------------------------------ COPR DB 0 ;SAVED OPER BYTE CSEC DW 0 ;TRK AND SECTOR SAVED ; CRDWR: STA COPR ;SAVE OPER CODE SHLD SECTOR ;AND TRK/SECTOR MOV C,H MVI B,0 ;SET TRACK FIRST CALL BSTRK LDA SECTOR ;GET SECTOR NEXT MOV C,A MVI B,0 CALL BSSEC LDA COPR ;GET OPERATION CODE CPI 01H ;READ? JNZ CWRTE CALL BSRD ;READ SECTOR JMP CSEND CWRTE: CALL BSWRT ;ELSE WRITE ONE CSEND: CPI 0 ;TEST STATUS LDA COPR ;RESTORE A AND HL LHLD SECTOR RET ;RETURN WITH Z SET IF OK ;----------------------------------------------------------------------- ; ; CCGET GET SYSTEM BIOS JUMP TABLES ; ; Brings the current BIOS Jump tables starting at WARM BOOT ; to this local area for ease of utility access. ; ; If this BIOS is Version 2.1 or greater, also brings in the ; secondary Jump Table. ; ; Exits with Z set if lower than 2.1 Bios level ; ;--------------------------------------------------------------------- CGET: LHLD 1 ;GET START OF BIOS CODE AREA LXI D,BBOOT ;MOVE TO LOCAL STORAGE MVI B,BLEN ;SET COUNT CALL CGET0 ;MOVE STRING MVI A,0 ;TEST FOR VERSION CALL BGETT ;IF 0, THEN LESS TAHN 1.4 STA BVERS ;SAVE BIOS VERS INX H ;SEE IF HL IS FFFF MOV A,H ORA L RZ ;IF SO, THEN OLD SYSTEM DCX H ;FIX HL SINCE HAS THE TABLE ADDRESS LXI D,BNXTTBL ;SAVE NEXT TABLE MVI B,BSLEN CALL CGET0 MVI A,0FFH ;SET NZ ORA A RET ;TO ID THIS LEVEL CGET0: MOV A,M STAX D INX H INX D DCR B JNZ CGET0 RET ; ;------------------------------------------------------------------- ; ; CMESS SEND MESSAGE STRING ; ; Outputs the string pointed to be (DE) until the ($) delimeter ; ;------------------------------------------------------------------- CMESS: MVI C,9 JMP BDOS ;--------------------------------------------------------------------- ; ; CDMA Set (DE) to the DMA address ; ;--------------------------------------------------------------------- CDMA: MVI C,26 JMP BDOS ; ;---------------------------------------------------------------------- ; ; CRDC Read and Echo a Console Input ; ;--------------------------------------------------------------------- ; CRDC: lda clchr ora a jz crdc2 dcr a sta clchr lhld clptr mov a,m inx h shld clptr push psw call cwtc pop psw ret crdc2: MVI C,1 JMP BDOS ; ;-------------------------------------------------------------------- ; ; CWTC Write character in (A) to the console ; ;-------------------------------------------------------------------- CWTC: MVI C,2 MOV E,A JMP BDOS ;------------------------------------------------------------------- ; ; CLEAR THE SCREEN USING LINE-FEEDS ONLY ; ;------------------------------------------------------------------ CLEAR: MVI A,24 ;SET TO CLEAR 24 LINES STA CURCNT ;USE THE COUNTER CLR0: MVI A,LF ;ISSUE A LINE FEED CALL CWTC LXI B,1670 ;SET ABOUT 10 MSEC DELAY CLR1: ;DO DELAY BETWEEN SO ALL CRTS CAN FOLLOW DCX B MOV A,C ORA B JNZ CLR1 LDA CURCNT DCR A STA CURCNT JNZ CLR0 RET ; ;-------------------------------------------------------------------- ; ; EXIT PROGRAM ; ; Clear screen and Warm Boot System. (same as JMP 0) ; ;------------------------------------------------------------------ DCLR: JP BBOOT ;TO WARM BOOT ; ;------------------------------------------------------------------ ; ; REPLICATED BIOS JUMP TABLE FOR EASE OF USAGE. ; ;------------------------------------------------------------------ ; BBOOT DS 3 BCSTS DS 3 BCIN DS 3 BCOUT DS 3 BLST DS 3 BPNCH DS 3 BRDR DS 3 BHOME DS 3 BSEL DS 3 BSTRK DS 3 BSSEC DS 3 BSDMA DS 3 BSRD DS 3 BSWRT DS 3 BLSTS DS 3 BSTRN DS 3 BGETT DS 3 ;GET 2.1 JUMP TABLES BGETE DS 3 BIOINT DS 3 BSCSI DS 3 BLEN EQU $-BBOOT ;LENGTH TO GET ; BNXTTBL: ;VERSION 2.1 > SECONDARY TABLE BSWAP DS 3 BSXBINT DS 3 BPHTBAC DS 3 BPAGET DS 3 DS 3 DS 3 DS 3 DS 3 BSLEN EQU $-BNXTTBL BVERS: DB 0 ;VERSION OF BIOS CODE MSG1: DB CR,LF,' AMPRO System Generation Utility' DB CR,LF,'Copyright (C) 1984,1985 AMPRO Computers, Inc.' DB CR,LF,' Version ' DB VER/10+'0','.',VER MOD 10+'0' DB CR,LF,'$' MSGS: DB CR,LF,'Enter Source Drive? (A thru ' SMXD: DB 'P) $' MSG2: DB CR,LF,'Place source on ' SDR: DB 'A, then type $' MSGD: DB CR,LF,LF,'Enter Destination Drive? (A thru ' DMXD: DB 'P) $' MSG4: DB CR,LF,'Place destination disk on ' DDR: DB 'A, then type $' CRSTG: DB CR,LF,'$' MEM2: DB cr,lf,lf,'NO SYSTEM IN MEMORY.',lf,'$' MEM1: DB cr,lf,lf,'Source = Memory Image.',lf,'$' ds 32 stack: END