Title 'CP/M 3 Serialization Program (27_Jan_84)' ; ; Copyright (c) 1982 ; Morrow Designs, Inc ; San Leandro, Ca ; ;This program was assembled with MAC from Digital Research. ; ; 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 ; c. cp/m3 serialization ; see "ser30:' ; Modified by H. Fullmer Jan. 1984 ; ;format of six-byte serial number is: ; oem-lo,product,oem-hi,24-bit serial number ; in new products this field may be preceeded by a field of ; (ascii) '0000-XXXX-' ; ;---------------------------------------------------------------------- ; Equates ;-------- ; ; Constants ;---------- ; revnum equ 14 ;Revision 1.4 cpm3ver equ 30 ;cpm3 product code secsiz equ 128 ;128 byte/sector eom equ 24h ;string terminator ; Addresses ;---------- ; warm equ 0 ;Warm boot address bios equ 0 ;Jmp to the BIOS jump table bdos equ 5 ;System entry address cpmdrv equ 4 ;CP/M drive # tpa equ 0100h ;Start of the TPA ; Bdos Function Numbers ;---------------------- cin equ 1 ;Cosole input cout equ 2 ;Console output print equ 9 ;string output bufin equ 10 ;Buffered input 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 setdma equ 26 ;Set DMA address rread equ 33 ;Random read rwrite equ 34 ;Random write resdrv equ 37 ;Reset drive ; Define character constants ;--------------------------- ; cntlc equ 'C'-64 ;Control C lf equ 'J'-64 ;Line feed cr equ 'M'-64 ;Carraige return page ;---------------------------------------------------------------------- ; 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 page ;---------------------------------------------------------------------- ; The Main Line (Kupper's gone) ;------------------------------ ; org tpa lxi sp,stack ;Set up the stack call init ;Set up the environment dover: lxi sp,stack call ready ;Setup the disks jrc dover call domov ;Serialize the movcpm's againx: call again ;Set up for the next copy jr dover ;Do copy over ;---------------------------------------------------------------------- ; INIT - Set up the environment ;---------------------- ; init: lda cpmdrv ;Save the CP/M drive number sta savdrv 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 init0: lxi h,source ;Get the source drive name call getdrv sta drive call crlf ;All done ret ;---------------------------------------------------------------------- ; READY - 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 jnz exit call crlf ;Echo a LF ret ;---------------------------------------------------------------------- ; AGAIN - Set up for the next copy ;--------------------------------- ; again: lxi h,alldon ;Serialization of this disk is complete call puts xra a sta serflag 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 mov a,h ;check for number larger than 24 bits ora a jz again0 call crlf call outser lxi h,toobig call perror jmp exit toobig: db 0dh,0ah,'Serial number to big, : $' 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 page ;---------------------------------------------------------------------- ; GETDRV - Get a drive name ;-------------------------- ; getdrv: call puts ;Print the prompt string gdrv2: call conin ;Get a character push psw call crlf ;Echo a crlf pop psw cpi 3 ;^c is legal exit jz exit call lower ;Convert to lower case cpi 'a' ;Test for an illegal reply jc gdrv2 ;Quit on an illegal reply cpi 'p'+1 jnc gdrv2 ;Quit on an illegal reply sui 'a' ;Convert to binary ret ;---------------------------------------------------------------------- ; DOMOV - Serialize necessary files on the source drive ;------------------------------------------------------ ; domov: jmp ser30a ; Serialization Table ;-------------------- ; edit the following table to add/subtract names (UPPER CASE) ; .SYS files are examined and serialized 2 or 3 times ser3tbl: db 9 ;number of files db 'CPM3 SYS' ;must be first file name in list dw 35h db 'BNKBDOS3SPR' ;name of file dw 100h ;address to serialize in file db 'RESBDOS3SPR' dw 100h db 'MAC COM' dw 10fah db 'RMAC COM' dw 0a2h db 'LINK COM' dw 81h db 'LIB COM' dw 81h db 'SID COM' dw 7ah db 'CPM3F SYS' dw 35h ; Serialization Program ;---------------------- ; ser30a: call sinit mvi a,cpm3ver sta cpmver lxi h,ser3tbl mov b,m ;get count of files inx h ;point at a name ser30b: push b ;save file count lxi d,fcb+1 ;file fcb name area lxi b,11 ;name length ldir mvi a,0 stax d mov e,m inx h mov d,m inx h ;get byte offset push h ;save file list pointer mov h,d mov l,e ;hl=address to serialize mov a,e ;preserve offset in record dad h ;h=record number mov l,h mvi h,0 jnc ser30bb inr h ;allow 512 records ser30bb: push psw push h lxi d,fcb ;file name mvi c,fopen ;open file call bdos ora a jm locerr ;print error, exit pop h pop psw call ser3file ;serialize a file lda fcb+10 ;mid char in file_type ani 7fh ;reset [SYS] flag bit cpi 'Y' ;.SYS? jnz ser30c ;Start of CPM3.SYS File Serialization lxi h,0 ;record 0 shld record mvi c,rread ;read header record lxi d,fcb call bdos lda cpmbuf+3 ;banked part page mov b,a lda cpmbuf+1 ;res part mov e,a mov c,a push b ;save for banked part mvi d,0 lxi h,1 dad d dad d push h mvi a,0 call ser3file ;serialize res part pop h pop b mov a,b ;banked part ora a jz ser30c ;if = 0 , not banked .sys file mov c,a mvi b,0 dad b ;[hl] = number of records in banked dad b ;[hl] = record #-1 of banked serial mvi a,0 call ser3file ;serialize banked part ser30c: lxi d,fcb mvi c,fclose call bdos ;close file pop h ;file list pointer pop b ;file count dcr b ;count-- jnz ser30b ret ;serialized all files page ;---------------------------------------------------------------------- ; SER3FILE ;--------- ; ser3file: shld record ;set random record ani 7fh ;set offset in record push psw ;save lxi d,fcb mvi c,rread ;random read call bdos ora a jnz locerr1 ;print error, exit pop psw ;restore address lxi h,cpmbuf ;dma area add l mov l,a jnc ser30cc inr h ser30cc: lda serflag ora a jnz ser30cd ;no checking call ck123456 jz ser30cd mvi a,1 sta serflag push h lxi h,badser ;file already serialized call puts pop h push h mov e,m mvi d,0 lxi h,0 call out32 ;print oem number mvi e,'-' call conout pop h push h lxi d,5 dad d mov e,m dcx h mov d,m dcx h mov a,m dcx h mov h,m mov l,a call out32 ;print existing serial lxi h,badok call puts call gets lda verbuf+2 call lower cpi 'y' pop h jz ser30cd jmp againx badser: db 0dh,0ah,'Disk has been serialized with number: $' badok: db 0dh,0ah,'Want to re-serialize? $' ser30cd: call doser ;serialize buffer lxi d,fcb mvi c,rwrite call bdos ;write buffer ret ;---------------------------------------------------------------------- ; CK123456 - ;----------- ; ck123456: push h lxi d,c123456 mvi b,6 ck: ldax d cmp m jnz ck1 inx h inx d djnz ck ck1: pop h ret c123456: db '654321' ;---------------------------------------------------------------------- ; SINIT - Initialize ;------------------- ; sinit: mvi c,setdma ;set dma function lxi d,cpmbuf ;pointer to buffer call bdos ;set dma address lda drive ;get drive inr a sta fcb mov b,a ;b=drive mvi a,80h ;one bit for one drive rlop: rlc ;rotate bit djnz rlop ;loop mov e,a ;lo - byte of vector mvi d,0 ;hi - byte of vector mvi c,resdrv ;Reset the drive call bdos ret ;---------------------------------------------------------------------- ; PRSER - Print a name ;--------------------- ; prser: lxi h,fcb+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 page ;---------------------------------------------------------------------- ; DOSER - Write the serial number ;-------------------------------- ; doser: mvi m,34 ;We are OEM # 34 inx h lda cpmver mov m,a ;cp/m product code inx h lded sernum+2 ;get serial hi ; mov m,d mvi m,0 ;hardwire oem-hi = 0 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 page ;---------------------------------------------------------------------- ; CONIN - 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 ;---------------------------------------------------------------------- ; LOWER - Convert a character to lower case ;------------------------------------------ ; lower: cpi '@' ;Test for a letter rc ori 20h ret ;---------------------------------------------------------------------- ; EXIT - Termination routine ;--------------------------- ; exit: lxi h,goodby ;Print closing message call puts mvi c,cin ;Wait for a character call bdos lda savdrv ;Reselect the old drive sta cpmdrv call crlf ;Print a final CRLF jmp warm ;Do a warm boot ;---------------------------------------------------------------------- ; GETNUM - 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 ;clamp number at 24-bits 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 ;32 bits ; 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 locerr1: call prerr lxi h,bdfile ;File bad error call puts xra a sta fcb+12 jmp 0 locerr: call prerr lxi h,nofile ;File not found error call puts xra a sta fcb+12 pop h pop psw jmp ser30c prerr: mvi a,'$' sta fcb+12 call crlf lxi h,fcb+1 call puts ret ; ; Messages ; signon: db cr, lf, lf db ' Morrow Designs CP/M serialization.', cr, lf db ' For CP/M Plus v3.x', cr, lf db ' Revision ' db revnum/10+'0', '.', revnum mod 10+'0', cr, lf, lf, eom strser: dâ 'Enteò thå startinç seriaì number (7 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 control-C to quit: ', eom dest: db 'Enter the destination drive name or control-c to quit: ', eom self: db 'Can''t copy to self', cr, lf, lf, 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 # drive: db 0 ;Drive we are copying from/to hlsav: dw 0 ;Saved number used during printer ; ; Serialization data ; sernum: dw 0,0 ;Current serial number cpmver: db 0 ;product code dcount: dw 0 ;Disk down counter scount: dw 0 ;Disk up counter serflag:db 0 ;1=don't check for 654321 in 3.0 ; ; FCB for file operations ; fcb: db 0, ' ' ;File name db ' ' ;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 ; ; Messages ; nofile: db ' File not found, no serialization.', cr, lf, eom bdfile: db ' File defective, serialization terminated.', 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 ; cpmbuf equ ($ and 0ff00h)+100h ;move to page boundry verbuf equ cpmbuf + 100h end