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 orginally 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 jr z,macro addr ! dorel 28h, addr endm jr nz,macro addr ! dorel 20h, addr endm jr c,macro addr ! dorel 38h, addr endm jr nc,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 ld sp,stack ;Set up the stack call init ;Set up the environment dover: ld sp,stack call ready ;Setup the disks jr c,dover call dold ;Serialize the ldcpm's againx: call again ;Set up for the next copy jr dover ;Do copy over ;---------------------------------------------------------------------- ; INIT - Set up the environment ;---------------------- ; init: ld a,(cpmdrv) ;Save the CP/M drive number ld (savdrv),a ld hl,signon ;Print signon call puts ld hl,strser ;Get the starting serial number call getnum sbcd sernum ;lo sded sernum+2 ;hi ld hl,strcnt ;Get the disk count call getnum sbcd dcount ;lo ld hl,1 ;Start the up count at 1 ld (scount),hl call crlf init0: ld hl,source ;Get the source drive name call getdrv ld (drive),a call crlf ;All done ret ;---------------------------------------------------------------------- ; READY - Set up the drives ;-------------------------- ; ready: ld hl,ready0 ;'(' message call puts ld hl,(scount) ;Print the current disk number call puthl ld hl,ready1 ;') Press ...' message call puts call outser ;Print the serial number ld hl,ready2 ;': ' message call puts call conin ;Wait for a cpi cr jp nz,exit call crlf ;Echo a LF ret ;---------------------------------------------------------------------- ; AGAIN - Set up for the next copy ;--------------------------------- ; again: ld hl,alldon ;Serialization of this disk is complete call puts xra a sta serflag ld hl,(sernum) ;Bump the serial number inx h ld (sernum),hl ld a,h or l jr nz,again0 ld hl,(sernum+2) inx h ld (sernum+2),hl ld a,h ;check for number larger than 24 bits or a jp z,again0 call crlf call outser ld hl,toobig call perror jmp exit toobig: db 0dh,0ah,'Serial number to big, : $' again0: ld hl,(scount) ;Bump the up counter inx h ld (scount),hl ld hl,(dcount) ;Bump the down counter dcx h ld (dcount),hl ld a,h ;Test for the end or 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 jp z,exit call lower ;Convert to lower case cpi 'a' ;Test for an illegal reply jc gdrv2 ;Quit on an illegal reply cpi 'p'+1 jp nc,gdrv2 ;Quit on an illegal reply sui 'a' ;Convert to binary ret ;---------------------------------------------------------------------- ; DOMOV - Serialize necessary files on the source drive ;------------------------------------------------------ ; dold: 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 ld a,cpm3ver sta cpmver ld hl,ser3tbl ld b,m ;get count of files inx h ;point at a name ser30b: push b ;save file count ld de,fcb+1 ;file fcb name area ld bc,11 ;name length ldir ld a,0 stax d ld e,m inx h ld d,m inx h ;get byte offset push h ;save file list pointer ld h,d ld l,e ;hl=address to serialize ld a,e ;preserve offset in record dad h ;h=record number ld l,h ld h,0 jp nc,ser30bb inc h ;allow 512 records ser30bb: push psw push h ld de,fcb ;file name ld c,fopen ;open file call bdos or a jm locerr ;print error, exit pop hl pop psw call ser3file ;serialize a file lda fcb+10 ;mid char in file_type ani 7fh ;reset [SYS] flag bit cpi 'Y' ;.SYS? jp nz,ser30c ;Start of CPM3.SYS File Serialization ld hl,0 ;record 0 ld (record),hl ld c,rread ;read header record ld de,fcb call bdos lda cpmbuf+3 ;banked part page ld b,a lda cpmbuf+1 ;res part ld e,a ld c,a push b ;save for banked part ld d,0 ld hl,1 dad d dad d push h ld a,0 call ser3file ;serialize res part pop hl pop bc ld a,b ;banked part or a jp z,ser30c ;if = 0 , not banked .sys file ld c,a ld b,0 dad b ;[hl] = number of records in banked dad b ;[hl] = record #-1 of banked serial ld a,0 call ser3file ;serialize banked part ser30c: ld de,fcb ld c,fclose call bdos ;close file pop hl ;file list pointer pop bc ;file count dcr b ;count-- jp nz,ser30b ret ;serialized all files page ;---------------------------------------------------------------------- ; SER3FILE ;--------- ; ser3file: ld (record),hl ;set random record ani 7fh ;set offset in record push psw ;save ld de,fcb ld c,rread ;random read call bdos or a jp nz,locerr1 ;print error, exit pop psw ;restore address ld hl,cpmbuf ;dma area add l ld l,a jp nc,ser30cc inc h ser30cc: lda serflag or a jp nz,ser30cd ;no checking call ck123456 jp z,ser30cd ld a,1 sta serflag push h ld hl,badser ;file already serialized call puts pop hl push h ld e,m ld d,0 ld hl,0 call out32 ;print oem number ld e,'-' call conout pop hl push h ld de,5 dad d ld e,m dcx h ld d,m dcx h ld a,m dcx h ld h,m ld l,a call out32 ;print existing serial ld hl,badok call puts call gets lda verbuf+2 call lower cpi 'y' pop hl jp z,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 ld de,fcb ld c,rwrite call bdos ;write buffer ret ;---------------------------------------------------------------------- ; CK123456 - ;----------- ; ck123456: push h ld de,c123456 ld b,6 ck: ldax d cmp m jp nz,ck1 inx h inx d djnz ck ck1: pop hl ret c123456: db '654321' ;---------------------------------------------------------------------- ; SINIT - Initialize ;------------------- ; sinit: ld c,setdma ;set dma function ld de,cpmbuf ;pointer to buffer call bdos ;set dma address lda drive ;get drive inc a sta fcb ld b,a ;b=drive ld a,80h ;one bit for one drive rlop: rlc ;rotate bit djnz rlop ;loop ld e,a ;lo - byte of vector ld d,0 ;hi - byte of vector ld c,resdrv ;Reset the drive call bdos ret ;---------------------------------------------------------------------- ; PRSER - Print a name ;--------------------- ; prser: ld hl,fcb+1 ;Pointer to the name ld b,8 ;Print the first 8 characters call prser0 push h ld e,'.' ;A period call conout pop hl ld b,3 ;Print the name type call prser0 ret prser0: push b ;Save the pointers and the count push h ld a,m ;Get a character cpi ' ' ;Do not print spaces jr z,prser1 ld e,a ;Print a character call conout prser1: pop hl ;Bump the pointers and counts pop bc inx h djnz prser0 ret page ;---------------------------------------------------------------------- ; DOSER - Write the serial number ;-------------------------------- ; doser: ld m,34 ;We are OEM # 34 inx h lda cpmver ld m,a ;cp/m product code inx h lded sernum+2 ;get serial hi ; ld m,d ld m,0 ;hardwire oem-hi = 0 inx h ld m,e inx h lded sernum ;Get the serial number lo ld m,d ;High byte first inx h ld m,e ret page ;---------------------------------------------------------------------- ; CONIN - Input a character from the console, handle control C ;------------------------------------------------------------- ; conin: ld c,cin ;Use the BDOS's console input call bdos cpi cntlc ;Test for control C rnz ld hl,cntrlc ;Echo ^C jmp perror ;---------------------------------------------------------------------- ; LOWER - Convert a character to lower case ;------------------------------------------ ; lower: cpi '@' ;Test for a letter rc or 20h ret ;---------------------------------------------------------------------- ; EXIT - Termination routine ;--------------------------- ; exit: ld hl,goodby ;Print closing message call puts ld 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 hl ;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 ld bc,0 ;lo ld de,0 ;hi ld hl,verbuf+1 ;string ld a,m ;length or a ;test null rz ;exit with 0 if null cpi 10 ;9 digits is legal, 10 is not jp nc,badnum ;error inx h ;first character jr get32b ;continue get32a: pop hl pop psw dcr a or a ;carry=0 rz ;exit done get32b: push psw ld a,m ;get char inx h ;next push h ;save pointer sui '0' ;relde ascii offset jr c,badnum2 cpi 10 jr nc,badnum2 ;exit if not decimal push psw call x10 pop psw add c ;add this digit ld c,a ; jr nc,get32a ;if carry inc b ;b++ jr nz,get32a inc e jr nz,get32a ; inc d ;32 bits ; jr nz,get32a badnum2: pop hl pop hl badnum: ld hl,numerr call puts stc ret ;exit with error x10: ;multiply 32-bit number in [DE],[BC] (hi,lo) by 10 ld h,d ld l,e push h ;hi at (SP) ld h,b ld 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 ld b,h ld c,l ;overwrite entry lo pop hl ld d,h ld e,l ret ;exit [de],[bc] *10 puthl: ;output hl to console ld de,0 ;leading zeros xchg ;swap order, [hl]=lo jr out32 ;output it outser: ;output serial number ld hl,(sernum) ;lo serial xchg ld hl,(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: ld bc,10 ;/10 call divide ;bc=digit ld a,c ;get digit or '0' ;make ascii push psw ;save for print, z=0 ld a,h or l or e or d ;test all bits jr nz,outse0 ;until done outse1: pop psw rz ;exit when done, flag set above ld 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 ld hl,0 ;init hi ld a,32 ;32 bits divid0: dach ;hi *2 push h ;save in case borrow or a ;clear borrow sbbb ;sbc hl,bc ;hi=hi-divisor cmc ;invert borrow for shift later jr c,divid1 ;if borrow { pop hl ;replace with orginal 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-- jr nz,divid0 ;while not done, loop ld b,h ld c,l ;remainder in [bc] pop hl ;restore mid (now hi) ret ; ; Print a CRLF ; crlf: ld hl,crlfs ;CRLF string call puts ret ; ; Print an error message ; perror: call puts jmp exit ; ; Print [hl] to the console ; puts: xchg ld c,print jmp bdos ;exit to caller ; ; Print a character ; conout: ld c,cout ;The BDOS's console output function call bdos ret gets: ld de,verbuf ;Set up a data buffer ld a,80 ;80 characters stax d ld 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: ld a,l sub e ld l,a ld a,h sbb d ld 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: ld a,h cmp d rnz ld a,l cmp e ret ************************************************************************* * * * Multiply the contents of HL by the contents of DE. * * * ************************************************************************* hltde: ld c,l ld b,h ld hl,0 mult: ld a,b or c rz ld a,b rar ld b,a ld a,c rar ld c,a cc dadde xchg dad h xchg jr mult dadde: dad d ret locerr1: call prerr ld hl,bdfile ;File bad error call puts xra a ld (fcb+12),a jmp 0 locerr: call prerr ld hl,nofile ;File not found error call puts xor a ld (fcb+12),a pop hl pop psw jmp ser30c prerr: ld a,'$' ld (fcb+12),a call crlf ld hl,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 ;lde to page boundry verbuf equ cpmbuf + 100h end