CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   1


                        ; Use   "gencmd serial data[m100]" when producing CMD file

                        ; print control constants

   000D                 cr              equ     00Dh    ; carriage return
   000A                 lf              equ     00Ah    ; line feed
   0007                 bell            equ     007h    ; self-explanatory
   0008                 bs              equ     008h    ; backspace
   000B                 vt              equ     00Bh    ; vertical tab

                        ; ccpm call function codes

   00E0                 ccpm            equ     224     ; ccpm interrupt

   0001                 c_read          equ      1      ; request single character from console
   0002                 c_write         equ      2      ; send single character to console
   0009                 c_writebuf      equ      9      ; print string terminated by '$'
   001F                 drv_dpb         equ     31      ; get DBP offset and segment base
   000D                 drv_resetall    equ     13      ; reset disk system
   000E                 drv_set         equ     14      ; select disk drive reg DL=disk #
                                                        ;  (0=A,1=B,etc.)
   0035                 mc_max          equ     53      ; find available memory space

                        ; bdos function codes for direct BIOS calls

   0032                 s_bios          equ     50      ; direct BIOS call function code
   000D                 read_code       equ     13      ; read a 128 byte sector
   000E                 write_code      equ     14      ; write a 128 byte sector

                        ; program constants

   00E5                 blank           equ     0E5h    ; data which an empty (blank)
                                                        ;  sector will contain
   FFFF                 false           equ     -1
   0000                 true            equ      0

                                cseg

                        start:
                        ; init serial_number
 0000 B90600                    mov     cx,length ser_def
 0003 B030                      mov     al,'0'
 0005 BBA508                    mov     bx,offset serial_number
                        initlop10:
 0008 8807                      mov     byte ptr[bx],al
 000A 43                        inc     bx
 000B E2FB         0008         loop    initlop10

                        ; give sign on
 000D E88205       0592         call    clear                   ; clear the monitor screen
 0010 BAD902                    mov     dx,offset msg0          ; print sign on message
 0013 E87705       058D         call    pmsg
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   2



                        ; prompt operator for source and destination drives
 0016 BAC604                    mov     dx,offset msg12         ; send source message to
 0019 E87105       058D         call    pmsg                    ;  console
 001C E88105       05A0         call    get_char                ; get disk code
 001F 2C41                      sub     al,'A'                  ; correct it
 0021 A23601                    mov     dskS,al                 ; store code for source disk
 0024 BAE804                    mov     dx,offset msg13         ; send destination message
 0027 E86305       058D         call    pmsg                    ;  to console
 002A E87305       05A0         call    get_char                ; get disk code
 002D 2C41                      sub     al,'A'                  ; correct it
 002F A23701                    mov     dskD,al                 ; store code for dest disk

                        ; prompt operator for source disk
 0032 BA0E05                    mov     dx,offset msg14         ; send message
 0035 E83B05       0573         call    pmsg_wait       

                        ; the reset function clears out any previous information pertaining
                        ;  to format, sector size, density, etc. and the next time a disk is
                        ;  selected those values will be reinitialized.
 0038 B10D                      mov     cl,drv_resetall         ; reset disks
 003A CDE0                      int     ccpm

                        ; when a disk is selected, CP/M initializes the Disk Parameter Header
                        ;  and the Disk Parameter Block to conform with the format of the
                        ;  selected disk.
 003C A03601                    mov     al,dskS                 ; select source disk
 003F A20601                    mov     disk,al
 0042 B132                      mov     cl,s_bios
 0044 BA0501                    mov     dx,offset sel_dsk_tab
 0047 CDE0                      int     ccpm

                        ; when the "select disk" function is performed using a direct BIOS call
                        ;  the offset of the DPH (in system's extra segment) is returned in the
                        ;  BX register.  the first word of the DPH is the offset of the sector
                        ;  translation table for the system.
 0049 891E4A01                  mov     xlt_offset,bx           ; save offset of system's
                                                                ;  sector translation table

                        ; move DPB into program data area
 004D FC                        cld
 004E B11F                      mov     cl,drv_dpb              ; get system extra segment
 0050 CDE0                      int     ccpm                    ;  value and offset of DPB
 0052 06                        push    es                      ; save ES value
 0053 8BF3                      mov     si,bx                   ; init source pointer
 0055 8E060900                  mov     es,data_base
 0059 BF3B01                    mov     di,offset DPB
 005C 1F                        pop     ds                      ; get system extra seg into DS
 005D B90F00                    mov     cx,15                   ; init byte counter
 0060 F3A4                      rep  movsb
 0062 1E                        push    ds                      ; save system extra seg value
 0063 06                        push    es                      ; restore DS value
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   3


 0064 1F                        pop     ds

                        ; get system sector translation table into data segment of program
 0065 07                        pop     es                      ; recover extra seg value
 0066 8B1E4A01                  mov     bx,xlt_offset           ; get offset of trans table
 006A 268B37                    mov     si,es:word ptr[bx]      ;  into SI      
 006D 85F6                      test    si,si                   ; if SI = 0 then system doesn't
 006F 7514         0085         jnz     has_table               ;  have a translation table
 0071 BB4C01                    mov     bx,offset xlt_tab       ;  which means that I'll have 
 0074 8B0E3B01                  mov     cx,spt                  ;  to init "xlt_tab" myself
 0078 B000                      mov     al,0
                        initlop0:
 007A 8807                      mov     byte ptr[bx],al
 007C FEC0                      inc     al
 007E 43                        inc     bx
 007F E2F9         007A         loop    initlop0
 0081 B001                      mov     al,1                    ; set skew factor = 1
 0083 EB15         009A         jmps    init_addr_tab
                        has_table:
 0085 06                        push    es                      ; save extra seg again
 0086 8B1E4A01                  mov     bx,xlt_offset           ; get offset of trans table
 008A BF4C01                    mov     di,offset xlt_tab       ; DI = offset of program sector
                                                                ;  translation table
 008D 8B0E3B01                  mov     cx,spt                  ; use sectors/track as
                                                                ;  counter value
 0091 8E060900                  mov     es,data_base            ; init ES value
 0095 1F                        pop     ds                      ; init DS
 0096 F3A4                      rep  movsb
 0098 06                        push    es                      ; restore old DS value
 0099 1F                        pop     ds

                        ; make sure that serial numbers that cross sector boundries will be
                        ;  found
                        init_addr_tab:
 009A 2BC0                      sub     ax,ax                   ; init address offset
 009C BE4C01                    mov     si,offset xlt_tab       ; SI -> xlt-tab
 009F 8B0E3B01                  mov     cx,spt                  ; init counter
 00A3 2AF6                      sub     dh,dh                   ; DH = 0
                        initlop9:
 00A5 BBCC01                    mov     bx,offset addr_tab
 00A8 8A14                      mov     dl,byte ptr[si]         ; get sector number
 00AA 46                        inc     si                      ; move pointer
 00AB 2A164C01                  sub     dl,xlt_tab              ; subtract 1st sector number
 00AF 02D2                      add     dl,dl                   ; multiply by 2
 00B1 03DA                      add     bx,dx                   ; BX -> correct table entry
 00B3 8907                      mov     word ptr[bx],ax         ; put address into table
 00B5 058000                    add     ax,128                  ; AX = AX+bytes/sectorz
 00B8 E2EB         00A5         loop    initlop9

                        ; depending on the system, each physical sector on a diskette can
                        ;  be made up of a number of logical sectors (128 bytes long).  the
                        ;  following code analyses the system sector translate table to 
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   4


                        ;  determine the number of logical sectors in a physical sector.
 00BA BB4C01                    mov     bx,offset xlt_tab       ; BX -> xlt_tab
                        xltlop0:
 00BD 8A07                      mov     al,byte ptr[bx]         ; AL = table entry
 00BF 43                        inc     bx                      ; BX -> next byte in table
 00C0 FEC0                      inc     al
 00C2 3A07                      cmp     al,byte ptr[bx]         ; see if the two numbers are in
 00C4 74F7         00BD         je      xltlop0                 ;  the right order
 00C6 81EB4C01                  sub     bx,offset xlt_tab       ; if they aren't then calculate
                                                                ;  how long the sequence was
 00CA 891E3901                  mov     spb,bx                  ;  and save the value
                        ; calculate skew of system sector translation table
 00CE 8A874C01                  mov     al,xlt_tab[bx]          ; get byte at xlt_tab+spb
 00D2 2A064C01                  sub     al,xlt_tab              ;  and subtract byte at xlt_tab
 00D6 8B1E3901                  mov     bx,spb                  ;  now divide by sectors/block
 00DA 2AE4                      sub     ah,ah                   ; prepare of division
 00DC F6F3                      div     bl
 00DE A23801                    mov     skew,al
                        ; tell operator about skew
                        skew_prompt:
 00E1 50                        push    ax                      ; save system skew
 00E2 E8AD04       0592         call    clear                   ; clear screen
 00E5 BA7D07                    mov     dx,offset msg21         ; send message
 00E8 E8A204       058D         call    pmsg
 00EB 5A                        pop     dx                      ; recover skew
 00EC 80CA30                    or      dl,030h                 ; make it ASCII
 00EF B102                      mov     cl,c_write
 00F1 CDE0                      int     ccpm
                        ; ask operator if he/she would like to change the sector skew
 00F3 BA1E06                    mov     dx,offset msg16
 00F6 E89404       058D         call    pmsg
 00F9 E8A404       05A0         call    get_char                ; get Y/N response
 00FC 3C4E                      cmp     al,'N'                  ; check for No
 00FE 7445         0145         je      dont_change
                        ; ask for new skew factor
 0100 BA5306                    mov     dx,offset msg17
 0103 E88704       058D         call    pmsg
 0106 E8B004       05B9         call    get_1num
 0109 A23801                    mov     skew,al
                        ; make new sector translation table using skew factor supplied by
                        ;  operator
 010C BE4C01                    mov     si,offset xlt_tab       ; BX is pointer into xlt_tab
 010F 8A1C                      mov     bl,byte ptr[si]         ; init beginning sector number
 0111 8AFB                      mov     bh,bl
 0113 8A163B01                  mov     dl,sptbyte              ; calculate sectors/track +
 0117 02D3                      add     dl,bl                   ;  first sector number
 0119 8A0E3801                  mov     cl,skew                 ; init loop counter
 011D 2AED                      sub     ch,ch
                        xltlop1:
 011F 51                        push    cx                      ; save loop counter
                        xltlop2:
 0120 8B0E3901                  mov     cx,spb                  ; init sectors/block counter
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   5


 0124 53                        push    bx                      ; save sector # registers
                        xltlop3:
 0125 883C                      mov     byte ptr[si],bh         ; put sector number into table
 0127 46                        inc     si                      ; increment pointer
 0128 FEC7                      inc     bh                      ; increment sector number
 012A E2F9         0125         loop    xltlop3
 012C A13901                    mov     ax,spb                  ; calculate new starting sector
 012F 8A0E3801                  mov     cl,skew
 0133 F6E1                      mul     cl
 0135 5B                        pop     bx                      ; recover sector # registers
 0136 02F8                      add     bh,al                   ; add skew*spt to starting
                                                                ;  sector number
 0138 3AFA                      cmp     bh,dl                   ; compare new starting sector #
                                                                ;  to first sector # + spt
 013A 72E4         0120         jb      xltlop2
 013C 021E3901                  add     bl,spbbyte              ; add sectors/block to 1st
                                                                ;  starting sector number
 0140 8AFB                      mov     bh,bl                   ; init starting sector
                                                                ;  number of the next sector
                                                                ;  block
 0142 59                        pop     cx                      ; recover loop counter
 0143 E2DA         011F         loop    xltlop1
                        dont_change:
                        ; ok, now calculate many how bytes there are on a track.
                        ;  bytes/track = sectors/track * logical sector size
 0145 A13B01                    mov     ax,spt      
 0148 BB8000                    mov     bx,128
 014B F7E3                      mul     bx
 014D A31F01                    mov     bpt,ax                  ; save value

 0150 B135                      mov     cl,mc_max               ; find 64k or less of free
 0152 BA2101                    mov     dx,offset mcb           ;  memory
 0155 CDE0                      int     ccpm

                        ; check the disk for blank tracks starting at last track. blank
                        ;  tracks won't be copied
 0157 BA4708                    mov     dx,offset msg1          ; tell operator about search
 015A E83004       058D         call    pmsg
 015D FC                        cld                             ; set direction flag forward
 015E BA5204                    mov     dx,offset msg7          ; send 'Reading' message
 0161 E82904       058D         call    pmsg
 0164 8B0ED102                  mov     cx,last_trk             ; initialize track counter
                        scan_loop:
 0168 51                        push    cx                      ; save track counter
 0169 880E0101                  mov     track,cl                ; get current track
 016D 8AC1                      mov     al,cl                   ; make track number ascii
 016F E8E203       0554         call    make_ascii
 0172 BA7204                    mov     dx,offset ascii_trk     ; print it
 0175 E81504       058D         call    pmsg
 0178 C706CC020000              mov     dma_addr,0              ; initialize dma offset
 017E E8E302       0464         call    seek                    ; seek to track
 0181 E83902       03BD         call    read                    ; read a track 
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   6


 0184 B0E5                      mov     al,blank                ; init AL with the character
                                                                ;  which is found in blank
                                                                ;  (empty) sectors
 0186 8E062101                  mov     es,m_base               ; init segment reg
 018A BF0000                    mov     di,0                    ; offset is set to zero
 018D 8B0E1F01                  mov     cx,bpt                  ; how many bytes to scan
 0191 F3AE                      repe  scasb                     ; scan until ZF=1 or CX=0
 0193 750F         01A4         jne     data_found              ; if ZF=1 then have found data
 0195 E83304       05CB         call    erase_trk               ; erase old track message
 0198 59                        pop     cx                      ; otherwise scan another track
 0199 E2CD         0168         loop    scan_loop               ;  if CX<>0

                        ; the diskette is blank if program flow reaches this point
 019B BA2608                    mov     dx,offset error_msg0
 019E E8EC03       058D         call    pmsg                    ; inform operator that the
 01A1 E8DF03       0583         call    abort                   ;  source disk is blank and
                                                                ;  abort operation

                        data_found:
 01A4 59                        pop     cx                      ; if data is found then save
 01A5 890ED102                  mov     last_trk,cx             ;  the number of the non-blank
                                                                ;  track
                        ; the information on the source disk will more than likely need to be
                        ;  paged into memory.  the following code calculates how many pages
                        ;  or blocks will be needed.
 01A9 A12301                    mov     ax,m_length             ; calculate number of bytes
 01AC BB1000                    mov     bx,16                   ;  available to be used for
 01AF F7E3                      mul     bx                      ;  a buffer area
 01B1 8B1E1F01                  mov     bx,bpt
 01B5 F7F3                      div     bx
 01B7 8B0ED102                  mov     cx,last_trk             ; CX will contain number of
 01BB 2B0E4801                  sub     cx,off                  ;  tracks to be copied
 01BF 3BC1                      cmp     ax,cx                   ; if block1 track count<lst_trk
 01C1 7C0C         01CF         jl      over0                   ;  then get block2 track count 
 01C3 890E2B01                  mov     B1_trk_cnt,cx           ;  last_trk, block_cnt=
 01C7 C7062F010100              mov     block_cnt,1             ;  1 and jump to new_disk  
 01CD EB13         01E2         jmps    over07
                        over0:
 01CF 48                        dec     ax
 01D0 A32B01                    mov     B1_trk_cnt,ax
 01D3 2BD2                      sub     dx,dx  
 01D5 8BD8                      mov     bx,ax                   ; bx holds divisor
 01D7 8BC1                      mov     ax,cx                   ;  hold dividend in division
                                                                ;  operation
 01D9 F7F3                      div     bx                      ; do division
 01DB A32F01                    mov     block_cnt,ax            ; move result to memory
 01DE 89162D01                  mov     B2_trk_cnt,dx           ; remainder = block2 track
                                                                ;  count
                        over07:
                        ; prompt operator for number of serial fields on source disk
 01E2 E8BD02       04A2         call    get_cnt
 01E5 3C00                      cmp     al,0                    ; if count = 0 then don't ask
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   7


 01E7 7403         01EC         jz      over09                  ;  for a starting serial number

                        ; prompt operator for starting serial number
 01E9 E88F02       047B         call    get_serial
                        over09:
                        ; ask operator if he/she wants to verify the copy against the source
                        ;  disk and if so, how often
 01EC E8A303       0592         call    clear                   ; clear monitor screen
 01EF BA7106                    mov     dx,offset msg18         ; ask question
 01F2 E89803       058D         call    pmsg
 01F5 C606270100                mov     ver_freq,0              ; init verification frequency
                                                                ;  value
 01FA E8A303       05A0         call    get_char                ; get yes/no answer
 01FD 3C4E                      cmp     al,'N'                  ; check for no
 01FF 740C         020D         je      over01                  ; if no then dont verify
                        ; ask operator for frequency of verification
 0201 BAA606                    mov     dx,offset msg19         ; send message
 0204 E88603       058D         call    pmsg
 0207 E8A502       04AF         call    get_2num                ; get response from operator
 020A A22701                    mov     ver_freq,al             ; save value
                        over01:

                        ; clear monitor screen
 020D E88203       0592         call    clear

 0210 C606290100                mov     dsk_cnt,0               ; init diskette counter

                        ; this portion of code does the copying and serializing
                        new_disk:
 0215 FC                        cld                             ; move current serial number
 0216 8E060900                  mov     es,data_base            ;  into insert serial message
 021A B90600                    mov     cx,length ser_def
 021D BEA508                    mov     si,offset serial_number
 0220 BF5005                    mov     di,offset serial_1
 0223 F3A4                      rep  movsb

 0225 BA4605                    mov     dx,offset msg3          ; prompt operator for
 0228 E84803       0573         call    pmsg_wait               ;  destination diskette

                        ; home both disk drives
 022B E84402       0472         call    selectD
 022E E81002       0441         call    home
 0231 E83802       046C         call    selectS
 0234 E80A02       0441         call    home

 0237 A14801                    mov     ax,off                  ; don't copy reserved tracks
 023A A2CE02                    mov     trackS,al
 023D A2CF02                    mov     trackD,al

 0240 A12B01                    mov     ax,B1_trk_cnt           ; init track counter
 0243 A33101                    mov     track_cnt,ax

CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   8


 0246 C606330100                mov     tog0,0                  ; decides whether to use
                                                                ;  B1_trk_cnt or B2_trk_cnt

 024B C606340100                mov     serial_cnt,0            ; used to check if all the
                                                                ;  serial fields were found

 0250 BA5204                    mov     dx,offset msg7          ; send 'Reading' message
 0253 E83703       058D         call    pmsg
 0256 E8EF01       0448         call    seekS                   ; read in a track so that
 0259 C706CC020000              mov     dma_addr,0              ;  there is always an extra
 025F E85B01       03BD         call    read                    ;  one in memory
 0262 E85F03       05C4         call    erase_msg               ; erase "Reading" message

 0265 8B0E2F01                  mov     cx,block_cnt            ; init block counter

                        create_dsk:
 0269 51                        push    cx                      ; save block counter
 026A 8B0E1F01                  mov     cx,bpt                  ; intialize dma offset
 026E 890ECC02                  mov     dma_addr,cx
 0272 E8F701       046C         call    selectS                 ; select source disk
 0275 BA5204                    mov     dx,offset msg7          ; send 'Reading' message
 0278 E81203       058D         call    pmsg
 027B 8B0E3101                  mov     cx,track_cnt            ; init track counter
                        lop0:
 027F 51                        push    cx                      ; save track counter
 0280 E8C501       0448         call    seekS                   ; seek track on source drive
 0283 E83701       03BD         call    read                    ; read a track
 0286 E84203       05CB         call    erase_trk               ; erase old track message
 0289 59                        pop     cx                      ; recover track counter
 028A E2F3         027F         loop    lop0
 028C E83503       05C4         call    erase_msg               ; erase "Reading" message

 028F E86002       04F2         call    serialize               ; insert current serial number
                                                                ;  into all serial fields in
                                                                ;  this block

 0292 C706CC020000              mov     dma_addr,0              ; same as above but write to
                                                                ;  destination drive
 0298 E8D701       0472         call    selectD                 ; select destination drive
 029B BA6204                    mov     dx,offset msg8          ; send "Writing" message to
 029E E8EC02       058D         call    pmsg                    ;  console
 02A1 8B0E3101                  mov     cx,track_cnt
                        lop1:
 02A5 51                        push    cx
 02A6 E8A801       0451         call    seekD
 02A9 E81801       03C4         call    write
 02AC E81C03       05CB         call    erase_trk               ; erase old track message
 02AF 59                        pop     cx
 02B0 E2F3         02A5         loop    lop1
 02B2 E80F03       05C4         call    erase_msg               ; erase "Writing" message

                        ; move extra track (read and searched but not written) from end of
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE   9


                        ;  buffer to the beginning of the buffer
 02B5 FC                        cld                             ; clear direction flag
 02B6 8B0E1F01                  mov     cx,bpt                  ; init counter
 02BA 8BC1                      mov     ax,cx                   ; calculate starting address 
 02BC 8B1E2B01                  mov     bx,B1_trk_cnt           ;  of data to be moved
 02C0 F7E3                      mul     bx
 02C2 8BF0                      mov     si,ax
 02C4 BF0000                    mov     di,0                    ; where block is to be moved
 02C7 A12101                    mov     ax,m_base               ; init segment registers
 02CA 1E                        push    ds                      ; save old values
 02CB 06                        push    es
 02CC 8ED8                      mov     ds,ax                   ; move in new values
 02CE 8EC0                      mov     es,ax
 02D0 F3A4                      rep  movsb                      ; do the move
 02D2 07                        pop     es                      ; recover values of segment
 02D3 1F                        pop     ds                      ;  registers

 02D4 59                        pop     cx                      ; recover block counter
 02D5 E292         0269         loop    create_dsk              ; do again if not last block
 02D7 803E330101                cmp     tog0,1                  ; check if we have reached this
                                                                ;  point before
 02DC 7416         02F4         je      done                    ; if yes then we are done
 02DE C606330101                mov     tog0,1                  ; no, so toggle tog0
 02E3 A12D01                    mov     ax,B2_trk_cnt           ; if B2_trk_cnt=0
 02E6 3D0000                    cmp     ax,0                    ;  then we are done
 02E9 7409         02F4         je       done
 02EB A33101                    mov     track_cnt,ax            ; else do above again but with
 02EE B90100                    mov     cx,1                    ;  B2_trk_cnt = track count
 02F1 E975FF       0269         jmp     create_dsk
                        done:
 02F4 BA6204                    mov     dx,offset msg8          ; send "Writing" message
 02F7 E89302       058D         call    pmsg                    ;  to console
 02FA E85401       0451         call    seekD                   ; write last track to dest
 02FD E8C400       03C4         call    write                   ;  drive

 0300 A03501                    mov     al,count_num            ; check if all serial fields
 0303 3A063401                  cmp     al,serial_cnt           ;  were found
 0307 7409         0312         je      serial_ok               ; if not then there is an error
 0309 BA9C07                    mov     dx,offset error_msg3    ; inform operator of error
 030C E87E02       058D         call    pmsg
 030F E87102       0583         call    abort                   ; abort operation
                        serial_ok:

 0312 E8AF02       05C4         call    erase_msg               ; erase "Writing" message

 0315 FE062901                  inc     dsk_cnt                 ; increment diskette counter

 0319 A12901                    mov     ax,dsk_cntword          ; get number of diskettes done
 031C 8B0E2701                  mov     cx,ver_freqword         ; get verification frequency
 0320 E37C         039E         jcxz    dont_verify             ; don't verify if CX = 0
 0322 F6F1                      div     cl                      ; see if it's time to verify
 0324 84E4                      test    ah,ah                   ; if DX = 0 then it's time
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  10


 0326 7576         039E         jnz     dont_verify
                        ; do the verification
 0328 BA6C07                    mov     dx,offset msg20         ; send "Verifying" message
 032B E85F02       058D         call    pmsg
 032E 8B0ED102                  mov     cx,last_trk             ; calculate number of tracks to
 0332 A14801                    mov     ax,off                  ;  compare
 0335 2BC8                      sub     cx,ax
 0337 41                        inc     cx                      ; correct result
 0338 A2CE02                    mov     trackS,al
 033B A2CF02                    mov     trackD,al
                        verlop0:
 033E 51                        push    cx                      ; save track counter
 033F E83001       0472         call    selectD                 ; select dest disk
 0342 E80C01       0451         call    seekD                   ; seek to track on dest disk
 0345 C706CC020000              mov     dma_addr,0              ; init offset of 1st buffer
 034B E86F00       03BD         call    read                    ; read a track from source disk
 034E E87A02       05CB         call    erase_trk               ; erase old track message
 0351 E81801       046C         call    selectS                 ; select source drive
 0354 E8F100       0448         call    seekS                   ; seek to current track
 0357 8B0E1F01                  mov     cx,bpt                  ; init 2nd buffer offset
 035B 51                        push    cx                      ; temp save
 035C 890ECC02                  mov     dma_addr,cx
 0360 E85A00       03BD         call    read                    ; read a track from dest disk
 0363 E86502       05CB         call    erase_trk               ; erase old track message
 0366 59                        pop     cx                      ; recover track data length
                                                                ;  into byte counter
 0367 2BF6                      sub     si,si                   ; init 1st pointer
 0369 8BF9                      mov     di,cx                   ; init 2nd pointer
                        verlop1:
 036B 1E                        push    ds                      ; save value of data seg reg
 036C A12101                    mov     ax,m_base               ; get extra seg reg value
 036F 8EC0                      mov     es,ax                   ; init ES
 0371 8ED8                      mov     ds,ax                   ; init DS
 0373 F3A6                      repe  cmpsb                     ; verify
 0375 1F                        pop     ds                      ; recover data seg reg value
 0376 7423         039B         je      verlop2                 ; if ZF = 0 then verification
                                                                ;  failed.  inform operator
 0378 4F                        dec     di                      ; correct 2nd buffer pointer
 0379 56                        push    si                      ; save pointer to 1st buffer
 037A 51                        push    cx                      ; save byte pointer
 037B BED302                    mov     si,offset ser_def       ; SI -> to ser_def
 037E B90600                    mov     cx,length ser_def       ; init counter
 0381 F3A6                      repe  cmpsb                     ; do compare
 0383 750A         038F         jne     verlop3
 0385 59                        pop     cx                      ; recover byte counter
 0386 83E905                    sub     cx,length ser_def-1     ; correct it
 0389 5E                        pop     si                      ; recover 1st buffer pointer
 038A 83C605                    add     si,length ser_def-1     ; correct it
 038D EBDC         036B         jmps    verlop1
                        ; verification failed so inform operator to try it again
                        verlop3:
 038F E80002       0592         call    clear
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  11


 0392 BAF207                    mov     dx,offset error_msg7
 0395 E8F501       058D         call    pmsg
 0398 E97AFE       0215         jmp     new_disk
                        verlop2:
 039B 59                        pop     cx                      ; recover track counter
 039C E2A0         033E         loop    verlop0

                        dont_verify:
 039E E8F101       0592         call    clear                   ; clear monitor screen
 03A1 FC                        cld                             ; insert current serial number
 03A2 B90600                    mov     cx,length ser_def       ;  into remove message
 03A5 8E060900                  mov     es,data_base
 03A9 BEA508                    mov     si,offset serial_number
 03AC BF9C05                    mov     di,offset serial_2
 03AF F3A4                      rep  movsb

 03B1 BA9105                    mov     dx,offset msg4          ; prompt operator to remove
 03B4 E8D601       058D         call    pmsg                    ;  copy

 03B7 E87201       052C         call    inc_serial              ; increment current serial
                                                                ;  number

 03BA E958FE       0215         jmp     new_disk                ; do another disk


                        ; read a track from the selected disk
                        read:
 03BD C6061A010D                mov     io_tab,read_code
 03C2 EB07         03CB         jmps    track_io

                        ; write a track to the selected disk drive
                        write:
 03C4 C6061A010E                mov     io_tab,write_code
 03C9 EB00         03CB         jmps    track_io

                        ; do track input or output on selected disk drive
                        track_io:
 03CB B90400                    mov     cx,4                    ; initialize io retry counter
                        io_retry:
 03CE 51                        push    cx                      ; save retry counter
 03CF E83E00       0410         call    track_setup             ; init dma base address
 03D2 C606190100                mov     sector,0                ; start with sector #0
 03D7 8B0E3B01                  mov     cx,spt                  ; init sector counter
                        io_lop:
 03DB 51                        push    cx                      ; save sector counter
 03DC E83F00       041E         call    sectran                 ; perform sector translation
 03DF BA1401                    mov     dx,offset set_sector    ; set sector thru ccpm
 03E2 B132                      mov     cl,s_bios
 03E4 CDE0                      int     ccpm

 03E6 BA0F01                    mov     dx,offset set_dma_offset ; set dma offset thru ccpm
 03E9 B132                      mov     cl,s_bios
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  12


 03EB CDE0                      int     ccpm

 03ED B132                      mov     cl,s_bios               ; set read/write func thru ccpm
 03EF BA1A01                    mov     dx,offset io_tab
 03F2 CDE0                      int     ccpm
 03F4 84C0                      test    al,al           ; io error if not zero
 03F6 7510         0408         jnz     io_error                ; tell operator about io error
 03F8 FE061901                  inc     sector                  ; next sector to read
 03FC 59                        pop     cx                      ; recover sector counter
 03FD E2DC         03DB         loop    io_lop

 03FF 59                        pop     cx                      ; clean up stack
 0400 A11F01                    mov     ax,bpt                  ; init dma_addr for next
 0403 0106CC02                  add     dma_addr,ax             ;  track
 0407 C3                        ret     
                        io_error:
 0408 59                        pop     cx                      ; clean up stack
 0409 E83500       0441         call    home                    ; home disk
 040C 59                        pop     cx                      ; recover retry counter
 040D E2BF         03CE         loop    io_retry
 040F C3                        ret
                         
                        track_setup:
 0410 A12101                    mov     ax,m_base               ; initialize dma base address
 0413 A30B01                    mov     dma_base,ax
 0416 B132                      mov     cl,s_bios
 0418 BA0A01                    mov     dx,offset set_dma_base
 041B CDE0                      int     ccpm
 041D C3                        ret

                        ; do logical to physical sector translation
                        sectran:
 041E 2AE4                      sub     ah,ah
 0420 A01901                    mov     al,sector
 0423 BB4C01                    mov     bx,offset xlt_tab
 0426 D7                        xlat    xlt_tab
 0427 A21501                    mov     tsector,al
 042A 2AE4                      sub     ah,ah
 042C 2A064C01                  sub     al,xlt_tab
 0430 02C0                      add     al,al
 0432 BBCC01                    mov     bx,offset addr_tab
 0435 03D8                      add     bx,ax
 0437 8B07                      mov     ax,word ptr[bx]
 0439 0306CC02                  add     ax,dma_addr
 043D A31001                    mov     dma_offset,ax
 0440 C3                        ret

                        ; home the selected drive
                        home:
 0441 C606010100                mov     track,0
 0446 EB1C         0464         jmps    seek

CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  13


                        ; seek to the selected track on the source drive
                        seekS:
 0448 A0CE02                    mov     al,trackS
 044B FE06CE02                  inc     trackS
 044F EB07         0458         jmps    display_trk

                        ; seek to the selected track on the destination drive
                        seekD:
 0451 A0CF02                    mov     al,trackD
 0454 FE06CF02                  inc     trackD
                        display_trk:
 0458 A20101                    mov     track,al
 045B E8F600       0554         call    make_ascii                      ; make track # ascii
 045E BA7204                    mov     dx,offset ascii_trk             ; send track number to
 0461 E82901       058D         call    pmsg                            ;  console

                        ; seek to the selected track on the selected drive
                        ;  "track" = desired track #
                        seek:
 0464 B132                      mov     cl,s_bios
 0466 BA0001                    mov     dx,offset seek_trk_tab
 0469 CDE0                      int     ccpm
 046B C3                        ret

                        ; select source disk
                        selectS:
 046C 8A163601                  mov     dl,dskS
 0470 EB04         0476         jmps    select

                        ; select destination disk
                        selectD:
 0472 8A163701                  mov     dl,dskD

                        ; select a disk drive for future operations
                        select:
 0476 B10E                      mov     cl,drv_set
 0478 CDE0                      int     ccpm
 047A C3                        ret

                        ; get starting serial number from operator
                        get_serial:
 047B BAFC03                    mov     dx,offset msg2                  ; send prompt message
 047E E80C01       058D         call    pmsg                            ;  to console

 0481 BAA308                    mov     dx,offset con_buf0      ; point to console input buffer
 0484 B10A                      mov     cl,10                   ; CP/M read console buffer
 0486 CDE0                      int     ccpm
 0488 803EA40806                cmp     buf0_len,length ser_def ; check for correct number
                                                                        ;  of digits
 048D 7501         0490         jne     bad_serial
 048F C3                        ret

CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  14


                        bad_serial:
 0490 C606A70406                mov     error_msg2,length ser_def
 0495 800EA70430                or      error_msg2,030h                 ; make it ASCII
 049A BA8E04                    mov     dx,offset error_msg1
 049D E8ED00       058D         call    pmsg
 04A0 EBD9         047B         jmps    get_serial

                        ; get from the operator how many serial fields are on the source
                        ;  diskette.  this is a safeguard to help prevent the wrong disk
                        ;  from being used.
                        get_cnt:
 04A2 BA1E04                    mov     dx,offset msg6                  ; send prompt message
 04A5 E8E500       058D         call    pmsg                            ;  to console
 04A8 E80400       04AF         call    get_2num                        ; get a number (0-99)
                                                                        ; from operator
 04AB A23501                    mov     count_num,al                    ; save number
 04AE C3                        ret

                        ; input two ASCII numbers into buffer 1 and translate them into a 
                        ;  binary number which is returned in the AL register
                        get_2num:
 04AF BAAE08                    mov     dx,offset con_buf1              ; get address of buffer
 04B2 B10A                      mov     cl,10
 04B4 CDE0                      int     ccpm
 04B6 803EAF0802                cmp     buf1_len,2                      ; can't have more than
 04BB 7609         04C6         jbe     input_ok0                       ;  two digits 0-99
                        input_err0:
 04BD BAD107                    mov     dx,offset error_msg6            ; tell operator about
 04C0 E8CA00       058D         call    pmsg                            ;  error and try again
 04C3 E9E9FF       04AF         jmp     get_2num
                        input_ok0:
 04C6 803EAF0800                cmp     buf1_len,0                      ; need at least one
 04CB 74F0         04BD         je      input_err0                      ;  digit. tell operator
                                                                        ;  if there isn't
 04CD BBB008                    mov     bx,offset input_num             ; bx -> input buffer
 04D0 8A0EAF08                  mov     cl,buf1_len                     ; (cl) = digit count
 04D4 2AED                      sub     ch,ch                           ; zero upper half of cx
 04D6 03D9                      add     bx,cx                           ; make bx point to
 04D8 4B                        dec     bx                              ;  units digit of input

 04D9 8A37                      mov     dh,byte ptr[bx]                 ; get units digit
 04DB 80E60F                    and     dh,00Fh                         ; mask off upper nybble
 04DE E203         04E3         loop    tens                            ; if (cx) <> 2 then get
                                                                        ;  tens digit
 04E0 E90C00       04EF         jmp     got_it                          ; only had one digit
                        tens:
 04E3 4B                        dec     bx                              ; make bx -> to tens
                                                                        ;  digit
 04E4 8A17                      mov     dl,byte ptr[bx]                 ; get tens digit
 04E6 80E20F                    and     dl,00Fh                         ; mask off upper nybble
 04E9 B00A                      mov     al,10                           ; load multiplier
 04EB F6E2                      mul     dl                              ; do multiply
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  15


 04ED 02F0                      add     dh,al                           ; add tens to units
                        got_it:
 04EF 8AC6                      mov     al,dh                           ; save number
 04F1 C3                        ret

                                
                        serialize:      ; locate all occurrances of serial numbers in buffer

 04F2 FC                        cld                     ; set direction forward
 04F3 8E062101                  mov     es,m_base       ; point ES: to beginning of buffer
 04F7 BF0000                    mov     di,0
 04FA A11F01                    mov     ax,bpt
 04FD 8B1E3101                  mov     bx,track_cnt
 0501 43                        inc     bx              ; remember that an extra track was read
 0502 F7E3                      mul     bx
 0504 8BC8                      mov     cx,ax
                        next_serial:
 0506 BED302                    mov     si,offset ser_def       ; point at pattern
 0509 AC                        lodsb                   ; get first char of pattern into AL
 050A F2AE                      repne scasb             ; look for next occurance of AL
 050C 751D         052B         jne     no_match        ; if not match, then we are done

 050E 57                        push    di              ; save scan pointer
 050F 51                        push    cx              ; save count
 0510 B90500                    mov     cx,(length ser_def)-1   ; residual length of pattern
 0513 F3A6                      repe cmpsb
 0515 59                        pop     cx              ; recover scan count
 0516 5F                        pop     di              ; recover scan pointer
 0517 75ED         0506         jne     next_serial     ; no, rest didn't match

 0519 51                        push    cx              ; save scan pointer
 051A 4F                        dec     di              ; move di back to start of field
 051B BEA508                    mov     si,offset serial_number ; si points to current serial
                                                                ;  number
 051E B90600                    mov     cx,length ser_def ; counter for number of bytes to move
 0521 F3A4                      rep  movsb
 0523 59                        pop     cx              ; recover scan pointer
 0524 FE063401                  inc     serial_cnt
 0528 E9DBFF       0506         jmp     next_serial

                        no_match:
 052B C3                        ret

                        ; increment the ASCII serial number

                        inc_serial:
 052C B90600                    mov     cx,length ser_def       ; length of serial number
 052F BBA508                    mov     bx,offset serial_number ; bx points to start of string
 0532 83C305                    add     bx,(length ser_def)-1 ; bx now points to end of string
                        addlop:
 0535 51                        push    cx                      ; save length of pointer
 0536 8A07                      mov     al,byte ptr[bx]         ; get byte of serial number
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  16


 0538 FEC0                      inc     al                      ; add 1 to it
 053A 27                        daa                             ; decimal adjust it
 053B 9F                        lahf                            ; check to see if there was a
 053C 80E410                    and     ah,10h          ;  carry from the lower half of
 053F B104                      mov     cl,4                    ;  the al register
 0541 D2E4                      shl     ah,cl
 0543 7204         0549         jc      fix                     ; if yes then increment the next
                                                                ;  byte of the serial number
 0545 8807                      mov     byte ptr[bx],al         ; else save byte and stop
 0547 59                        pop     cx                      ; clean up stack
 0548 C3                        ret
                        fix:
 0549 240F                      and     al,0fh                  ; make high nybble of byte
 054B 0C30                      or      al,30h                  ;  equal to "3" again
 054D 8807                      mov     byte ptr[bx],al         ; save byte back in serial
                                                                ;  number
 054F 4B                        dec     bx                      ; point at next higher byte
 0550 59                        pop     cx                      ; recover length of serial
                                                                ;  number
 0551 E2E2         0535         loop    addlop                  ; do again if CX<>0
 0553 C3                        ret

                        ; translate the 8 bit digit in AL to ASCII into "ascii_trk"
                        make_ascii:
 0554 BA2020                    mov     dx,'  '                 ; fill "ascii_trk" with blanks
 0557 89167204                  mov     ascii_trk,dx
 055B 89167404                  mov     ascii_trk+2,dx
 055F BB7504                    mov     bx,offset ascii_trk+3   ; BX -> "ascii_trk"+3
 0562 B20A                      mov     dl,10                   ; init divisor
                        makelop1:
 0564 2AE4                      sub     ah,ah                   ; make AH zero  
 0566 F6F2                      div     dl                      ; and divide by 10
 0568 80C430                    add     ah,'0'                  ; make remainder ascii
 056B 8827                      mov     byte ptr[bx],ah         ; store it in "ascii_trk"
 056D 4B                        dec     bx                      ; move pointer to next location
 056E 84C0                      test    al,al                   ; see if quotient zero yet
 0570 75F2         0564         jnz     makelop1                ; no, got more digits
 0572 C3                        ret

                        ; print the message at [DX] and wait for RETURN key
                        pmsg_wait:
 0573 E81700       058D         call    pmsg                    ; print the message
                        wait_1:
 0576 B101                      mov     cl,c_read               ; CP/M Console Input
 0578 CDE0                      int     ccpm
 057A 3C03                      cmp     al,'C'-'@'              ; see if control-C
 057C 7405         0583         je      abort                   ; terminate program
 057E 3C0D                      cmp     al,cr                   ; see if ASCII carriage return
 0580 75F4         0576         jne     wait_1                  ; no, try again
 0582 C3                        ret                             ; back to caller

                        ; abort the program
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  17


                        abort:
 0583 BABD05                    mov     dx,offset abort_msg
 0586 E8EAFF       0573         call    pmsg_wait
 0589 B100                      mov     cl,0                    ; CP/M reboot function
 058B CDE0                      int     ccpm

                        ; print the string whose offset is in dx and is terminated by '$'
                        pmsg:
 058D B109                      mov     cl,c_writebuf
 058F CDE0                      int     ccpm
 0591 C3                        ret

                        ; clears the monitor screen
                        clear:
 0592 803ED002FF                cmp     clear_on,false          ; see if clear screen enable is
 0597 7406         059F         je      no_clear                ;  off
 0599 BA6708                    mov     dx,offset clear_msg
 059C E8EEFF       058D         call    pmsg
                        no_clear:
 059F C3                        ret

                        ; get ASCII input from operator and translate to upper case
                        get_char:
 05A0 B101                      mov     cl,c_read               ; request single character
 05A2 CDE0                      int     ccpm                    ;  from console
 05A4 3C03                      cmp     al,'C'-'@'                      ; check for control-C
 05A6 74DB         0583         je      abort                   ; abort operation if yes
 05A8 245F                      and     al,05Fh                 ; xlate lower to upper chase
                        ; echo choice back to operator
                        echo_choice:
 05AA 50                        push    ax                      ; temp save
 05AB B208                      mov     dl,bs                   ; write over last input
 05AD B102                      mov     cl,c_write
 05AF CDE0                      int     ccpm
 05B1 5A                        pop     dx                      ; get temp save
 05B2 52                        push    dx
 05B3 B102                      mov     cl,c_write              ; write it out
 05B5 CDE0                      int     ccpm
 05B7 58                        pop     ax
 05B8 C3                        ret

                        ; get a single ASCII number from operator and check for .
                        get_1num:
 05B9 B101                      mov     cl,c_read
 05BB CDE0                      int     ccpm
 05BD 3C03                      cmp     al,'C'-'@'                      ; check for control-C
 05BF 74C2         0583         je      abort
 05C1 240F                      and     al,00Fh
 05C3 C3                        ret

                        ; this code erases the "Reading" and "Writing" messages from the
                        ;  monitor screen
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  18


                        erase_msg:
 05C4 BA7804                    mov     dx,offset msg10
 05C7 E8C3FF       058D         call    pmsg
 05CA C3                        ret

                        ; this code erases the old track numbers from the monitor screen
                        erase_trk:
 05CB BA8804                    mov     dx,offset msg11
 05CE E8BCFF       058D         call    pmsg
 05D1 C3                        ret

                                dseg
                                org     0000h

                                ; Page Zero Definitions

 0000                   code_length     rw      1       ; low 16 bits code segment length
 0002                   code_length_h   rb      1       ; high 8 bits code segment length
 0003                   code_base       rw      1       ; base paragraph of code segment
 0005                   model_8080      rb      1       ; 8080 model byte
 0006                   data_length     rw      1       ; low 16 bits data segment length
 0008                   data_length_h   rb      1       ; high 8 bits data segment length
 0009                   data_base       rw      1       ; base paragraph of data segment
 000B                                   rs      1       ; << reserved >>
 000C                   extra_length    rw      1       ; low 16 bits extra segment length
 000E                   extra_length_h  rb      1       ; high 8 bits extra segment length
 000F                   extra_base      rw      1       ; base paragraph of extra segment


                                org     0100h

 0100 0A                seek_trk_tab    db      10      ; seek track function table
 0101                   track      rb   4

 0105 09                sel_dsk_tab     db      9       ; select disk drive
 0106                   disk            rb      4

 010A 11                set_dma_base    db      17      ; set dma base address function table
 010B                   dma_base        rw      2

 010F 0C                set_dma_offset  db      12      ; set dma offset address function table
 0110                   dma_offset      rw      2

 0114 0B                set_sector      db      11      ; set sector function table
 0115                   tsector         rb      4       ; holds translated sector #
 0119                   sector          rb      1       ; holds untranslated sector #

 011A                   io_tab          rb      1       ; select read/write function table
 011B                                   rw      2

 011F                   bpt    rw       1               ; how many bytes per track

CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  19


 0121                   mcb             rw      0               ; memory control block
 0121                   m_base    rw    1               ; base address (segment address)
 0123 FF0F              m_length        dw      0FFFh   ; desired length of memory area
 0125                   m_ext      rw   1

 0127                   ver_freqword    rw      0
 0127 0000              ver_freq        db      0,0     ; holds verification frequency value
 0129                   dsk_cntword     rw      0
 0129 0000              dsk_cnt         db      0,0     ; number of copies made so far

 012B                   B1_trk_cnt    rw        1
 012D                   B2_trk_cnt    rw        1

 012F                   block_cnt       rw      1

 0131                   track_cnt       rw      1

 0133                   tog0        rb  1

 0134                   serial_cnt    rb        1

 0135                   count_num       rs      1       ; holds number of serial fields
                                                        ;  to expect on source disk
 0136 00                dskS            db      0
 0137 01                dskD            db      1

 0138                   skew            rb      1       ; reserve storage for skew factor
 0139                   spb             rw      0       ; sectors/block
 0139                   spbbyte         rb      2

 013B                   DPB             rb      0       ; Disk Parameter Block
 013B                   spt             rw      0       ; sector per track
 013B                   sptbyte         rb      2
 013D                   bsh             rb      1       ; block shift factor
 013E                   blm             rb      1       ; block mask
 013F                   exm             rb      1       ; extent mask
 0140                   dsm             rw      1       ; total storage capacity of drive
 0142                   drm             rw      1       ; number of directory entries
 0144                   al0             rb      1
 0145                   al1             rb      1
 0146                   cks             rw      1
 0148                   off             rw      1       ; number of reserved tracks

 014A                   xlt_offset      rw      1       ; offset of system translate table

 014C                   xlt_tab         rb      128     ; will contain sector translation table
 01CC                   addr_tab        rw      128     ; will contain sector address offsets
                                                        ;  from beginning of track address in
                                                        ;  disk data buffer
 02CC                   dma_addr        rw      1       ; will hold dma offset by track

 02CE                   trackS          rb      1
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  20


 02CF                   trackD          rb      1

 02D0 00                clear_on        db      true

 02D1 4C00              last_trk        dw      76

 02D3 363534333231      ser_def         db      '654321'

 02D9 0D0A0A            msg0            db      cr,lf,lf
 02DC 2D2D2D2D2D2D                      db      '-------------------------'
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D
 02F5 2D2D2D2D2D2D                      db      '-------------------------'
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D
 030E 2D                                db      '-'
 030F 0D0A                              db      cr,lf
 0311 53455249414C                      db      'SERIAL16          V1.0  Serial No. '
      313620202020
      202020202020
      56312E302020
      53657269616C
      204E6F2E20
 0334 585858582D30                      db      'XXXX-0000-999999'
      3030302D3939
      39393939
 0344 0D0A                              db      cr,lf
 0346 436F70797269                      db      'Copyright (C) 1982'
      676874202843
      292031393832
 0358 0D0A                              db      cr,lf
 035A 446967697461                      db      'Digital Research, Inc.          '
      6C2052657365
      617263682C20
      496E632E2020
      202020202020
      2020
 037A 416C6C205269                      db      'All Rights Reserved'
      676874732052
      657365727665
      64
 038D 0D0A                              db      cr,lf
 038F 2D2D2D2D2D2D                      db      '-------------------------'
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D
 03A8 2D2D2D2D2D2D                      db      '-------------------------'
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  21


      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D2D2D2D2D2D
      2D
 03C1 2D                                db      '-'
 03C2 0D0A0A                            db      cr,lf,lf
 03C5 4469736B6574                      db      'Diskette Generation Utility',cr,lf
      74652047656E
      65726174696F
      6E205574696C
      6974790D0A
 03E2 666F72204350                      db      'for CP/M-86 based systems'
      2F4D2D383620
      626173656420
      73797374656D
      73
 03FB 24                                db      '$'

 03FC 0D0A0A            msg2            db      cr,lf,lf
 03FF 456E74657220                      db      'Enter starting serial number  '
      737461727469
      6E6720736572
      69616C206E75
      6D6265722020
 041D 24                                db      '$'

 041E 070D0A0A          msg6            db      bell,cr,lf,lf
 0422 456E74657220                      db      'Enter number of serial fields on source disk'
      6E756D626572
      206F66207365
      7269616C2066
      69656C647320
      6F6E20736F75
      726365206469
      736B
 044E 203F20                            db      ' ? '
 0451 24                                db      '$'

 0452 52656164696E      msg7            db      'Reading Track  '
      672054726163
      6B2020
 0461 24                                db      '$'

 0462 57726974696E      msg8            db      'Writing Track  '
      672054726163
      6B2020
 0471 24                                db      '$'

 0472                   msg9            rs      0
 0472                   ascii_trk       rw      2
 0476 20                                db      ' '
 0477 24                                db      '$'
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  22



 0478 080808080808      msg10           db      bs,bs,bs,bs,bs,bs,bs,bs,bs,bs
      08080808
 0482 080808080808                      db      bs,bs,bs,bs,bs,bs
 0488 0808080808        msg11           db      bs,bs,bs,bs,bs
 048D 24                                db      '$'

 048E 0D0A0A            error_msg1      db      cr,lf,lf
 0491 53657269616C                      db      'Serial number must be '
      206E756D6265
      72206D757374
      20626520
 04A7                   error_msg2      rb      1
 04A8 206469676974                      db      ' digits long. Try again !!!  '
      73206C6F6E67
      2E2054727920
      616761696E20
      2121212020
 04C5 24                                db      '$'

 04C6 0D0A0A0A          msg12           db      cr,lf,lf,lf
 04CA 536F75726365                      db      'Source Drive is (A,B,etc.) ? '
      204472697665
      206973202841
      2C422C657463
      2E29203F20
 04E7 24                                db      '$'

 04E8 0D0A0A            msg13           db      cr,lf,lf
 04EB 44657374696E                      db      'Destination Drive is (A,B,etc.) ? '
      6174696F6E20
      447269766520
      69732028412C
      422C6574632E
      29203F20
 050D 24                                db      '$'

 050E 0D0A0A            msg14           db      cr,lf,lf
 0511 496E73657274                      db      'Insert Source Disk '
      20536F757263
      65204469736B
      20
 0524 616E64207479                      db      'and type "Return" to continue '
      706520225265
      7475726E2220
      746F20636F6E
      74696E756520
 0542 0D0A0A                            db      cr,lf,lf
 0545 24                                db      '$'

 0546 0D0A0A            msg3            db      cr,lf,lf
 0549 496E73657274                      db      'Insert '
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  23


      20
 0550                   serial_1        rb      length ser_def
 0556 20696E746F20                      db      ' into destination drive'
      64657374696E
      6174696F6E20
      6472697665
 056D 0D0A                              db      cr,lf
 056F 7468656E2074                      db      'then type "Return" to continue'
      797065202252
      657475726E22
      20746F20636F
      6E74696E7565
 058D 0D0A0A                            db      cr,lf,lf
 0590 24                                db      '$'

 0591 070D0A0A          msg4            db      bell,cr,lf,lf
 0595 52656D6F7665                      db      'Remove '
      20
 059C                   serial_2        rb      length ser_def
 05A2 2066726F6D20                      db      ' from destination drive'
      64657374696E
      6174696F6E20
      6472697665
 05B9 0D0A0A                            db      cr,lf,lf
 05BC 24                                db      '$'

 05BD 0D0A0D0A          abort_msg       db      cr,lf,cr,lf
 05C1 0D0A2A2A2A20                      db      cr,lf,'*** Serialization terminated ***'
      53657269616C
      697A6174696F
      6E207465726D
      696E61746564
      202A2A2A
 05E3 0D0A                              db      cr,lf
 05E5 0D0A5265706C                      db      cr,lf,'Replace disk in Drive A:'
      616365206469
      736B20696E20
      447269766520
      413A
 05FF 0D0A09207468                      db      cr,lf,'  then type ENTER to reboot ','$'
      656E20747970
      6520454E5445
      5220746F2072
      65626F6F7420
      24

 061E 0D0A0A            msg16           db      cr,lf,lf
 0621 576F756C6420                      db      'Would you like to change the skew factor'
      796F75206C69
      6B6520746F20
      6368616E6765
      207468652073
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  24


      6B6577206661
      63746F72
 0649 2028592F4E29                      db      ' (Y/N) ? '
      203F20
 0652 24                                db      '$'

 0653 0D0A0A            msg17           db      cr,lf,lf
 0656 456E74657220                      db      'Enter skew factor (1-9) ? '
      736B65772066
      6163746F7220
      28312D392920
      3F20
 0670 24                                db      '$'

 0671 0D0A0A            msg18           db      cr,lf,lf
 0674 446F20796F75                      db      'Do you want to perform copy verification'
      2077616E7420
      746F20706572
      666F726D2063
      6F7079207665
      726966696361
      74696F6E
 069C 2028592F4E29                      db      ' (Y/N) ? '
      203F20
 06A5 24                                db      '$'

 06A6 0D0A0A0A          msg19           db      cr,lf,lf,lf
 06AA 31203D206576                      db      '1 = every disk is verified'
      657279206469
      736B20697320
      766572696669
      6564
 06C4 0D0A                              db      cr,lf
 06C6 32203D206576                      db      '2 = every 2nd disk is verified'
      65727920326E
      64206469736B
      206973207665
      726966696564
 06E4 0D0A                              db      cr,lf
 06E6 33203D206576                      db      '3 = every 3rd disk is verified'
      657279203372
      64206469736B
      206973207665
      726966696564
 0704 0D0A220D0A22                      db      cr,lf,'"',cr,lf,'"',cr,lf,'"',cr,lf
      0D0A220D0A
 070F 3939203D2065                      db      '99 = every 99th disk is verified'
      766572792039
      397468206469
      736B20697320
      766572696669
      6564
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  25


 072F 0D0A0A                            db      cr,lf,lf
 0732 486F77206F66                      db      'How often do you want the verification to'
      74656E20646F
      20796F752077
      616E74207468
      652076657269
      666963617469
      6F6E20746F
 075B 206F63637572                      db      ' occur (1-99) ? '
      2028312D3939
      29203F20
 076B 24                                db      '$'

 076C 566572696679      msg20           db      'Verifying Track '
      696E67205472
      61636B20
 077C 24                                db      '$'

 077D 0D0A0A            msg21           db      cr,lf,lf
 0780 546865206375                      db      'The current sector skew is '
      7272656E7420
      736563746F72
      20736B657720
      697320
 079B 24                                db      '$'

 079C 070D0A0A          error_msg3      db      bell,cr,lf,lf
 07A0 446964206E6F                      db      'Did not find all of the required serial '
      742066696E64
      20616C6C206F
      662074686520
      726571756972
      656420736572
      69616C20
 07C8 6669656C6473                      db      'fields'
 07CE 0D0A                              db      cr,lf
 07D0 24                                db      '$'

 07D1 0D0A0A            error_msg6      db      cr,lf,lf
 07D4 57726F6E672E                      db      'Wrong. Need one or two digits'
      204E65656420
      6F6E65206F72
      2074776F2064
      6967697473
 07F1 24                                db      '$'

 07F2 070D0A0A          error_msg7      db      bell,cr,lf,lf
 07F6 2A2A2A2A2056                      db      '**** Verification failed ****'
      657269666963
      6174696F6E20
      6661696C6564
      202A2A2A2A
CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  26


 0813 0D0A0A                            db      cr,lf,lf
 0816 547279206974                      db      'Try it again.'
      20616761696E
      2E
 0823 0D0A                              db      cr,lf
 0825 24                                db      '$'

 0826 070D0A0A          error_msg0      db      bell,cr,lf,lf
 082A 205468652053                      db      ' The Source Disk is BLANK '
      6F7572636520
      4469736B2069
      7320424C414E
      4B20
 0844 0D0A                              db      cr,lf
 0846 24                                db      '$'

 0847 0D0A0A            msg1            db      cr,lf,lf
 084A 436865636B69                      db      'Checking for blank tracks'
      6E6720666F72
      20626C616E6B
      20747261636B
      73
 0863 0D0A0A                            db      cr,lf,lf
 0866 24                                db      '$'

 0867 0D0A0A0A0A0A      clear_msg       db      cr,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf
      0A0A0A0A0A0A
      0A0A0A
 0876 0A0A0A0A0A0A                      db      lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf
      0A0A0A0A0A0A
      0A0A0A
 0885 0A0A0A0A0A                        db      lf,lf,lf,lf,lf
 088A 0B0B0B0B0B0B                      db      vt,vt,vt,vt,vt,vt,vt,vt,vt,vt,vt,vt,vt,vt,vt
      0B0B0B0B0B0B
      0B0B0B
 0899 0B0B0B0B0B0B                      db      vt,vt,vt,vt,vt,vt,vt,vt,vt
      0B0B0B
 08A2 24                                db      '$'

 08A3 0A                con_buf0        db      10                      ; buffer used to read
 08A4                   buf0_len        rb      1                       ;  serial number
 08A5                   serial_number   rb      length ser_def
 08AB                                   rb      10-1-length ser_def

 08AE 05                con_buf1        db      5               ; another console input buffer
 08AF                   buf1_len        rb      1
 08B0                   input_num       rb      5


 08B5 00                                db      0               ; force out end of data segment


CP/M ASM86 1.1  SOURCE: SERIAL16.A86                                                                         PAGE  27


END OF ASSEMBLY.  NUMBER OF ERRORS:   0.  USE FACTOR:  6%
