 ttl UniFLEX Disk Formatter
 sttl WD 1000 5" Winchester Bootstrap
 pag
 info Bootstrap for MPU/WD1000 Version 2.02; 11/09/83
* 11/09/83 - Added single/multi-unit volume handling

* UniFLEX Bootstrap Loader for WD 1000 5" Winchester

 global uboot,DCtbl

* Equates
ffmap equ 17 file map offset in fdn
bhxfr equ 10 transfer address offset in header
BHDSIZ equ 24 binary file header size
*
* equates and addresses
*
board equ $E000 DMF-3 Interface Base Address
*
DMAXAL equ board+$25 Extended Address Latch
*
DMAC1A equ board+$04 DMA Channel 1 Address
DMAC1C equ board+$06 DMA Channel 1 Count
DMACC1 equ board+$11 DMA Channel 1 Control Register
DMAPRC equ board+$14 DMA Priority Control Register
DMADCR equ board+$16 DMA Data Control Register
*
wd1000 equ board+$30 Western Digital Interface
*
wd_data equ wd1000+0 data register
wd_error equ wd1000+1 error register
wd_sec_num equ wd1000+3 sector number
wd_cyl_low equ wd1000+4 cylinder (low part)
wd_cyl_hi equ wd1000+5 cylinder (high part)
wd_sdh equ wd1000+6 size/drive/head
wd_status equ wd1000+7 status register
wd_cmd equ wd_status command register
*
wd_read equ %00101000 read sector with DMA

* Temporary storage

 base $00E0 Page 0 data

r0 rmb 4 divide work registers
r1 rmb 2
rmndr rmb 2
btdate rmb 4
direct rmb 1
mapptr rmb 2
fdnbkn rmb 3
entrys rmb 2
xfradr rmb 2
drive rmb 1

* Special locations

corcnt equ $13
lstmem equ $14

DATMAP equ $F40A Map for $A000
BLKHOLE equ $FF Black hole in map
DATSENSE equ $00 Sense of data in DAT

old_org equ $B000 org of loader as loaded by ROM
new_org equ $B800 new org of loader

 base new_org+512
buffer rmb 512
map rmb 512
*
 data

* Lookup "uniflex" in directory

uboot lbra uboot0 *** For SWTPC! ***
* filename for booting
btname fcc 'uniflex'
 fcb 0,0,0,0,0,0,0
*
uboot0
*
* Relocate loader from "old_org" to "new_org"
*
 ldx #old_org
 ldu #new_org
00 ldd ,x++ move loader text
 std ,u++
 cmpx #old_org+512
 blo 00b
 lbra (uboot1-old_org)+new_org
*
uboot1 lda $010A check block $A000 mapped in
 cmpa #BLKHOLE black hole?
 bne uboot2
 dec corcnt decrease number of pages available
 ldx lstmem pick up last page pointer
 lda ,-x get a page
 stx lstmem
 sta $010A set up map
 sta DATMAP
uboot2 ldd #1 root directory fdn no.
 lbsr fdnblk read in fdn
 ldd 7,y find size of directory
 bsr divby8
 lsra
 rorb
 std entrys save entry count
read1 lbsr rdblk read data block
 bne loaderr exit if error
lookup leax 2,u point to filespec
 ldy #btname-uboot+new_org point to boot file name
 ldb #14 set name length
cmpnam lda 0,x+
 cmpa 0,y+ is this boot file entry?
 bne nxtent if not, skip to next
 decb
 bne cmpnam
 ldd 0,u found it, get fdn
 bra load go load uniflex
nxtent ldx entrys
 leax -1,x decrement count
 stx entrys end of directory?
 beq noboot error if so
 leau 16,u point to next entry
 cmpu #buffer+512 past current block?
 bne lookup check entry if not
 bra read1 else, get another block


* Load UniFLEX

load bsr fdnblk read in uniflex fdn
 ldx mapptr point to fdn map
 ldd 13*3,x save boot date
 std btdate
 ldd 13*3+2,x
 std btdate+2
 bsr rdblk read 1st block of the file
loaderr bne noboot exit if error
 ldd bhxfr,u get transfer address
 std xfradr save it
 leau BHDSIZ,u skip binary file header
getrc1 bsr getchr get record length in x
 tfr b,a
 bsr getchr
 pshs d terminator?
 ldx ,s++
 beq done start uniflex if so
 bsr getchr get load address in y
 tfr b,a
 bsr getchr
 tfr d,y
getrc2 bsr getchr get a data byte
 stb 0,y+ put in memory
 leax -1,x decrement the count
 bne getrc2 loop if not end of record
 bra getrc1 else, get next record

* Uniflex is loaded, begin execution

done ldu $5002 get boot date vector
 ldd btdate copy boot date
 std ,u++
 ldd btdate+2
 std ,u++
 jmp [xfradr] jump to transfer address

* Divide contents of D by 8

divby8 lsra
 rorb
 lsra
 rorb
 lsra
 rorb
 rts

* Get single character from binary file

getchr cmpu #buffer+512 more data in buffer?
 bne getch2 skip if so
 pshs a,x,y
 bsr rdblk else, read another block
 puls a,x,y
 bne nbootx exit if error
getch2 ldb 0,u+ get character, advance ptr
 rts

* Uniflex file was not found

nbootx puls d fix stack
noboot rts return to monitor ROM

* Read fdn specified in D

fdnblk pshs d save fdn number
 addd #15 convert to block number
 bsr divby8
 std fdnbkn+1 save fdn block #
 clr fdnbkn
 ldy #fdnbkn
 bsr mread read a block
 puls d restore fdn number
 bne nbootx exit if error
 decb calculate buffer offset
 andb #$07
 lda #64
 mul offset=(fdn&7)*64
 addd #map
 tfr d,y fdn pointer in y
 addd #9 point to ffmap
 std mapptr save map pointer
 lda #10 get direct block count
 sta direct initialize indirect flag
 rts

* Read a block from file

rdblk tst direct a direct block?
 beq chgind change to indirect
 dec direct dec. direct count
 ldy mapptr get file map pointer
 ldx #buffer setup buffer address
 bsr xread read the sector
 pshs cc
 sty mapptr
 puls cc,pc

chgind ldy mapptr get file map pointer
 bsr mread read block of indirects
 bne nbootx exit if error
 stu mapptr reset file map pointer
 lda #128 set new direct count
 sta direct
 bra rdblk now read data block

* Read the specified map block

mread ldx #map address of buffer for block

* Read a single sector
*  X - Buffer Address
*  Y - Block # Pointer

xread leau 0,x save X pointer
 lbsr setadr set up DMA address
 ldb ,y+ calculate disk address
 clra
 std r0
 ldd ,y++
 std r0+2
 ldd #17 Sectors/Track
 std r1
 bsr ldiv
 ldb rmndr+1 get sector #
 incb adjust (no sector 0)
 stb wd_sec_num
 ldb DCtbl+2-uboot+new_org get number of heads
 clra
 std r1
 bsr ldiv
 ldd r0+2
 clr drive
 tst multi-uboot+new_org multi-drive volume?
 beq 00f jump if not
 cmpd DCtbl-uboot+new_org which drive?
 blo 00f
 subd DCtbl-uboot+new_org adjust to second drive
 inc drive
00 sta wd_cyl_hi
 stb wd_cyl_low
 ldb rmndr+1 get head #
 orb #$20+$80 set for 512 byte sectors and ECC
 pshs b
 ldb drive
 lslb
 lslb
 lslb
 orb ,s+
 stb wd_sdh
 lda #wd_read send command
 sta wd_cmd
10 lda DMACC1 wait for DMA complete
 bmi 20f
 lda wd_status operation fail?
 bpl 15f not busy - must have!
 bsr delay delay a while
 bra 10b
15 bita #1 error bit set?
 beq 10b no - assume everything OK
 rts return - error
20 clra -- shut down DMA
 clrb
 std DMAPRC
 rts

*
* '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
 clra -- do init
 clrb
 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

* convert address for dmaf

setadr lda $010B get memory map value
 tfr a,b
 lsra get upper half
 lsra
 lsra
 lsra
 ora #$10 set for channel 1
 sta DMAXAL set up DMA address
 eorb #DATSENSE
 lslb get lower half
 lslb
 lslb
 lslb
 pshs b save it
 tfr x,d get address
 anda #$0F mask off upper 4 bits
 ora 0,s+ replace with map bits
 std DMAC1A
 lda #8 set for 4 channel mode
 sta DMADCR
 ldd #512 set up count
 std DMAC1C
 clr DMACC1 set for dma read
* lda #2 enable channel 1 *** Caution ***
 sta DMAPRC
 rts

*
* delay - delay for a short while
*
delay ldx #500
10 leax -1,x
 bne 10b
 rts


DCtbl fdb 306 Cylinders
 fcb 6 Heads
multi fcb 0 Single/Multi-drive volume indicator

* filler bytes

 if (*-uboot)>512
 err 'Bootstrap overflow'
 else
 rzb 512-(*-uboot)
 endif
 end
