 opt nol
 lib sysdef
 lib sysints
 opt lis
 ttl UniFLEX Disk Formatter
 sttl Main Format Program
 pag
 info UniFLEX (R) Disk Format Program
 info Core Version 1.09; Released November 29, 1984
 info Copyright, (C) 1984, by
 info Technical Systems Consultants, Inc.
 info All rights reserved.


 lib DNT

* UniFLEX Disk Format Program

*
* usage: ++ formatxx +nmdrfqvlBIMLP
* where:
*    formatxx - The name of the format program.  This
*      name differs for different devices.  E.g.
*      "formatfd" is the format program for 8" floppy
*      diskettes.
*    options:
*      +n - Don't prompt the user for the volume information
*      +m - Specify a device model as "+m=XXXX"
*      +d - Specify the [block] device to be formatted
*           Given as "+d=XXXX"
*      +r - Specify the number of swap cylinders
*           Given by "+r=NN", where NN is a decimal number
*      +f - Specify the number of FDN blocks
*           Given by "+f=NN", where NN is a decimal number
*      +q - Don't issue the verification prompt.
*      +v - Verify the disk surface before writing the file
*           system information.  This is useful for devices
*           on which the format operation does not verify the
*           usability of a given track.  The verify operation
*           will perform a write/read check of each sector on
*           the disk volume, reporting any bad sectors found
*           and placing them in the "/.badblocks" file.
*      +B - Don't actually format the disk - Only rewrite
*           the boot sector.
*      +M - Prompt the user for the disk model information.
*           Should be used in place of the "+m" option.
*      +L - Prompt the user for known bad blocks.  These blocks
*           are entered in the format "hh/ccc/ss", where "hh"
*           is the head number (0-N), "ccc" is the cylinder
*           number (0-N) and "ss" is the sector number (1-N)
*           of the bad spot on the disk media.
*      +l - Same as +L except the list comes from a file, given
*           by "+l=file-name".
*      +P - Prompt for disk parameters (instead of relying on
*           a model number or info built into the tables).  This
*           option is automatically invoked if an unknown model
*           name is given.
*      +I - Interleave disk.  Applies only to specific devices
*           such as floppies and is system dependent.  E.g.
*           this option will cause an interleave factor of
*           2 for most standard floppies but has no effect on
*           winchesters.
*
* -- 1.06 - Added two additional bytes in DNT (and SIR)
*         - to be used for more complete control of
*         - Winchesters using XEBEC controllers
* -- 1.07 - Bad FDN Blocks change # free FDNs
* -- 1.08 - Added +I option
*         - Bad block input now accepts $xxx (hex block #)
*

 text
 global track,wsk,wsk2,dfd,VOLCNT,N_ST,N_CYL,N_HD,BRW,BWP,Get_parm
 global setbsc,disktype,diskindex,work,get_YN,r0,r1,lmul,intopt

*
STDOUT equ 1 Standard Output Channel
STDERR equ 2 Standard Error Channel
*

*
* Format
*
* Main entry here.
*

Format sys guid get user id
 cmpx #0 is it 0?
 lbne 01f
 leax 4,s point to arg list
 stx argpt save it
 jsr option get options
 jsr names get names
 jsr getparams read disk parameters if necessary
 jsr initparams set up parameters for format
 jsr get_list read bad block list if any
 jsr validate
 sys unmnt,blkdev unmount device if mounted
 bec 10f any errors?
 cmpd #16 is device busy
 lbeq 03f if so - error
10 sys open,dev,2 open device for write
 lbes 02f error?
 std dfd save file desc
*
* Try to read block 1 of device -- This will cause the
* system to restore the heads on the drive and make sure
* that it knows where the heads are.  If this step is
* omitted, then it is possible to begin formatting on
* any arbitrary track and the whole process is doomed
* to failure!
*
 sys seek,0,1,0 force head to be restored
 ldx work set up I/O call
 stx r_SIR0 *** Buffer address in call ***
 ldd dfd
 sys ind,r_SIR
*
* Now inform the system of the details of the type of
* device about to be formatted.  For floppy diskettes,
* this information consists of single or double density
* and single/double sided diskettes (quad density for
* 5" mini-floppies).  For winchester drives, this
* information describes the drive in detail as it is
* really an index into a table kept by the operating
* system containing all the data about all drive models
* supported.
*
 ldd disktype set up for ttyset
 cmpa #$FF winchester configurable?
 beq 10f yes - have to do this differently
 pshs d save original value
 exg a,b
 std disktype
 ldd dfd restore file descriptor
 sys ttyset,disktype set up sides/density (model type)
 puls d restore original value
 std disktype
 bra 19f
10 ldx diskindex set up device control info
 ldy #d_DCT
 ldd DNTcyl,x
 std ,y++
 ldd DNTheads,x
 stb ,y+
 ldd DNTbrw,x
 std ,y++
 ldd DNTbwp,x
 std ,y++
 lda #11 Max ECC burst
 sta ,y+
 lda DNTtype+1,x seek rate indication
 sta ,y+
 lda DNTtype+2,x imbedded servo indicator
 sta ,y+
 lda #0 clear spare bytes
 sta ,y+
 ldd dfd inform UniFLEX of the disk configuration
 sys ttyset,DCTset
*
* The +B option (new_boot) indicates that the disk is not
* to be reformatted - just a new boot sector written.
*
19 tst new_boot rewrite boot only?
 bne 20f
 jsr format format disk
 tst Verify +v option present?
 beq 15f no - skip verify
 jsr verify verify disk surface
15 jsr strd write structural info
20 jsr mkbt write out boot sector
 ldd dfd get file desc
 sys close close the device
 tst quiet quiet mode?
 beq 25f no - go ahead and report
 ldd badbc any bad blocks?
 addd badsbc
 addd badfdnbc
 beq 26f no - just exit
25 bsr report report on completion
26 ldd #0 set status
 sys term exit
*
* Abnormal exits
*
* -- format must run as System Manager
*
01 ldd #STDOUT set file desc
 sys write,E1,S1 output error
 ldd #10 set status
 sys term exit
*
* -- Couldn't open the [character] device
*
02 pshs d save status
 ldd #STDOUT set file desc
 sys write,E3,S3 output error
 puls d
 sys term exit
*
* -- The [block] device is mounted and busy
*
03 pshs d save status
 ldd #STDOUT set file desc
 sys write,E7,S7 output error
 puls d get status
 sys term exit

*
* report
*
report ldd #STDOUT
 sys write,rptm00,rptm00s
 ldd #0 print device name
 pshs d
 ldx #blkdev
 pshs x
10 lda ,x+
 beq 15f
 inc 3,s
 bra 10b
15 lda #write
 pshs a
 leax 0,s
 ldd #STDOUT
 sys indx
 leas 5,s clean up stack
 ldd #STDOUT
 sys write,rptm01,rptm01s
 ldd N_HD
 ldx #rptm020
 jsr cvtdec
 ldd N_CYL
 ldx #rptm021
 jsr cvtdec
 ldd N_ST
 ldx #rptm022
 jsr cvtdec
 lda VOLCNT
 jsr MapHex
 std rptm023
 ldd VOLCNT+1
 jsr MapHex
 std rptm023+2
 stx rptm023+4
 ldd #STDOUT
 sys write,rptm02,rptm02s
 ldd badbc get count of bad blocks
 addd badsbc
 addd badfdnbc
 lbeq rpt100
 ldd #STDOUT "Bad blocks detected:"
 sys write,rptm2,rptm2s
 ldy #Bsclst point at start of list
rpt010 cmpy Bscptr all items listed?
 bhs rpt020 jump if yes
 lda 0,y print block in hex
 jsr MapHex
 std rptm30
 ldd 1,y
 jsr MapHex
 std rptm30+2
 stx rptm30+4
 clra
 ldb ,y+ convert block #
 std r0
 ldd ,y++
 std r0+2
 ldd N_ST
 std r1
 jsr ldiv compute sector #
 ldd rmndr get sector #
 addd #1
 ldx #rptm33
 jsr cvtdec convert to decimal ASCII
 ldd N_HD
 std r1
 jsr ldiv
 ldd rmndr get head #
 ldx #rptm31
 jsr cvtdec
 ldd r0+2 get cylinder #
 ldx #rptm32
 jsr cvtdec
 ldd #STDOUT print detail line
 sys write,rptm3,rptm3s
 bra rpt010
rpt020 ldx #rptm0+2
 ldd badbc restore bad block count
 addd badsbc
 addd badfdnbc
 jsr cvtdec
 ldd #STDOUT
 sys write,rptm0,rptm0s
 bra rpt900
rpt100 ldd #STDOUT
 sys write,rptm1,rptm1s
rpt900 rts
*
 data
*
rptm00 fcc $d,'Formatting complete on device "'
rptm00s equ *-rptm00
rptm01 fcc '"',$d
rptm01s equ *-rptm01
rptm02 fcc $d
rptm020 fcc ' NNNNN Heads',$d
rptm021 fcc ' NNNNN Cylinders',$d
rptm022 fcc ' NNNNN Sectors/Track',$d
rptm023 fcc 'XXXXXX Total blocks (hex)',$d
rptm02s equ *-rptm02
*
rptm0 fcc $d,$d
 fcc ' NNNNN bad blocks detected',$d
rptm0s equ *-rptm0
*
rptm1 fcc 'No bad blocks detected',$d
rptm1s equ *-rptm1
*
rptm2 fcc $d,'Bad blocks detected:'
 fcc $d,$d,'Block (hex)          Head / Cylinder / Sector  (dec)'
 fcc    $d,'===========          ====   ========   ======'
rptm2s equ *-rptm2
*
rptm3 fcc    $d
rptm30 fcc  'XXXXXX             '
rptm31 fcc  ' NNNNN     '
rptm32 fcc  ' NNNNN   '
rptm33 fcc  ' NNNNN'
rptm3s equ *-rptm3
 text

*
* validate
*
* Inform the user of what's happening and
* make sure he wants to go through with it.
*
validate pshs d,x,y,u save registers
 tst quiet should we prompt?
 bne 99f no - exit (assume everything OK)
 ldy diskindex get device name index
 ldb #8 copy model name
 ldx #Vmsg3
25 lda ,y+
 sta ,x+
 decb
 bne 25b
 ldy #blkdev copy device name
 ldx #Vmsg1
30 lda ,y+
 beq 40f
 sta ,x+
 bra 30b
40 lda #'"
 sta ,x+
 tfr x,d compute length of string
 subd #Vmsg0
 std w_Vmsg0s
 jsr get_YN display message & prompt
 fdb w_Vmsg0
 fdb w_Vmsg2
 fdb 0
 beq 99f jump if 'yes'
 ldd #$00FF aborted status
 sys term quit if 'no'
99 puls d,x,y,u,pc return
*
 data
Vmsg0 fcc 'About to format "'
Vmsg1 fcc '********* ********* ********* *'
*
Vmsg2 fcc ' as '
Vmsg3 fcc '********'
 fcc ' - Continue (y/n)? '
Vmsg2s equ *-Vmsg2
*
w_Vmsg0 fcb write write Vmsg0
 fdb Vmsg0
w_Vmsg0s fdb 0 size
*
w_Vmsg2 fcb write write Vmsg2
 fdb Vmsg2
 fdb Vmsg2s
*
 text

*
* option
*
* Set specified options.
*

option ldu argpt get arg ptr
10 ldx 0,u++ get next arg
 bne 20f end of args?
 rts return
20 stu argpt save pos
 lda 0,x+ get character
 cmpa #'+ is it '+'?
 bne badoption if not - error
 bsr sop get options
 bra 10b repeat
*
badoption ldd #STDOUT set file desc
 sys write,E5,S5 output error
 ldd #$ff
 sys term exit

*
* sop
*
* Decode specified options.
*

sop lda 0,x+ get character
 bne 0f end of arg?
 rts return
0 cmpa #'n is it no names?
 bne 0f
 inc nonam set flag
 bra sop
0 cmpa #'B re-write boot sector only?
 bne 0f
 inc new_boot
 bra sop
0 cmpa #'I interleave option?
 bne 0f
 inc intopt
 bra sop
0 cmpa #'M is is model prompt?
 bne 0f
 lbsr getModel prompt for model name
 bra sop
0 cmpa #'q is it quiet mode?
 bne 0f
 inc quiet yes - set flag
 bra sop
0 cmpa #'v is it verify mode?
 bne 0f
 inc Verify
 bra sop
0 cmpa #'r reserve swap?
 bne 0f
 jsr decvt get count
 std swpspc save count
 bra sop
0 cmpa #'m is it disk model?
 bne 0f
 lbsr getmodel get disk model
 bra sop
0 cmpa #'P is it get disk parameters interactively?
 bne 0f
 inc Get_parms yes - set flag
 bra sop
0 cmpa #'d is it device select?
 bne 0f
 lbsr getdevice get device specification
 bra sop
0 cmpa #'f is it fdn count?
 bne 0f
 jsr decvt convert to binary
 std optfdn save as fdn block count
 bra sop repeat
0 cmpa #'L is it interactive bad block list?
 bne 0f
 inc List_opt
 bra sop continue
0 cmpa #'l is it file bad block list?
 bne 0f
 inc list_opt
 lda ,x check for "+l=xxx"
 cmpa #'=
 bne 1f
 leax 1,x bump past "="
1 stx list_ptr save file name pointer
2 lda ,x+ find end of string
 bne 2b
 leax -1,x point at null
 lbra sop continue
0 lbra badoption

*
* names
*
* Get disk names from s.i.
*

names tst nonam do names?
 beq names2
 rts return
names2 ldd #1 set file desc
 sys write,N1,Z1 output prompt
 ldd #0 set input
 sys read,fsnam,32 input file system name
 ldx #fsnam point to name
 subd #1 adjust count
 bmi names6 eof?
 clr d,x set term char
 ldd #1 set file desc
 sys write,N2,Z2 output prompt
 ldd #0 set input
 sys read,vlnam,32 get volume name
 ldx #vlnam point to name
 subd #1 adjust length
 bmi names6 eof?
 clr d,x set term char
 ldd #1 set file desc
 sys write,N3,Z3 output prompt
 ldd #0 set input file
 sys read,resbuf,32 get volume number
 cmpd #0 eof?
 beq names6
 cmpd #1 null response?
 beq names5
 ldx #resbuf point to response
 jsr decvt convert to binary
 std vlnum save it
names5 rts return
names6 ldd #1 output cr
 sys write,crst,1
 ldd #$00FF set status
 sys term

*
* initparams
*
* Set up disk format parameters
*
initparams ldx diskindex get disk name index
 ldd DNTcyl,x get number of cylinders
 std N_CYL
 ldd DNTheads,x get number of heads
 std N_HD
 ldd DNTst,x get number of sectors / track
 std N_ST
 ldd DNTbrw,x get Reduced Write Cylinder
 std BRW
 ldd DNTbwp,x get Write Precomp Cylinder
 std BWP
 ldd DNTtype,x get disk type (2 bytes)
 std disktype
 ldd DNTspace,x get additional space needed
 cmpd #1024 nead at least 2 blocks worth
 bhi 0f
 ldd #1024
0 pshs d
 ldd #END compute addr of contiguous memory
 addd #4095
 anda #$F0
 clrb
 std work
 addd ,s++ compute high address
 std lastaddr
 ldx #fst_time
 stx timeptr
10 sys ind,ex_mem
 bec 20f
 jsr get_YN get a yes/no response
 fdb w_Nomem
 fdb 0
 beq 15f jump if yes
 ldd #$FF exit with error!
 sys term end of program
15 ldx timeptr calculate length of sleep time
 ldd ,x++
 cmpx #lst_time
 bne 17f
 ldx #fst_time reset pointer
17 stx timeptr
 jsr sleep go to sleep for a while
 bra 10b
20 ldd N_ST Compute Heads*Cylinders*Sectors
 std r0+2
 ldd N_HD
 std r1+2
 ldd #0
 std r0
 std r1
 jsr lmul
 ldd N_CYL
 std r1+2
 jsr lmul
 lda r0+1 get VOLCNT
 sta VOLCNT
 sta volbc
 ldd r0+2
 std VOLCNT+1
 std volbc+1
 ldd #(100/3) compute default FDN count (3% of total disk)
 std r1
 jsr ldiv
 ldd r0+2
 std fdnbc
 ldd swpspc get swap space count
 beq 30f is it zero?
25 std r0+2 swap tracks * sectors/cylinder
 ldd N_ST
 std r1+2
 ldd #0
 std r0
 std r1
 jsr lmul
 ldd N_HD * heads/cylinder
 std r1+2
 jsr lmul = swap blocks
 ldd r0+2 pick up swap size
 std swpsiz set swap size
 ldd volbc+1 get volume size
 subd swpsiz remove swap space
 std volbc+1 save new size
 lda volbc
 sbca #0
 sta volbc
30 ldd optfdn get option fdn count
 beq 40f is it set?
 std fdnbc save it
 cmpd #65000/8
 bhi 80f
 addd #100
 cmpd volbc+1 too large for volume?
 bhs 80f
40 jsr setDP set up disk params for boot & format
 rts
*
80 ldd #STDOUT set file desc
 sys write,E2,S2 output error
 ldd #$ff set status
 sys term exit
*
 data
Nomem fcc 'Unable to obtain required memory - '
 fcc 'Do you wish to wait? '
Nomem_s equ *-Nomem
*
w_Nomem fcb write
 fdb Nomem
 fdb Nomem_s
*
* List of sleep times
*
fst_time fdb 5
 fdb 15
 fdb 30
lst_time fdb 60
timeptr fdb 0
*
 text

*
* get_YN
*
* Print a message on the terminal and wait for a Yes/No
* response.
*    jsr get_YN
*    fdb System call for prompt
*    fdb ...
*    fdb 0
*    <EQ> if response is 'yes'
*
get_YN pshs d,x,y,u get registers
10 ldy 8,s get pointer
15 ldd #STDERR
 ldx ,y++ get system call address
 beq 20f jump if no more
 sys indx
 bra 15b
20 ldd #STDERR read response
 sys read,resbuf,32
 cmpd #0
 beq 10b
 lda resbuf get response
 cmpa #'y
 beq 99f
 cmpa #'Y
 beq 99f
 cmpa #'n
 beq 95f take 'no' exit
 cmpa #'N
 bne 10b re-issue prompt
95 lda #1 set <NE> condition
99 pshs cc save exit conditions
 sty 9,s fix up return address
 puls cc,d,x,y,u,pc return

*
* sleep
*
* Put the task to sleep for the time in (D).
*
sleep pshs d,x,y,u save registers
 tfr s,d expand memory to full 64K
 anda #$F0 strip out low bits
 clrb
 subd #1
 std ibrk2 set up call
 sys ind,ibrk
 sys cpint,ALRMI,10f
 ldd 0,s get wait time
 sys alarm
 sys stop wait for interrupt
 ldd #END restore original memory allocation
 addd #4095
 anda #$F0
 clrb
 subd #1
 std ibrk2
 sys ind,ibrk
 bra 99f exit
10 rti nothing to do but exit
99 puls d,x,y,u,pc return
*
 data
ibrk fcb break
ibrk2 fdb 0
 text

*
* getmodel
*
* Pick up disk model name from command line
* and set "disktype" appropriately.
*    (X) - Points to model name text
*
getmodel pshs d,x,y,u save registers
 ldb #8 copy 8 characters for model name
 ldy #model
 lda #'  clear name buffer
00 sta ,y+
 decb
 bne 00b
 ldb #8 copy model name from command line
 ldy #model
 lda ,x check for "+m=XXX"
 cmpa #'=
 bne 10f
 leax 1,x skip over "="
10 lda ,x+ get next character from command line
 beq 20f jump if end of argument
 sta ,y+
 decb continue for 8 characters
 bne 10b
15 lda ,x+ find null at end of string
 bne 15b
20 leax -1,x point back at null
 stx 2,s update register for return
 ldx #DNT search Device Name Table
30 ldy #model reset pointer
 ldb #8 length of name
 leau 0,x save DNT pointer
35 lda ,x+ compare names
 cmpa ,y+
 bne 40f jump on no match
 decb check all 8 characters
 bne 35b
 stu diskindex save index
 bra 99f all done - exit
40 leax DNTsize,u bump to next name entry
 cmpx #DNTend end of table
 blo 30b no - continue
 ldd #STDOUT
 sys write,Badmdl,BadmdlS
 inc Get_parms force interactive parameter fetching
99 puls d,x,y,u,pc return
*
 data
Badmdl fcc 'Illegal disk model - ignored',$d
BadmdlS equ *-Badmdl
*
 text

*
* getModel - prompt the user for a model name
*
getModel pshs d,x,y,u save registers
 jsr get_YN see if guy wants a list of available models
 fdb w_Lsttab
 fdb 0
 bne 00f
 ldd #STDERR write out heading
 sys ind,w_Tabhdr
 ldu #DNT print device name table
10 ldy #Tab_mod copy model name
 ldb #8
 leax DNTname,u
11 lda ,x+
 sta ,y+
 decb
 bne 11b
 ldd DNTcyl,u
 ldx #Tab_cyl
 jsr cvtdec
 ldd DNTheads,u
 ldx #Tab_hds
 jsr cvtdec
 ldd DNTst,u
 ldx #Tab_spt
 jsr cvtdec
 ldd #STDERR
 sys ind,w_Tabdet
20 leau DNTsize,u bump to next entry
 cmpu #DNTend end of table?
 blo 10b
00 ldd #STDERR write out prompt
 sys write,Model,ModelS
 ldd #STDERR read model name
 sys read,resbuf,32
 bec 10f
 ldx #Badmodel - force illegal model error
 bra 20f
10 ldx #resbuf-1 set up response
 leax d,x point at end of response
 lda ,x+ check for CR at end of name
 cmpa #$0D
 bne 15f
 clr -1,x
15 clr ,x+ force at least one null at end
 ldx #resbuf set up for getmodel
20 lbsr getmodel go look up model
99 puls d,x,y,u,pc return
*
 data
Model fcc $d,'Disk Model Name: '
ModelS equ *-Model
*
Badmodel fcc '********' Illegal model name
*
w_Lsttab fcb write
 fdb 00f,01f-00f
00 fcc $d,'Do you want a list of available models? '
01
*
w_Tabhdr fcb write
 fdb 00f,01f-00f
00 fcc $d,'Model Name    Cylinders    Heads   Sectors/Track'
   fcc $d,'==========    =========    =====   ============='
01
*
w_Tabdet fcb write
 fdb 00f,01f-00f
00 fcc $d
Tab_mod fcc '********'
   fcc '     '
Tab_cyl fcc '   ***'
   fcc '     '
Tab_hds fcc '    **'
   fcc '     '
Tab_spt fcc '    **'
01
 text

*
* getdevice
*
* Pick up device name from command line
*
getdevice pshs d,x,y,u save registers
 ldy #blkdev clear out block device name
 ldb #32
10 clr ,y+
 decb
 bne 10b
 ldy #blkdev set to copy device name
 lda ,x check for "+d=XXX"
 cmpa #'=
 bne 20f
 leax 1,x bump past "="
20 lda ,x+ copy name
 beq 30f
 sta ,y+
 cmpy #blkdev+32 name overflow
 blo 20b
 bra 80f Illegal name
*
* Block device name obtained - set up character device name
*
30 leax -1,x point back at null
 stx 2,s save updated pointer
 ldx #blkdev copy name into character device name
 ldy #dev
35 lda ,x+
 sta ,y+
 cmpy #dev+32 end of buffer?
 blo 35b
36 cmpx #blkdev start of name?
 bls 80f yes - illegal name
 ldb ,-y back up pointer
 lda ,-x get character
 beq 36b skip over nulls
 cmpa #'9 check for digit
 bhi 36b
 cmpa #'0
 blo 36b
37 cmpx #blkdev check buffer boundary
 bls 80f jump for illegal name
 ldb ,-y back up pointer
 lda ,-x found non-digit?
 beq 80f null here is a bad owie!
 cmpa #'9
 bhi 40f non-digit - exit
 cmpa #'0
 bhs 37b keep scanning
40 leay 1,y bump pointers
 leax 1,x
 lda #'c set up character device name
 sta ,y+
45 cmpy #dev+32 check for overflow
 bhs 80f
 lda ,x+ copy rest of name
 sta ,y+
 bne 45b
 bra 99f all done
80 ldd #STDERR Illegal device specification
 sys write,BadDN,BadDNs
 ldd #$00FF aborted status
 sys term
99 puls d,x,y,u,pc return
*
 data
BadDN fcc 'Illegal device specification',$d
BadDNs equ *-BadDN
*
 text

*
* setbsc - determine bad sector
*
*
setbsc pshs d,x,y,u save registers
 ldx #track check for duplicate entry
 jsr isbad
 bcs setb90 nothing to do if already in place
 ldx Bscptr get pointer
 cmpx #Bsclst+(3*MaxBSC) too many bad sectors?
 bhs setb99
 lda track copy bad sector
 sta ,x+
 ldd track+1
 std ,x++
 stx Bscptr
 ldd badbc update bad block count
 addd #1
 std badbc
10 tst bs_msg should we print the message?
 bne setb90 no - exit
 lda track print message
 jsr MapHex
 std stbm00
 ldd track+1
 jsr MapHex
 std stbm00+2
 stx stbm00+4
 ldd #STDOUT
 sys write,stbm0,stbm0s
setb90 puls d,x,y,u,pc return
*
setb99 ldd #STDOUT
 sys write,tmbsc,TMBSCS
 jsr report issue report before quitting
 ldd #$00FF aborted status
 sys term
*
 data
stbm0 fcc 'Format error - Sector '
stbm00 fcc 'XXXXXX bad',$d
stbm0s equ *-stbm0
*
tmbsc fcc 'Too many bad sectors - Format aborted',$d
TMBSCS equ *-tmbsc
*
bs_msg fcb 0 Print Bad Sector Message flag (=1 -> no message)
 text

*
* get_list
*
* Read the bad block list if present.  The format of
* the list is:
*    hh/ccc/ss
* HH  - Head number of bad spot (0-N)
* CCC - Cylinder number of bad spot (0-N)
* SS  - Sector number (512 byte sectors) of bad spot (1-N)
*
get_list pshs d,x,y,u save registers
 lda List_opt check for either +L or +l option
 ora list_opt
 lbeq 99f exit if neither
 inc bs_msg don't print bad sector messages
 tst List_opt interactive list?
 beq 10f no - set up for file
 ldd #STDERR yes - read responses from Standard Error
 std list_fd
 sys write,GLmsg0,GLmsg0s
 bra 20f go process list
10 sys ind,list_open open bad block list file
 bcc 15f jump if no errors
 lbsr rpt_gl_err report error
 lbra 99f exit
15 std list_fd save file descriptor
20 tst List_opt should we prompt?
 beq 25f
 ldd list_fd
 sys write,GLmsg1,GLmsg1s
25 ldd list_fd read next response
 sys read,list_buf,10
 bec 30f jump if no error
 ldd #STDERR inform user of error
 sys write,GLmsg3,GLmsg3s
 lbra 90f exit
30 cmpd #0 end of file?
 lbeq 90f yes - all done
 ldx #list_buf set up terminator
 leax d,x
 clr ,-x set null terminator
 ldx #list_buf set up pointer
 lda 0,x hex input - block #?
 cmpa #'$
 lbeq 40f yes - go process it
 jsr scan_int find next integer
 lbcs 80f jump if syntax error
 std list_hh save head #
 cmpd N_HD check range
 blt 31f jump if OK
 jsr rpt_bsn Inform user of error
 fdb GLmsg7,GLmsg7s
 bra 20b
31 lda ,x+ get terminator
 cmpa #'/ make sure it is a slash
 lbne 80f not - syntax error
 jsr scan_int get cylinder
 lbcs 80f jump if syntax error
 std list_ccc
 cmpd N_CYL check range
 blt 32f jump if OK
 jsr rpt_bsn Inform user of error
 fdb GLmsg8,GLmsg8s
 bra 20b
32 lda ,x+ get terminator
 cmpa #'/
 lbne 80f syntax error
 jsr scan_int get sector #
 lbcs 80f syntax error
 subd #1 make range 0..N
 blt 33f jump if error
 std list_ss
 cmpd N_ST check range
 blt 34f jump if OK
33 jsr rpt_bsn Inform user of error
 fdb GLmsg9,GLmsg9s
 lbra 20b
34 lda ,x+ check terminator
 lbne 80f
 ldd list_ccc compute block #
 std r0+2
 ldd N_HD
 std r1+2
 ldd #0
 std r0
 std r1
 jsr lmul compute heads*cylinders
 ldd r0+2
 addd list_hh
 std r0+2
 ldd r0
 adcb #0
 adca #0
 std r0
 ldd N_ST * sectors/track
 std r1+2
 jsr lmul
 ldd r0+2 compute actual block #
 addd list_ss
 std track+1
 ldb r0+1
 adcb #0
 stb track
 bra 70f go mark block bad
40 ldd #0 reset block #
 std r0
 std r0+2
 lda ,x+ skip over $
45 lda ,x+ get next input character
 beq 60f jump at end
 cmpa #'0 legal digit?
 blo 80f no - syntax error
 cmpa #'9
 bhi 46f
 suba #'0 get offset
 bra 50f
46 cmpa #'A validate
 blo 80f
 ora #$20 make lower case
 cmpa #'f
 bhi 80f error if out of range
 suba #'a-10 compute digit
50 pshs a save digit
 ldd #0
 std r1
 ldd #16
 std r1+2
 jsr lmul
 clra
 puls b get new digit
 addd r0+2 add into value
 std r0+2
 ldd r0
 adcb #0
 adca #0
 std r0
 bra 45b continue with scan
60 lda r0+1 move value into "track"
 sta track
 ldd r0+2
 std track+1
70 jsr setbsc mark as bad block
 lbra 20b continue
80 ldd #STDERR report syntax error
 sys write,GLmsg2,GLmsg2s
 tst List_opt interactive list?
 lbne 20b yes - try again
90 tst List_opt interactive input?
 bne 95f yes - no files to close
 ldd list_fd yes - close input file
 sys close
 bra 99f
95 ldd #STDERR print a CR/LF
 sys write,GLmsg4,GLmsg4s
99 clr bs_msg print bad sector messages when necessary
 puls d,x,y,u,pc return
*
* rpt_gl_err - Report error opening bad block list file
*
rpt_gl_err pshs d
 ldd #STDERR inform the user we couldn't open his file
 sys write,GLmsg5,GLmsg5s
 ldx list_ptr print out file name
 clrb
10 lda ,x+
 beq 20f
 incb
 bra 10b
20 pshs d
 ldx list_ptr
 pshs x
 lda #write
 pshs a
 leax 0,s
 ldd #STDERR
 sys indx
 leax 5,s
 ldd #STDERR
 sys write,GLmsg5,GLmsg5s
 puls d,pc return
*
* rpt_bsn - Inform of illegal block #
*
rpt_bsn pshs d,x,y,u save registers
 ldy 8,s get parameter pointer
 ldd ,y++ get message address
 ldx ,y++ get message length
 sty 8,s replace return address
 pshs d,x set up call
 lda #write
 pshs a
 leax 0,s
 ldd #STDERR write out message
 sys indx
 leas 5,s clean up stack
 ldx #list_buf
 ldd #0
 pshs d set up count
 pshs x set up pointer
10 lda ,x+ find end of string
 beq 15f
 inc 3,s bump count
 bra 10b
15 lda #write
 pshs a
 leax 0,s
 ldd #STDERR
 sys indx
 leas 5,s clean up stack
 ldd #STDERR
 sys write,GLmsg11,GLmsg11s
99 puls d,x,y,u,pc return
*
* scan_int
*
* Scan a decimal integer value
*  X - ASCII string (null or '/' terminated)
*  D - Decimal value
*  Any other character is an error - carry set on exit
*
scan_int pshs y,u save registers
 ldd #0 set up initial value
 pshs d
10 ldb ,x+ get next input character
 cmpb #'0 check for legal digits
 blo 20f jump - end of number or error
 cmpb #'9
 bhi 20f
 subb #'0 compute offset
 clra
 tfr d,y save digit
 ldd ,s++ compute val*10
 aslb
 rola
 pshs d save *2
 aslb
 rola
 bcs 90f jump if overflow
 aslb
 rola compute *8
 addd ,s++ compute *10
 pshs d save
 bcs 90f
 tfr y,d restore digit
 addd ,s++
 pshs d save new value
 bcs 90f
 bra 10b continue
20 leax -1,x bad up pointer to terminator
 cmpb #0 check for legal terminators
 beq 95f exit - ok
 cmpb #'/
 beq 95f
90 sec return - error
 bra 99f
95 clc return - no error
99 puls d,y,u,pc return
*
 data
GLmsg0 fcc 'Enter bad blocks as: hh/ccc/ss (decimal values)',$d
GLmsg0s equ *-GLmsg0
GLmsg1 fcc 'HH/CCC/SS: '
GLmsg1s equ *-GLmsg1
GLmsg2 fcc 'Bad block syntax error - ignored',$d
GLmsg2s equ *-GLmsg2
GLmsg3 fcc 'I/O error reading bad block list',$d
GLmsg3s equ *-GLmsg3
GLmsg4 fcb $d
GLmsg4s equ *-GLmsg4
GLmsg5 fcc $d,'Unable to open bad block list file "'
GLmsg5s equ *-GLmsg5
GLmsg6 fcc '" - ignored',$d
GLmsg6s equ *-GLmsg6
GLmsg7 fcc 'Illegal head value in "'
GLmsg7s equ *-GLmsg7
GLmsg8 fcc 'Illegal cylinder value in "'
GLmsg8s equ *-GLmsg8
GLmsg9 fcc 'Illegal sector value in "'
GLmsg9s equ *-GLmsg9
GLmsg11 fcc '" - ignored',$d
GLmsg11s equ *-GLmsg11
*
list_fd fdb 0 file descriptor for list
list_buf rzb 80 input buffer
list_hh fdb 0 Head number
list_ccc fdb 0 Cylinder number
list_ss fdb 0 Sector number
*
list_open fcb open open bad block list file
list_ptr fdb 0 file name pointer
 fdb 0 open for read
*
 text

*
* verify
*
* Verify the disk surface by performing a write/read
* test of every sector on the disk.
*
verify pshs d,x,y,u save registers
 ldx work initialize test pattern
 leay 512,x end of buffer
 stx w_test0 set up I/O calls
 sty r_test0
 ldd #$FFFE
5 std ,x++ copy into buffer
 pshs a
 asla rotate pattern
 rolb
 puls a
 rola
 pshs y
 cmpx ,s++
 blo 5b
*
* Write test pattern to every block on disk
*
 ldd #0 start with block 0
 sta track
 std track+1
10 lda track end of volume?
 cmpa VOLCNT
 bne 15f
 ldd track+1
 cmpd VOLCNT+1
 lbeq 30f yes - go verify
15 clra set up block #
 ldb track
 std isk2
 ldd track+1
 std isk3
 ldd dfd seek to desired block
 sys ind,isk
 ldd dfd now write test pattern
 sys ind,w_test
 bec 20f jump if no error on write
 jsr setbsc mark block as bad
20 ldd track+1 bump block #
 addd #1
 std track+1
 lda track
 adca #0
 sta track
 bra 10b continue until entire disk written
*
* Verify each block on disk
*
30 ldd #0 start with block 0
 sta track
 std track+1
40 lda track end of volume?
 cmpa VOLCNT
 bne 45f
 ldd track+1
 cmpd VOLCNT+1
 lbeq 99f yes - all done
45 clra set up block #
 ldb track
 std isk2
 ldd track+1
 std isk3
 ldx work clear buffer
 leax 512,x
 leay 512,x
 ldd #0
46 std ,x++
 pshs y end of buffer?
 cmpx ,s++
 blo 46b
 ldd dfd seek to desired block
 sys ind,isk
 ldd dfd now read test pattern
 sys ind,r_test
 bes 50f jump if error on read
 ldx work verify data
 leay 512,x
 leau 512,x end of buffer pointer
47 ldd ,x++
 cmpd ,y++
 bne 50f jump if failure
 pshs u
 cmpx ,s++ done with comparison?
 blo 47b
 bra 55f
50 jsr setbsc mark block as bad
55 ldd track+1 bump block #
 addd #1
 std track+1
 lda track
 adca #0
 sta track
 bra 40b continue until entire disk read
99 puls d,x,y,u,pc return
*
 data
w_test fcb write write test pattern
w_test0 fdb 0 ** Address of buffer **
 fdb 512
*
r_test fcb read read test pattern
r_test0 fdb 0 *** Address of buffer ***
 fdb 512
*
 text

*
* strd
*
* Set up all disk structures.
*

strd
 bsr calcs do all calculations
 jsr clrfdn clear all fdn blocks
 jsr mksir make the sir block
 jsr mkrfdn make root fdn
 jsr mkrtf make root file
 jsr mkfree make free block list
* jsr ckswap check for bad spots in swap space
 rts return

*
* calcs
*
* Do all parameter calculations.
*

calcs
 ldd fdnbc get fdn block count
 addd #3 3 for the 3 blocks used
 pshs d
 ldd volbc+1 get volume size in blocks
 subd 0,s++ subtract off above
 std frebc+1 save as free count
 lda volbc get hi byte
 sbca #0 propagate cary
 sta frebc save hi byte of free count
 jsr sort_bbl sort bad block list
 jsr mkbtkf make /.badblocks file
 ldd fdnbc get fdn block count
 subd badfdnbc remove any bad FDN blocks
 ble no_FDN error - no good FDN blocks remain!
 lslb multiply by 8
 rola (8 fdn's per block)
 lslb
 rola
 lslb
 rola
 subd #rtfcnt subtract predefined files
 std fdnfc save free count
 ldd frebc+1 bump free count by 1
 addd #1
 std r0+2
 ldb frebc
 adcb #0
 clra
 std r0
 ldd #100 set up for later divide
 std r1 save it
calcs4 lbsr ldiv do divide (freecount mod 100)
 ldb rmndr+1 get remainder
 bne calcs5
 ldb #100
calcs5 stb blkic save as in core blocks
 ldd #3 calc starting free sequence number
 addd fdnbc add in fdn blocks
 addd badfbc add in blocks used by /.badblocks
 std frseq+1 save sequence number
 clr frseq
 rts return
*
* no_FDN - No good FDN blocks (all were marked bad)!
*
no_FDN ldd #STDERR
 sys write,no_Fmsg,no_Fmsgs
 jsr report
 ldd #$00FF
 sys term
*
no_Fmsg fcc $d,$a,'No good FDN blocks remaining (all marked bad)!'
no_Fmsgs equ *-no_Fmsg

*
* lmul
*
* Long multiply - 32 bits (r0) X 32 bits (r1).
* Result is in r0.
*

lmul ldb #32 set loop count
 pshs b
 ldd #0 init variables
 std mpytmp
 std mpytmp+2
 lsr r0 do initial shift
 ror r0+1
 ror r0+2
 ror r0+3
lmul1 bcc lmul2 need to add?
 ldd mpytmp+2
 addd r1+2
 std mpytmp+2
 ldd mpytmp
 adcb r1+1
 adca r1
 std mpytmp save result
lmul2 ror mpytmp do shifting
 ror mpytmp+1
 ror mpytmp+2
 ror mpytmp+3
 ror r0
 ror r0+1
 ror r0+2
 ror r0+3
 dec 0,s dec the loop count
 bne lmul1 repeat?
 puls b,pc return

*
* 'Ldiv' divides a 32 bit number (r0 -> r0+3) by a 16 bit
* number (r1 -> r1+1) and produces a 32 bit result
* in r0 and a 16 bit remainder in 'rmndr'.
*

ldiv ldb #33 set loop counter
 pshs b
 ldd #0 do init
 std rmndr
 bra ldiv2
ldiv1 ldd rmndr do subtraction
 subd r1
 bcs ldiv2 rmndr > r1 ?
 std rmndr set new work value
ldiv2 rol r0+3 do shifting
 rol r0+2
 rol r0+1
 rol r0
 rol rmndr+1
 rol rmndr
 dec 0,s dec the loop count
 bne ldiv1
 com r0 compliment the result
 com r0+1
 com r0+2
 com r0+3
 lsr rmndr adjust the remainder
 ror rmndr+1
 puls b,pc return

*
* sort_bblk - Sort the bad block list into ascending order
*
sort_bbl pshs d,x,y,u save registers
 ldy #Bsclst Start of Bad Block List
10 cmpy Bscptr end of list?
 bhs 99f yes - end of sort
 leau 3,y
20 cmpu Bscptr end of list?
 bhs 80f yes - end of pass
 lda 0,u (U) < (Y)?
 cmpa 0,y
 bhi 30f no - jump
 blo 25f
 ldd 1,u
 cmpd 1,y
 bhs 30f
25 lda 0,u yes - exchange elements
 pshs a
 ldd 1,u
 pshs d
 lda 0,y
 sta 0,u
 ldd 1,y
 std 1,u
 puls d
 std 1,y
 puls a
 sta 0,y
30 leau 3,u bump to next element
 bra 20b
80 leay 3,y bump to next element
 bra 10b continue (new pass)
99 puls d,x,y,u,pc return

*
* mkbtkf - Make the bad block file /.badblocks
*
mkbtkf ldd #0 set up counts
 std badbc count of bad blocks
 std badsbc count of bad blocks in swap space
 std badfdnbc count of bad blocks in fdn space
 std badfbc count of blocks used by /.badblocks
 ldd fdnbc compute first available free block
 addd #3
 std badfbn+1 save "bad" free block #
 clr badfbn
 ldx #mpfdn1 set up pointers
 stx fdnmp1
 ldx #badib
 stx badip
 ldx #badib2
 stx badip2
 ldx #Bsclst initialize pointer
mkbtk0 cmpx Bscptr end of bad tracks?
 bhs mkbtk2 yes - all done
 bsr putbsn put sector into bad block file
 leax 3,x move to next track #
 bra mkbtk0
mkbtk2 ldx badip anything in indirection block
 cmpx #badib
 bls mkbtk3 no - don't write
 lbsr wrtib write out indirection block
mkbtk3 ldx badip2 anything in 2nd indirection block
 cmpx #badib2
 bls mkbtk4 no - don't write
 lbsr wrtib2 write out 2nd level indirection block
mkbtk4
mkbtk9
* Adjust free block count by bad blocks
 ldd frebc+1
 subd badbc actual bad blocks
 std frebc+1
 ldb frebc
 sbcb #0
 stb frebc
* Adjust free block count by blocks used by /.badblocks
 ldd frebc+1
 subd badfbc
 std frebc+1
 ldb frebc
 sbcb #0
 stb frebc
* Set up size of /.badblocks file
 ldd badbc block count * 512
 addd badsbc include bad swap blocks
 addd badfdnbc include fdn blocks
 aslb
 rola
 std szfdn2
 clr szfdn2+2
 rts

*
* putbsn - put sector number in bad block file
*    X - sector # address
*
putbsn pshs x,y,u save pointer
 ldy fdnmp1 get block map pointer
 lda 0,x bad block in file or swap space
 cmpa volbc
 bhi 10f jump for swap space
 blo 05f
 ldd 1,x
 cmpd volbc+1
 bhs 10f jump for block in swap space
05 lda 0,x check for volume space or fdn space
 bne 06f must be in volume space
 ldd 1,x
 subd #2 adjust for overhead blocks
 cmpd fdnbc
 bhs 06f jump - in volume space
 ldd badfdnbc bump counter
 addd #1
 std badfdnbc
 bra 15f
06 ldd badbc get current bad block count
 addd #1
 std badbc
 bra 15f
10 ldd badsbc bump count of bad blocks in swap space
 addd #1
 std badsbc
15 ldd badbc get number of bad blocks so far
 addd badsbc
 addd badfdnbc
 cmpd #11 direct map?
 bge putbs1 no - check indirection
putbs0 lda ,x+
 sta ,y+
 ldd ,x++
 std ,y++
 lbra putbs9 all done
putbs1 bne putbs2
 lda badfbn set up 1st level indirect pointer
 sta ,y+
 sta bdibn
 ldd badfbn+1
 std ,y++
 std bdibn+1
 bsr bmpfbn
 bra putbs3
putbs2 cmpd #138 2nd level indirection?
 bgt putbs4
putbs3 ldu badip get indirection block pointer
 lda ,x+ copy block #
 sta ,u+
 ldd ,x++
 std ,u++
 stu badip
 cmpu #badib+(128*3) indirection block full?
 blo putbs9 no - exit
 bsr wrtib write indirection block
 ldu #badib reset pointer
 stu badip
 bra putbs9
putbs4 ldu badip get indirection pointer
 cmpu #badib start of new block
 bne putbs5
 ldu badip2 set up block # in 2nd level indirection block
 cmpu #badib2 start of 2nd level block?
 bne putbs5
 lda badfbn get free block #
 sta bdibn2
 sta ,y+ set up in file map
 ldd badfbn+1
 std bdibn2+1
 std ,y++
 bsr bmpfbn bump bad free block #
putbs5 lda badfbn set up block # in indirection block
 sta ,u+
 sta bdibn
 ldd badfbn+1
 std ,u++
 std bdibn+1
 stu badip2
 bsr bmpfbn consume free block
putbs6 ldu badip
 lda ,x+ copy block #
 sta ,u+
 ldd ,x++
 std ,u++
 stu badip save pointer
putbs9 sty fdnmp1
 puls x,y,u,pc return

*
* bmpfbn - bump free block # for bad block file
*
bmpfbn ldd badfbn+1
 addd #1
 std badfbn+1
 lda badfbn
 adca #0
 sta badfbn
 ldd badfbc bump free blocks used
 addd #1
 std badfbc
 rts

*
* wrtib - write out indirection block
*
wrtib pshs d,x,y,u save registers
 jsr clrbuf clear out work buffer
 ldx work copy indirection block contents
 ldy #badib
wrti00 ldd ,y++ copy info
 std ,x++
 cmpy #badib+(128*3)
 blo wrti00
 ldb bdibn
 clra
 ldy bdibn+1
 exg d,y
 jsr wrblk write out block
 lbcs wrbad -- can't be a bad block!
 puls d,x,y,u,pc return

*
* wrtib2 - write out 2nd level indirection block
*
wrtib2 pshs d,x,y,u save registers
 jsr clrbuf clear out work buffer
 ldx work copy indirection block contents
 ldy #badib2
wrti20 ldd ,y++ copy info
 std ,x++
 cmpy #badib2+(128*3)
 blo wrti20
 ldb bdibn2
 clra
 ldy bdibn2+1
 exg d,y
 jsr wrblk write out block
 lbcs wrbad -- can't be a bad block
 puls d,x,y,u,pc return


*
* clrbuf
*
* Clear out the working buffer
*

clrbuf ldx work point to buffer
 clra set count (256)
 pshs a
 clrb set d=0
clrbu2 std 0,x++ clear 2 bytes
 dec 0,s dec the count
 bne clrbu2
 ldx work reset to buf begin
 puls a,pc return

*
* clrfdn
*
* clear all FDN blocks on disk
*
clrfdn pshs d,x,y save registers
 bsr clrbuf clear working buffer
 ldy #0 set up block value
 ldd #2 FDN's start in block 2
 ldx fdnbc get count of FDN blocks
clrfd0 pshs d,x,y save registers
 jsr wrblk write block
 puls d,x,y restore registers
 addd #1 bump block #
 leax -1,x all FDN's written?
 bne clrfd0 no - keep going
 puls d,x,y,pc return


*
* mksir
*
* Make the sir (block 1)
*

mksir bsr clrbuf zero out buffer
 jsr snam setup names
 sys time,tbuf get time
 ldd tbuf transfer to sir
 std 8,x
 std 12,x
 ldd tbuf+2
 std 10,x
 std 14,x
 ldd fdnbc get fdn block count
 std 16,x save in block
 ldd volbc+1 get volume block count
 subd #1 dec by one (last block number here)
 std 19,x save in sir
 lda volbc get hi byte
 sbca #0 prop. cary
 sta 18,x save in sir
 ldd frebc get free block count
 std 21,x save in block
 lda frebc+2
 sta 23,x
 ldd fdnfc get fdn free count
 std 24,x save in sir
 ldd disktype get disk type
 std 58,x place in density/side flags
 cmpa #$FF special type for Winchester
 bne 10f
 leay 66,x configuration info in SIR
 ldu #d_DCT
 ldb #11
05 lda ,u+ copy device configuration table
 sta ,y+
 decb
 bne 05b
10 ldd swpsiz get swap size
 beq mksir4 is it zero?
 std 63,x set swap size
 ldd volbc+1 get start address
 std 61,x
 lda volbc
 sta 60,x
mksir4 bsr mffd make fdn in core list
 lbsr mfbl make in core free block list
 ldy #0 set up block number
 ldd #1 block 1
 jsr wrblk write out block
 lbcs wrbad -- can't be bad
 ldx work compute buffer address for reading
 leax 512,x
 stx r_SIR0 set up I/O call
 ldd dfd verify sir contents
 sys ind,isk
 ldd dfd
 sys ind,r_SIR
 bes mksir9
 ldx work
 leay 512,x point at read buffer
 leau 512,x compute end of buffer
mksir5 ldd ,x++ verify contents
 cmpd ,y++
 bne mksir9
 pshs u
 cmpx ,s++
 blo mksir5
 rts return - all OK
*
mksir9 ldd #STDOUT Unable to read/verify SIR block
 sys write,BdSIR,BdSIRs
 jsr report
 ldd #$00FF aborted status
 sys term
*
 data
BdSIR fcc 'Unable to read/verify SIR contents - disk unusable',$d
BdSIRs equ *-BdSIR
*
r_SIR fcb read read SIR block
r_SIR0 fdb 0 *** Address of buffer ***
 fdb 512
*
 text

*
* mffd
*
* Make the in core free fdn list
*

mffd ldx work point to buffer
 ldd badfdnbc any bad fdn blocks?
 bne 99f yes - don't use fdn free list
 ldd #50 set up max fdn count
 cmpd fdnfc is it greater than free count?
 bls mffd2
 ldd fdnfc use free count instead
mffd2 stb fdnic save in core count
 stb 88,x save in sir
 pshs b save it
 ldd #rtfcnt+1 set first avail fdn
mffd4 std 89,x save in list
 leax 2,x
 addd #1 bump fdn count
 dec 0,s dec the free count
 bne mffd4
 puls b
99 rts

*
* mfbl
*
* Make in core free block list
*

mfbl ldx work point to buffer
 ldb blkic get in core block count
 pshs b save as count
 leax 189,x set up SIR
 stb ,x+ save block count
 lda #3
 mul
 leax d,x
mfbl2 pshs x save address
 ldx #frseq point at free block #
 jsr isbad see if marked "bad"
 puls x restore address
 bcc mfbl3 good block - go to it
 ldd frseq+1 bump block #
 addd #1
 std frseq+1
 lda frseq
 adca #0
 sta frseq
 bra mfbl2 try again
mfbl3 ldd frseq+1 get sequence block number
 std ,--x save in list
 lda frseq
 sta ,-x save in list
 dec 0,s dec the count
 beq mfbl5 finished?
 ldd frseq+1 update block #
 addd #1 bump block number
 std frseq+1
 lda frseq
 adca #0
 sta frseq
 bra mfbl2
mfbl5 lda frseq save block #
 sta frblk
 ldd frseq+1
 std frblk+1
 leas 1,s clean up stack
 rts
*

*
* snam
*
* Set up name info in sir.
*

snam pshs x save pointer
 leax 26,x point to file system name entry
 ldu #fsnam point to entered name
 bsr xfnam transfer name to sir
 ldx 0,s reset pointer
 leax 40,x point to vol name entry
 ldu #vlnam point to name
 bsr xfnam xfr name to sir
 puls x reset ptr
 ldd vlnum get number
 std 54,x save in sir
 rts return

*
* xfnam
*
* Transfer names to sir block.
*

xfnam ldb #14 set count
xfnam2 lda 0,u+ get a char
 sta 0,x+ move it
 beq xfnam4 end of name?
 decb dec the count
 bne xfnam2 max length?
xfnam4 rts return


*
* mkrfdn
*
* Make root fdn.
*

mkrfdn jsr clrbuf zero buffer
 ldy #rtfdn copy fdn templates
 ldb #rtfsiz
mkrfd0 lda ,y+ copy fdn info
 sta ,x+
 decb
 bne mkrfd0
 ldx work reset pointer
 ldb #rtfcnt
mkrfd1 pshs b
 ldd tbuf set fdn mod time
 std 48,x
 ldd tbuf+2
 std 50,x
 leax 64,x bump to next FDN
 puls b
 decb
 bgt mkrfd1
* Set up file block map for /.
 ldx work reset pointer
 ldd fdnbc get fdn block count
 addd #2 bump by 2
 std 10,x save as block map
 ldd #2 set block number
 ldy #0
 jsr wrblk write block and return
 lbcs wrbad -- can't be bad
 rts
*
 data
*
*  FDNs for predefined files
*
rtfdn
rtfdn1 fcb $09 Directory
 fcb $3F permissions
 fcb $02 link count
 fcb 0,0,0,0
 fdb rtsiz Length
 rzb 64-(*-rtfdn1)
rtfdn2 fcb $01 Normal file
 fcb $80 Very Special permissions!
 fcb $01 link count
 fcb 0,0,0
szfdn2 rzb 3 length of file
mpfdn1 rzb 64-(*-rtfdn2)
rtfsiz equ *-rtfdn
rtfcnt equ rtfsiz/64
*
 text


*
* mkrtf
*
* Make the root file (dir).
*

mkrtf jsr clrbuf zero buffer
 ldy #rtdir
 ldb #rtsiz
mkrtf0 lda ,y+ copy file entries
 sta ,x+
 decb
 bne mkrtf0
 ldd fdnbc get block count
 addd #2 find first free block
 ldy #0
 jsr wrblk write block and return
 lbcs wrbad -- can't be bad
 rts
*
 data
*
*  Root directory information -- placed into file /.
*
rtdir
rtfn0 fdb 1 FDN number
 fcc '.'
 rzb 16-(*-rtfn0)
rtfn1 fdb 1 FDN number
 fcc '..'
 rzb 16-(*-rtfn1)
rtfn2 fdb 2 FDN number
 fcc '.badblocks'
 rzb 16-(*-rtfn2)
rtsiz equ *-rtdir
*
 text


*
* mkfree
*
* Make free block chain on disk.
*

mkfree
mkfre2 bsr dofb fill a free block list
 ldd frseq check if done
 cmpd volbc
 bne mkfre2
 lda frseq+2 check lo byte
 cmpa volbc+2
 bne mkfre2
 rts return

*
* dofb
*
* Fill up one block of the free list.
*

dofb jsr clrbuf zero the buffer
 ldb #99 set up count
 pshs b
 ldx work
 leax 3*99+3,x
dofb3
 ldd frseq+1 get to next block
 addd #1
 std frseq+1
 lda frseq
 adca #0
 sta frseq
 lda frseq if at end of disk - don't check
 cmpa volbc
 bne 0f
 ldd frseq+1
 cmpd volbc+1
 beq dofb6 exit - null forward link
0 pshs x save pointer
 ldx #frseq
 jsr isbad is this a bad block?
 puls x restore address
 bcs dofb3 yes - skip it
 lda frseq+2 get lo byte
 sta ,-x
 ldd frseq get block number
 std ,--x
 dec 0,s dec the count
 bne dofb3 repeat?
 leas 1,s clean up stack
dofb4 ldd frseq+1
 addd #1
 std frseq+1
 lda frseq
 adca #0
 sta frseq
 cmpa volbc check for end of disk
 bne dofb5
 ldd frseq+1
 cmpd volbc+1
 beq dofb6
dofb5 ldx #frseq
 jsr isbad
 bcs dofb4
 lda frseq
 ldx work
 lda frseq set up link
 sta ,x+
 ldd frseq+1
 std ,x++
dofb6 ldb frblk
 clra
 tfr d,y set hi part
 ldd frblk+1 get lo part
 jsr wrblk write out data block
 lbcs wrbad -- can't be bad
 lda frseq get new free block #
 sta frblk
 ldd frseq+1
 std frblk+1
 rts

*
* mkbt
*
* Make boot.
*

mkbt ldd #0 set block number 0
 std isk2
 std isk3 save in seek ind call
 ldx work copy bootstrap into a solid buffer
 ldy #uboot
10 ldd ,y++
 std ,x++
 cmpy #uboot+512 end of boot?
 blo 10b
 ldd #0 set to write block 0
 ldy #0
 jsr wrblk
 lbcs wrbad -- can't be bad
 rts return


*
* ckswap
*
* Check SWAP space for bad sectors
*
ckswap
 ldd volbc+1 get temp block #
 pshs d
 lda volbc
 pshs a
cksw0 lda 0,s end of volume?
 cmpa VOLCNT
 bne cksw1
 ldd 1,s
 cmpd VOLCNT+1
 beq cksw2 all done
cksw1 leax 0,s point at block #
 jsr isbad is this a bad block?
 bcs cksw9 yes - tell the guy
 ldd 1,s no - bump block #
 addd #1
 std 1,s
 lda 0,s
 adca #0
 sta 0,s
 bra cksw0
cksw2 leas 3,s clean up stack
 rts
cksw9 ldd #STDOUT print error message
 sys write,BadSB,BadSBs
 jsr report
 ldd #$00FF aborted status
 sys term
*
 data
BadSB fcc 'SWAP space contains one or more bad sectors - disk unusable!',$d
BadSBs equ *-BadSB
*
 text

*
* wrblk
*
* Write out the block in Y-D.
*

wrblk sty isk2 save block number
 std isk3
 ldx #isk2+1 check for bad sector
 jsr isbad
 bcs 99f
 ldd dfd get file desc
 sys ind,isk do seek
 ldx work
 stx w_addr
 ldd dfd get file desc
 sys ind,w_work
 bes wrberr error?
99 rts return

wrberr bsr wrbmsg
 jsr report
 ldd #$ff set status
 sys term exit
*
 data
w_work fcb write
w_addr fdb 0
 fdb 512
*
 text
*
wrbmsg
 bsr MapHex
 stx wberm0
 ldd isk2
 bsr MapHex
 stx wberm1
 ldd isk3
 jsr MapHex
 std wberm1+2
 stx wberm1+4
 ldd #STDOUT set file desc
 sys write,wberm,WMS output error
 rts
*
wrbad ldd isk2 get block #
 jsr MapHex
 stx wbbkm0
 ldd isk3
 jsr MapHex
 std wbbkm0+2
 stx wbbkm0+4
 ldd #STDOUT
 sys write,wbbkm,WBBKMS
 jsr report
 ldd #$00FF aborted status
 sys term
*
 data
wbbkm fcc 'Required track has bad spot - sector # '
wbbkm0 fcc 'XXXXXX',$d
WBBKMS equ *-wbbkm
*
 text

*
* MapHex - Map the value in (D) into printable hex
*  characters in D.X
*
MapHex pshs d
 bsr MapHx0
 pshs d
 lda 3,s
 bsr MapHx0
 puls x
 exg d,x
 leas 2,s pop register
 rts
MapHx0 tfr a,b save value
 lsra
 lsra
 lsra
 lsra
 bsr MapHx1
 exg a,b
 bsr MapHx1
 exg a,b
 rts
MapHx1 anda #$0F strip off junk
 cmpa #$0A
 blo MapHx2
 adda #'A-'0-$0A
MapHx2 adda #'0
 rts

*
* cvtdec - convert an integer into a decimal string
*    D - integer value
*    X - string address (6 characters +nnnnn)
*
cvtdec pshs d,x,y,u save registers
 cmpd #0 check sign
 blt cvtd10
 pshs d
 lda #'
 bra cvtd15
cvtd10
 coma
 comb
 addd #1
 pshs d
 lda #'-
cvtd15 sta ,x+ set up sign
 puls d get value to convert
 ldy #cvttbl
cvtd20 clr 0,x compute digit
cvtd30 cmpd 0,y check range
 blt cvtd40
 inc 0,x
 subd 0,y
 bra cvtd30
cvtd40 pshs b
 ldb 0,x turn into a number
 orb #'0
 stb 0,x+
 puls b
 leay 2,y move to next table entry
 cmpy #cvttbe end of table?
 blo cvtd20
 leax -1,x point at last digit
 pshs x
 ldx 4,s restore original pointer
 leax 1,x bump past sign
cvtd50 lda 0,x perform zero suppression
 cmpa #'0
 bne cvtd57
 lda #'
cvtd55 sta ,x+
 cmpx 0,s end of number string?
 blo cvtd50
cvtd57 leas 2,s clean up stack
cvtd90 puls d,x,y,u,pc return
*
 data
cvttbl fdb 10000
 fdb 1000
 fdb 100
 fdb 10
 fdb 1
cvttbe
*
 text

*
* isbad - check to see if a block is in the "bad" list
*    X - block number address
*
*  return with carry set if block is bad
*
isbad pshs d,x,y,u save registers
 ldy #Bsclst get bad sector list address
isbd10 cmpy Bscptr any more sectors to search?
 bhs isbd90 no - must be OK
 ldd 0,x compare block #s
 cmpd 0,y
 bne isbd40
 lda 2,x
 cmpa 2,y
 beq isbd95 exit - found bad block
isbd40 leay 3,y bump to next bad sector
 bra isbd10
isbd90 clc return - not bad
 bra isbd99
isbd95 sec bad block
isbd99 puls d,x,y,u,pc return

*
* decvt
*
* Decimal convert routine.  Convert ascii string
* pointed at by x and null terminated.
* Return number in D and ne if error.
*

decvt ldd #0 set up zero
 pshs d
 lda ,x check for '=NNN'
 cmpa #'=
 bne 10f
 leax 1,x bump past "="
10 lda 0,x+ get character
 cmpa #'0 check for valid number
 blo 20f error?
 cmpa #'9
 bhi 20f
 anda #$F mask character
 pshs a save digit
 ldd 1,s get number
 aslb multiply by 8
 rola
 aslb
 rola
 aslb
 rola
 addd 1,s add in original twice
 addd 1,s
 addb 0,s+ add in new digit
 adca #0
 std 0,s save result
 bra 10b repeat
20 leax -1,x backup one
 puls d,pc return

 data

E1 fcc 'No permission.',$d
S1 equ *-E1
E2 fcc 'Too many fdn blocks specified.',$d
S2 equ *-E2
E3 fcc "Can't open device.",$d
S3 equ *-E3
E5 fcc 'Bad argument specified.',$d
S5 equ *-E5
E7 fcc 'The device is mounted and busy!',$d
S7 equ *-E7
wberm fcc 'Disk write error - Code: '
wberm0 fcc 'XX - sector: '
wberm1 fcc 'XXXXXX',$d
WMS equ *-wberm
crst fcb $d carriage return
N1 fcc 'File system name? '
Z1 equ *-N1
N2 fcc 'Volume name? '
Z2 equ *-N2
N3 fcc 'Volume number? '
Z3 equ *-N3

wsk fcb seek
 fcb 0
wsk2 rzb 3
 fdb 0 seek direction

isk fcb seek
isk2 fdb 0
isk3 fdb 0,0

fdnbc fdb 128 fdn block count
r0 rzb 4 divide reg
r1 rzb 2 divide reg
rmndr rzb 2 div reg
mpytmp rzb 4
dfd rzb 2 file desc
tbuf rzb 8 time buffer
frblk rzb 3 block # of free block
volbc rzb 3 volume block count
frebc rzb 3 free block count
fdnfc rzb 2 free fdn count
fdnic rzb 1 in core fdn count
blkic rzb 1 in core block count
frseq rzb 3 free sequence number
track rzb 3 track number
errbuf rzb 6 space for error info
argpt rzb 2 arg ptr
swpspc rzb 2 swap space
swpsiz rzb 2 swap size
nonam rzb 1 no name flag
quiet rzb 1 "quiet" mode flag
List_opt rzb 1 +L (Interactive bad block list)
list_opt rzb 1 +l (File bad block list)
Get_parms rzb 1 +P (Interactive disk parameters)
Verify rzb 1 "verify" option flag
optfdn rzb 2 optional fdn block count
new_boot rzb 1 re-write boot only option
intopt rzb 1 interleave option
disktype fdb 0 Disk type
diskindex fdb DNT pointer into DNT
d_DCT rzb 11 Device Characteristics Table
DCTset fdb $FF00 ** Marks Winchester special **
 fdb 0,d_DCT
*
ex_mem fcb cdata extend memory allocation
lastaddr fdb END highest address ever needed
*
* Bad sector list
*
MaxBSC equ 256 Number of Bad Sectors Allowed
Bsclst rzb 3*MaxBSC
Bscptr fdb Bsclst
badbc fdb 0 count of bad blocks
badsbc fdb 0 count of bad swap blocks
badfdnbc fdb 0 count of bad fdn blocks
badfbc fdb 0 free blocks used in /.badblocks
badfbn rzb 3 "free" block number
badip fdb 0 indirection block pointer
badip2 fdb 0 2nd level indirection block pointer
bdibn rzb 3 "bad" indirection block #
bdibn2 rzb 3 2nd level "bad" indirection block #
fdnmp1 fdb mpfdn1 file block map FDN #1
work fdb 0 Pointer to contiguous working space
*
model fcc '        '
*
*  Disk parameters
*
N_CYL fdb 0 Cylinders
N_HD fdb 0 Heads
N_ST fdb 17 Sectors / Track
BRW fdb 0 Begin Reduced Write Cylinder
BWP fdb 0 Begin Write Precomp Cylinder
VOLCNT rzb 3 Cylinders*Sectors*Heads
*
* Information fields for SIR
*
vlnum rzb 2 volume number
vlnam rzb 16 volume name
fsnam rzb 16 file sys name
resbuf rzb 32 response buffer

badib rzb 512 Indirection block for /.badblocks
badib2 rzb 512 2nd level indirection block
 end Format
