;Program originally written by Marc Kupper, 1982 ;Modified by Bill Smith, Nov. 1983 ;a. If SOURCE_DRIVE = DESTINATION_DRIVE, THEN SUPPRESS COPY ;b. serial numbers to 32-bits ; ; Quicky disk copy + serialization ; ; Copyright (c) 1982, Morrow Designs ; ; This program was assembled with MAC from Digital Research. ; ; ; Define the CP/M environment ; revnum equ 10 ;Revision 0.0 cpmver equ 22 ;CP/M version 2.2 bios equ 0 ;Jmp to the BIOS jump table cpmdrv equ 4 ;CP/M drive # bdos equ 5 ;System entry address fcb equ 5ch ;Systems File Control Block cpmbuf equ 80h ;CP/M's buffer tpa equ 0100h ;Start of the TPA secsiz equ 128 ;128 byte/sector cin equ 1 ;Cosole input cout equ 2 ;Console output print equ 9 ;string output eom equ 24h ;string terminator bufin equ 10 ;Buffered input reset equ 13 ;Reset disk system fopen equ 15 ;Open a file fclose equ 16 ;Close a file sfirst equ 17 ;Search for the first filename snext equ 18 ;Search for the next filename rread equ 33 ;Random read rwrite equ 34 ;Random write ; ; Define character constants ; cntlc equ 'C'-64 ;Control C lf equ 'J'-64 ;Line feed cr equ 'M'-64 ;Carraige return ; ; Define Z80 instructions ; dorel macro z80typ, addr z80tmp set addr-$-2 if (z80tmp ge 0ff80h) or (z80tmp le 7fh) db z80typ, low z80tmp else db 18h, 0feh 'Address over/under-flow' endif endm dach macro db 0edh,06ah ;adc hl,hl endm dacd macro db 0edh,05ah ;adc hl,de endm sbbb macro db 0edh,042h ;sbc hl,bc endm djnz macro addr ! dorel 10h, addr endm jr macro addr ! dorel 18h, addr endm jrz macro addr ! dorel 28h, addr endm jrnz macro addr ! dorel 20h, addr endm jrc macro addr ! dorel 38h, addr endm jrnc macro addr ! dorel 30h, addr endm lbcd macro addr ! dw 04bedh, addr endm lded macro addr ! dw 05bedh, addr endm ldir macro ! dw 0b0edh endm sbcd macro addr ! dw 043edh, addr endm sded macro addr ! dw 053edh, addr endm ; ; Le Programme ; org tpa lxi h,stack ;Set up the stack sphl call init ;Set up the environment dover: call ready ;Setup the disks call copy ;Copy disks jrc dover call domov ;Serialize the movcpm's call again ;Set up for the next copy jr dover ;Do copy over ; ; Set up the environment ; init: lda cpmdrv ;Save the CP/M drive number sta savdrv lxi b,17*3 ;Make a copy of the BIOS jump table lxi d,cold lhld bios+1 mvi l,0 ldir lxi h,signon ;Print signon call puts lxi h,strser ;Get the starting serial number call getnum sbcd sernum ;lo sded sernum+2 ;hi lxi h,strcnt ;Get the disk count call getnum sbcd dcount ;lo lxi h,1 ;Start the up count at 1 shld scount call crlf xra a sta nocopy sta same ;Clear the disk swap flag sta inch8 ;Clear 8 inch flag cma sta cdrive ;Set the current drive init0: lxi h,source ;Get the source drive name call getdrv sta from lxi h,dest ;Get the destination drive name call getdrv sta to lda from ;Test for copying to self mov b,a lda to cmp b jrz toself ;Skip if copying to self call crlf ;All done ret toself: mvi a,1 ;set nocopy = true sta nocopy ret ; ; Set up the drives ; ready: lxi h,ready0 ;'(' message call puts lhld scount ;Print the current disk number call puthl lxi h,ready1 ;') Press ...' message call puts call outser ;Print the serial number lxi h,ready2 ;': ' message call puts call conin ;Wait for a cpi cr ;Make sure that we have a CR jnz exit call crlf ;Echo a LF lda from ;Test out the source drive lxi h,fromp call drvsel jrc selerr ;Skip if a select error occured lda to ;Test out the destination drive lxi h,top call drvsel jrc selerr mvi c,16 ;Make sure the drives are identical lxi d,fromp lxi h,top setcmp: ldax d ;Compare the DPB's cmp m jrnz setcpe ;Skip if DPB's are different inx d ;Bump DPB pointers and counters inx h dcr c jrnz setcmp lhld cks ;Look for 8 inch floppies mov a,h ora l jz not8 ;Skip if this is a hard disk lhld spt ;Test out various spt values lxi d,20 ;Single density 5 1/4 inch floppy? call hlcde jz not8 lxi d,40 ;Double density 5 1/4 inch floppy? call hlcde jz not8 lxi d,80 ;Double sided 5 1/4 inch floppy? call hlcde jz not8 lxi d,26 ;Single density 8 inch floppy? call hlcde jz not8 mvi a,1 ;Set 8 inch select mode sta inch8 not8: ret selerr: lda cdrive ;Get the current drive adi 'A' ;Convert the name to ASCII sta baddr0 ;Place the name in the message text lxi h,baddrv ;Print a complaint jr setu2 setcpe: lxi h,badcmp ;Complain about dissimilar drives setu2: call puts jmp ready ; ; Copy destination to source disk, serialize the system disk ; copy: call calc ;Figure out buffering, disk sizes lxi b,0 ;Source track mov d,b ;Destination track mov e,c lhld sysize ;Number of system sectors mvi a,1 ;Serialization mode call docopy ;Copy system tracks rc lda nocopy ora a ;test rnz ;don't copy if same drive lbcd off ;Source track lded top-fromp+off ;Destination track lhld datsiz ;Number of data sectors xra a ;No serialization call docopy ;Copy data tracks ret ; ; Set up for the next copy ; again: lxi h,alldon ;Serialization of this disk is complete call puts lhld sernum ;Bump the serial number inx h shld sernum mov a,h ora l jrnz again0 lhld sernum+2 inx h shld sernum+2 again0: lhld scount ;Bump the up counter inx h shld scount lhld dcount ;Bump the down counter dcx h shld dcount mov a,h ;Test for the end ora l rnz jmp exit ;Quit ; ; Copy some tracks ; docopy: sta sysmod ;Save system serialization mode sbcd sparam ;Source track sded dparam ;Destination track sded vparam ;Verify track shld maxsec ;Number of sectors to copy shld numsec ;Initialize sector count lxi h,0 ;Clear the sector numbers shld sparam+2 shld dparam+2 shld vparam+2 mvi a,1 ;Set all drives to double density sta sparam+4 sta dparam+4 sta vparam+4 docpy0: lded maxsec ;Get the number of sectors to copy mov a,d ;Test for no more sectors ora e rz ;Return 'done', carry reset lhld numbuf ;Get the buffer size (in sectors) call hlcde ;Compare jrc docpy1 ;Skip if NUMBUF > NUMSEC mov h,d ;Do partial buffer load mov l,e docpy1: shld numsec ;Save number of sectors to move call readbf ;Read from disk to the buffer rc lda sysmod ;Do we serialize this buffer load? ora a cnz sersys ;Serialize the system lhld numsec call writbf ;Write to disk from the buffer rc lhld numsec call veribf ;Verify the disk with the buffer rc lded numsec ;Knock off the sectors just copied from lhld maxsec ; the count call hlmde shld maxsec jmp docpy0 ;Do another buffer load ; ; Fill the data buffer ; readbf: push h ;Save the number of sectors to read lda from ;Select the source drive mov c,a call select lxi h,datbuf ;Initial DMA address shld dmaddr pop h read0: push h ;Save the sector count lxi h,sparam ;Source parameters call setup ;Set up DMA, track, and sector values call read ;Read a sector ora a ;Test for a read error lxi h,readr cnz error ;Complain if an error occures pop h ;Get the sector count rc ;Return if read error not cleared dcx h ;Bump the sector count mov a,h ora l jnz read0 ret ; ; Flush the data buffer ; writbf: push h ;Save the number of sectors to write lda to ;Select the destination drive mov c,a call select lxi h,datbuf ;Initial DMA address shld dmaddr xra a ;Set allocated write mode sta allocw pop h writ0: push h ;Save the sector count lxi h,dparam ;Destination position pointer call setup ;Set up DMA, track, and sector values lda allocw ;Get allocation mode mov c,a mvi a,2 ;Future writes are unallocated sta allocw call write ;Write a sector ora a ;Test for a read error lxi h,writer cnz error ;Complain if an error occures pop h ;Get the sector count rc ;Return if write error not cleared dcx h ;Bump the sector count mov a,h ora l jnz writ0 ret ; ; Verify the data buffer ; veribf: lxi d,verbuf ;Set compare address to data buffer sded dmaddr veri0: push h ;Save the sector count lxi h,vparam ;Verification parameters call setup ;Set up DMA, track, and sector values lxi b,verbuf ;Reset the DMA address to our buffer call setdma call read ;Read a sector ora a ;Test for a read error lxi h,verifr cnz error ;Complain if an error occures pop h ;Get the sector count rc ;Return if read error not cleared push h ;Do a data compare mvi c,secsiz ;Sector size lxi d,verbuf ;Verify buffer pointer lhld dmaddr ;Data buffer pointer vercmp: ldax d ;Compare the buffers cmp m jrnz vererr ;Skip if the buffers are different inx d ;Bump data pointers and counters inx h dcr c jrnz vercmp vererr: lxi h,datcmp ;Data compare error cnz error pop h ;Restore the sector count rc ;Return if error not accepted dcx h ;Bump the sector count mov a,h ora l jnz veri0 ret ; ; Error reporter ; error: push h ;Save the operation type string pointer lxi h,errm0 ;'Unrecoverable ' call puts pop h ;'read', 'write', 'verify', 'data comp' call puts lda cdrive ;Get the current drive adi 'A' ;Convert to ASCII sta errm2 ;Save in the error message lxi h,errm1 ;' error on drive X:, track ' call puts lhld track ;Print the track call puthl lxi h,errm3 ;', sector ' call puts lhld tsectr ;Print the translated sector call puthl lxi h,errm4 ;'.CRLF....' call puts call conin ;Wait for a reply push psw call crlf call crlf pop psw cpi cr rz ;Ignore error on a CR stc ;Set the error flag ret ; » Setuð foò á buffeò operation¬ bumð thå DMA¬ track¬ anä sectoò pointers ; setup: shld param ;Save the parameter table pointer mov c,m ;Load the current track inx h mov b,m sbcd track inx h ;Load the current sector mov e,m inx h mov d,m inx h ;Load the current density mov a,m sta densty sded sector push d ;Save the sector push b ;Save the track lda inch8 ;Test for 8 inch drives ora a jrz setn8 ;Skip density test if not 8 inch mov a,b ;Test to see if we are on track 0 ora c lxi h,densty ;Density mode mov a,m jrnz sent0 ;Skip if not on track 0 ora a ;Test for double density cnz single ;Set up single density mode jr setn8 sent0: ora a ;Test for single density cz double ;Set up double density mode setn8: pop b ;Restore the track call settrk ;Set the track pop b lda sysmod ;Test for system track copy ora a mov h,b ;Set up in case of system track mode mov l,c inx h jrnz setn1 ;Skip sectran on the system tracks lded stranp ;Sectran table pointer call sectran ;Translate logical to physical sectors setn1: shld tsectr ;Save translated sector mov b,h mov c,l call setsec lbcd dmaddr ;DMA address lxi h,secsiz ;Sector size dad b ;Bump to the next sectors address shld dmaddr ;Save for the next read/write call setdma ;Set the DMA address lbcd track ;Bump to the next disk position lded spt lhld sector inx h ;Bump to the next sector call hlcde ;HL - DE jrc setu0 ;Skip if SPT > SECTOR inx b ;Bump to the next track lxi h,0 ; and to the start of that track setu0: xchg lhld param ;Parameter table pointer mov m,c ;Save the track inx h mov m,b inx h mov m,e ;Save the sector inx h mov m,d lda densty inx h mov m,a ;Save the density cmc ;Set the track overflow flag ret ; ; Make the BIOS think we are looking at a single density disk ; single: xra a ;Set single density mode flag mov m,a lxi h,dpb128 ;Write a single density DPB call doubl0 ret ; ; Make the BIOS think we are looking at a double density disk ; double: mvi a,1 ;Set double density mode flag mov m,a lxi h,top ;Double density DPB doubl0: lxi b,16 ;Length of the DPB lded dpbptr ;Pointer to the BIOS's DPB ldir lda cdrive ;Reselect the currently selected drive lxi h,fromp call drvsel ret ; ; Allocate the buffers, calculate the number of sectors ; ; NUMBUF = (BIOS-DATBUF)/128 Number of data buffers in memory ; ; SYSIZE = OFF * SPT Number of sectors on the system tracks ; DATSIZ = (BLM+1) * (DSM+1) Number of sectors on the data tracks ; calc: lxi d,datbuf ;Start of data buffer area lhld bdos+1 ;Pointer to the top of the buffer area call hlmde ;HL = HL-DE mov a,h ;HL = HL/128 ral mov e,a mvi a,0 ral mov h,a mov a,l rlc ani 1 ora e mov l,a shld numbuf ;Save the number of data buffers lda inch8 ;Test for 8 inch drives ora a jrz gatn8 ;Skip if not 8 inch lxi d,26 ;26 sectors on track 0 lhld spt ;Track 1's size dad d jr gatcnt gatn8: lded off ;Number of system tracks lhld spt ;Sectors per track call hltde ;HL = HL*DE gatcnt: shld sysize ;Save the number of system sectors lded blm ;Number of sectors per block - 1 mvi d,0 ;BLM is a byte value inx d lhld dsm ;Number of blocks - 1 inx h call hltde ;HL = HL*DE shld datsiz ;Save the number of data sectors ret ; ; Select a drive name ; drvsel: mov c,a ;Drive to select xra a ;Set first time select mode sta firstf push h call select ;Select the drive pop d rc ;Return if an error occured mvi a,1 ;Set second time select mode sta firstf mov c,m ;Save the sectran table pointer inx h mov b,m sbcd stranp lxi b,9 ;Offset to the DPB pointer dad b mov a,m ;Load the DPB pointer inx h mov h,m mov l,a shld dpbptr ;Save for mucking with 8 inch drives lxi b,16 ;Copy the DPB ldir xra a ;Clear the error flag ret ; ; Select a drive ; select: mov a,c ;Save the currently select drive sta cdrive lda firstf ;Get the select flag mov e,a call seldsk ;Select the drive mov a,h ;Test for a select error ora l rnz ;Return if no error (carry clear) stc ;Set the error flag ret ; ; Get a drive name ; getdrv: push h ;save string address call puts ;Print the prompt string call conin ;Get a character push psw call crlf ;Echo a crlf pop psw pop h ;restore string address cpi 3 ;control-c jz exit call lower ;Convert to lower case cpi 'a' ;Test for an illegal reply jc getdrv ;do again if illegal cpi 'p'+1 jnc getdrv ;do again if illegal sui 'a' ;Convert to binary ret ; ; Serialize ALL MOVCPMs on the source drive ; domov: call sinit ;Initialize the serializer call find ;Find all the MOVCPM??.COM programs call locate ;Locate the serial number call serall ;Serialize the MOVCPM's ret ; ; Initialize ; sinit: mvi c,reset ;Reset the disk system call bdos lda to ;Destination drive name inr a ;Convert to CP/M format sta mname lxi h,'??' ;Set the wild characters shld mwild lxi h,list ;Reset the list pointer shld listp lxi h,16 ;Start at record 16 shld record+1 shld record ret ; ; Find all the MOVCPM's ; find: mvi c,sfirst ;Find the first name find0: lxi d,mname ;MOVCPM??.COM name call bdos cpi 255 ;At the end of the list? rz ;Return if so rlc ;Times 2 rlc ; 4 rlc ; 8 rlc ; 16 rlc ; 32 bytes per dir entry mov l,a ;Make a pointer to the name mvi h,0 lxi d,cpmbuf+(mwild-mname) ;Offset to the two wild bytes dad d lded listp ;Pointer to the name list mov a,m ;Copy a couple of bytes stax d inx d inx h mov a,m stax d inx d sded listp ;Save the pointer to the next name mvi c,snext ;Get the next name jr find0 ; ; Locate the serial number. ; locate: lhld list ;Get the first name mov a,h ;Test for a name present ora l jz locerr ;No MOVCPM program shld mwild ;Save in our FCB mvi c,fopen ;Open the file lxi d,mname call bdos cpi 4 ;Test for an open error jrnc locerr loca0: mvi c,rread ;Read a record lxi d,mname call bdos ora a ;Test for an error jrnz locnot lxi d,cpmbuf+10h ;The CCP's command list location call cmpstr ;Look for the name list rz ;RECORD now points to the right place lhld record ;Bump to the next record inx h shld record jr loca0 ;Read the next record locerr: lxi h,nofile ;File not found error jmp perror locnot: lxi h,noser ;Not a MOVCPM image jmp perror ; ; Serialize all the MOVCPM's found ; serall: lxi h,list ;Reset the list pointer shld listp sera0: call serbld ;Build a name rz ;Return if no more names mvi c,fopen ;Open a MOVCPM program lxi d,mname call bdos cpi 4 ;Test for an error jrnc sererr lxi d,10 ;Offset to the BDOS's serial # lxi h,cpmbuf+28h ;CCP's serial number location call serial ;Serialize the CCP jrc sererr lxi d,-10 ;Offset back to the CCP lxi h,cpmbuf+0 ;BDOS's serial number location call serial ;Serialize the BDOS jrc sererr mvi c,fclose ;Close the serialized file lxi d,mname call bdos cpi 4 ;Test for an error jrc sera0 ;Serialize the next MOVCPM sererr: lxi h,serbad ;Print a complaint call puts call prser call crlf jmp exit ; ; Build the next MOVCPM's name ; serbld: lhld listp ;Pointer to the name list mov e,m ;Get a name inx h mov d,m mov a,d ;Test for the end of the list ora e rz inx h ;Set up the pointer to the next name shld listp sded mwild ;Set up the name ret ; ; Serialize a record ; serial: push d ;Save the record offset push h ;Save the serial address mvi c,rread ;Read the record lxi d,mname call bdos pop h ;Recover the offset ora a ;Test for an error jrnz serirr call doser ;Write the serial number to the buffer mvi c,rwrite ;Write the record lxi d,mname call bdos ora a ;Test for an error jrnz serirr pop d ;Offset to the next record lhld record dad d shld record ora a ;Clear the error flag ret serirr: pop h ;Clean the stack stc ;Set an error mode ret ; ; Print a name ; prser: lxi h,mname+1 ;Pointer to the name mvi b,8 ;Print the first 8 characters call prser0 push h mvi e,'.' ;A period call conout pop h mvi b,3 ;Print the name type call prser0 ret prser0: push b ;Save the pointers and the count push h mov a,m ;Get a character cpi ' ' ;Do not print spaces jrz prser1 mov e,a ;Print a character call conout prser1: pop h ;Bump the pointers and counts pop b inx h djnz prser0 ret ; ; Locate the serial number in the buffer, serialize it ; sersys: lxi d,datbuf ;First look for the names lbcd sysize ;Bump of record to look at sers0: push b ;Save the record count push d ;Save the buffer pointer lxi h,10h ;Offset to the name list dad d xchg call cmpstr pop d pop b jrz sers1 ;Found the name list start serilization lxi h,80h ;Bump to the next record dad d xchg dcx b ;Bump the record count mov a,b ora c jrnz sers0 ;Inspect the next record lxi h,nosys ;No CP/M system present jmp perror sers1: push d ;Save record pointer for now lxi h,28h ;Offset to the CCP's serial number dad d call doser ;Write the serial number pop d lxi h,500h ;Offset to the BDOS's serial number dad d call doser ret ; ; Look for the name list ; cmpstr: mvi b,comlen ;Command of the command list lxi h,comlst ;Our idea of the CCP's command list cmps0: ldax d ;Get a byte from the buffer cmp m ;Test against our image rnz ;Return if different inx d ;Bump the string pointers inx h djnz cmps0 ;Test the next byte ret ; ; Write the serial number ; doser: mvi m,34 ;We are OEM # 34 inx h mvi m,cpmver ;CP/M version number inx h lded sernum+2 ;get serial hi mov m,d inx h mov m,e inx h lded sernum ;Get the serial number lo mov m,d ;High byte first inx h mov m,e ret ; ; Input a character from the console, handle control C ; conin: mvi c,cin ;Use the BDOS's console input call bdos cpi cntlc ;Test for control C rnz lxi h,cntrlc ;Echo ^C jmp perror ; ; Convert a character to lower case ; lower: cpi '@' ;Test for a letter rc ori 20h ret ; ; Termination routine ; exit: lxi h,goodby ;Print closing message call puts mvi c,cin ;Wait for a character call bdos lda inch8 ;Test for 8 inch drives ora a cnz double ;Set up double density mode lda savdrv ;Reselect the old drive sta cpmdrv call crlf ;Print a final CRLF jmp warm ;Do a warm boot ; ; Fetch a number ; getnum: push h ;Save the pointer to the text call puts ;Print the message call gets ;Get the number call crlf ;Echo a CRLF call get32 ;Convert to binary pop h ;Get the message pointer rnc ;Return if get32 was ok jr getnum get32: ;convert 9-digit number at verbuf to 32-bit binary, ;exit [de],[bc]= number hi,lo lxi b,0 ;lo lxi d,0 ;hi lxi h,verbuf+1 ;string mov a,m ;length ora a ;test null rz ;exit with 0 if null cpi 10 ;9 digits is legal, 10 is not jnc badnum ;error inx h ;first character jr get32b ;continue get32a: pop h pop psw dcr a ora a ;carry=0 rz ;exit done get32b: push psw mov a,m ;get char inx h ;next push h ;save pointer sui '0' ;remove ascii offset jrc badnum2 cpi 10 jrnc badnum2 ;exit if not decimal push psw call x10 pop psw add c ;add this digit mov c,a ; jrnc get32a ;if carry inr b ;b++ jrnz get32a inr e jrnz get32a inr d jrnz get32a badnum2: pop h pop h badnum: lxi h,numerr call puts stc ret ;exit with error x10: ;multiply 32-bit number in [DE],[BC] (hi,lo) by 10 mov h,d mov l,e push h ;hi at (SP) mov h,b mov l,c ;lo in [hl] dad h ;*2 xthl dach xthl dad h ;*4 xthl dach xthl dad b ;*5 xthl dacd xthl dad h ;*10 xthl dach xthl mov b,h mov c,l ;overwrite entry lo pop h mov d,h mov e,l ret ;exit [de],[bc] *10 puthl: ;output hl to console lxi d,0 ;leading zeros xchg ;swap order, [hl]=lo jr out32 ;output it outser: ;output serial number lhld sernum ;lo serial xchg lhld sernum+2 ;hi serial out32: ;output 32-bit number in [HL],[DE] (hi,lo) to console, radix 10 xra a ;end of stack mark = z = 1 push psw outse0: lxi b,10 ;/10 call divide ;bc=digit mov a,c ;get digit ori '0' ;make ascii push psw ;save for print, z=0 mov a,h ora l ora e ora d ;test all bits jrnz outse0 ;until done outse1: pop psw rz ;exit when done, flag set above mov e,a call conout ;print digit jr outse1 ;do 'til done divide: ;divide 32-bit number in [hl],[de] (hi,lo) by [bc] ;on exit, [hl],[de] are 32-bit quotient, [bc] is remainder xchg ;get lo dad h ;*2 xchg dach ;mid *2 push h ;mid on stack lxi h,0 ;init hi mvi a,32 ;32 bits divid0: dach ;hi *2 push h ;save in case borrow ora a ;clear borrow sbbb ;sbc hl,bc ;hi=hi-divisor cmc ;invert borrow for shift later jrc divid1 ;if borrow { pop h ;replace with original hi push h ;stack phase divid1: inx sp inx sp ;drop xchg ;get lo dach ;lo *2 + remainder xchg xthl ;get mid dach ;mid *2 + lo overflow (remainder here) xthl ;cy = hi-bit of mid dcr a ;count-- jrnz divid0 ;while not done, loop mov b,h mov c,l ;remainder in [bc] pop h ;restore mid (now hi) ret ; ; Print a CRLF ; crlf: lxi h,crlfs ;CRLF string call puts ret ; ; Print an error message ; perror: call puts jmp exit ; ; Print [hl] to the console ; puts: xchg mvi c,print jmp bdos ;exit to caller ; ; Print a character ; conout: mvi c,cout ;The BDOS's console output function call bdos ret gets: lxi d,verbuf ;Set up a data buffer mvi a,80 ;80 characters stax d mvi c,bufin ;Do CP/M buffered input call call bdos ret ************************************************************************* * * * 16 bit routines * * * * name input output side description * * * * hlmde DE HL HL A HL = HL - DE * * hlcde DE HL A HL - DE * * hltde DE HL HL ABCDE HL = HL * DE * * * ************************************************************************* ************************************************************************* * * * Hlmde subtracts DE from HL and returns. * * * ************************************************************************* hlmde: mov a,l sub e mov l,a mov a,h sbb d mov h,a ret ************************************************************************* * * * Hlcdå compareó HÌ witè DE® Oî returî thå Ú flaç ió seô iæ theù * * arå equal¬ thå Carrù flaç ió seô iæ DE ió greater thaî HL® * * * ************************************************************************* hlcde: mov a,h cmp d rnz mov a,l cmp e ret ************************************************************************* * * * Multiply the contents of HL by the contents of DE. * * * ************************************************************************* hltde: mov c,l mov b,h lxi h,0 mult: mov a,b ora c rz mov a,b rar mov b,a mov a,c rar mov c,a cc dadde xchg dad h xchg jr mult dadde: dad d ret ; ; Messages ; signon: db cr, lf, lf db ' Morrow Designs CP/M v2.2 Universal Serialization.', cr, lf db ' Revision ' db revnum/10+'0', '.', revnum mod 10+'0' db cr,lf,lf,eom strser: dâ 'Enteò thå startinç seriaì number, (9 digits max)º '¬ eom strcnt: db 'How many disks do you want to serialize? ', eom numerr: db 'Illegal reply, try again', cr, lf, eom source: db 'Enter the source drive name or to quit: ', eom dest: db 'Enter the destination drive name or to quit: ', eom ready0: db '(', eom ready1: db ') Press when ready to serialize 34-', eom ready2: db ': ', eom badcmp: db 'Error, sector sizes are different', cr, lf, lf, eom baddrv: db 'Error, selecting drive ' baddr0: db 'A:', cr, lf, lf, eom alldon: db 'Copy and serialization complete, no errors.', cr, lf, lf, eom errm0: db 'Unrecoverable ', eom readr: db 'read', eom writer: db 'write', eom verifr: db 'verify', eom datcmp: db 'data compare', eom errm1º dâ § erroò oî drivå ' errm2: db 'X:, track ', eom errm3: db ', sector ', eom errm4: db '.', cr, lf db 'Press to ignore or any other character to quit: ', eom goodby: db cr, lf, lf, 'Load the system disk, press when ready: ' db eom cntrlc: db '^C', eom crlfs: db cr, lf, eom ; ; Data ; savdrv: db 0 ;Saved CP/M drive # cdrive: db 0 ;Currently selected drive freem: dw 0 ;Available buffer space numbuf: dw 0 ;Number of data buffers sysize: dw 0 ;Number of SYSTEM sectors datsiz: dw 0 ;Number of DATA sectors ;Source drive parameters sparam: dw 0 ;Track position dw 0 ;Sector position db 0 ;Density ;Destination drive parameters dparam: dw 0 ;Track dw 0 ;Sector db 0 ;Density ;Verification drive parameters vparam: dw 0 ;Track dw 0 ;Sector db 0 ;Density param: dw 0 ;Current parameter table pointer allocw: db 0 ;Alocated write mode flag dmaddr: dw 0 ;Current DMA address track: dw 0 ;Current track address sector: dw 0 ;Current sector address stranp: dw 0 ;Sector translation table pointer tsectr: dw 0 ;Current translated sector maxsec: dw 0 ;Number of sectors to copy numsec: dw 0 ;Number of sectors left to copy inch8: db 0 ;Set for 8 inch floppies densty: db 0 ;Double density mode flag firstf: db 0 ;0 on first select, then 1 same: db 0 ;Non-zero when copying to self drive: db 0 ;Drive we are copying from/to odrive: dw 0 ;Pointer to swap messages hlsav: dw 0 ;Saved number used during printer ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and single sided. * * * ***************************************************************** dpb128: dw 26 ;CP/M sectors/track db 3 ;BSH db 7 ;BLM db 0 ;EXM dw 242 ;DSM dw 63 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 16 ;CKS dw 2 ;OFF db 1 ;128 byte sectors dpbptr: dw 0 ;Pointer to the BIOS's DPB oldxlt: dw 0 ;Saved XLT pointer from: db 0 ;Source drive name fromp: equ $ ;Drives DPB spt: dw 0 ;Sectors per track bsh: db 0 ;Block shift factor blm: db 0 ;Block limit exm: db 0 ;Extent mask dsm: dw 0 ;Disk size maximum drm: dw 0 ;Directory size maximum al0: db 0 ;Directory allocation 0 al1: db 0 ;Directory allocation 1 cks: dw 0 ;Number of checked directory entries off: dw 0 ;Directory offset siz: db 0 ;Sector size code to: db 0 ;Destination drive name top: ds 16 ;Drives DPB ; ; BIOS jump table ; cold: jmp $ ;Cold boot warm: jmp $ ;Warm Boot jmp $ ;Console status jmp $ ;Console input jmp $ ;Console output jmp $ ;Printer output jmp $ ;Punch output jmp $ ;Reader output jmp $ ;Home drive seldsk: jmp $ ;Select drive settrk: jmp $ ;Set track setsec: jmp $ ;Set sector setdma: jmp $ ;Set DMA address read: jmp $ ;Read a sector write: jmp $ ;Write a sector jmp $ ;List status sectran:jmp $ ;Sector translation ; ; Serialization data ; sernum: dw 0,0 ;Current serial number dcount: dw 0 ;Disk down counter scount: dw 0 ;Disk up counter sysmod: db 0 ;Flag to for buffer serialization nocopy: db 0 ;Flag to indicate no disk duplication ; ; MOVCPM name used for lookups ; mname: db 0, 'MOVCPM' ;MOVCPM name prefix mwild: db '??' ;The wild characters db 'COM' ;The name type db 0, 0, 0, 0 ;FCB info dw 0, 0, 0, 0, 0, 0, 0, 0 db 0 record: db 0, 0, 0 ;Random record address ; ; Name list ; listp: dw list ;Pointer to the name list list: dw 0, 0, 0, 0, 0, 0, 0, 0, 0 ;Space for 8 MOVCPM'S comlst: db 'DIR ERA TYPESAVEREN USER' ;CCP commands comlen equ $-comlst ;Length of CCP commands list ; ; Messages ; nofile: db 'File not found, no serialization.', cr, lf, eom noser: db 'MOVCPM??.COM is not properly formatted, no serialization.' db cr, lf, eom serbad: db 'Error in serializing: ', eom nosys: db 'Error, Can''t find the CP/M system', cr, lf, eom ; ; THE STACK ; ds 50 stack equ $ ; ; Disk data buffers ; verbuf equ $ ;Verify buffer datbuf equ verbuf+secsiz ;Data buffers end