   ttl   APM System ROM Bootstrap

   bin

date   equ $190287  Last revision date
disk   equ 0        Remote Filestore
*disk  equ '2284'   Fujitsu 160 MB 14"
*disk  equ '2294'   Fujitsu 330 MB 14"
*disk  equ 'Mini'   Pair of 10MB 8"
*disk  equ '202E'   Rodime 20MB 5.25"
*disk  equ '204E'   Rodime 40MB 5.25"
*disk  equ '2243'   Fujitsu 80MB 5.25"
dcon   equ 0        Remote filestore
*dcon  equ '7261'   NEC chip with 14" Fuji drives
*dcon  equ 'WD1k'   WD1000 controller for mini-filestore
*dcon  equ 'HFDC'   Ambit-Pace controller for 5.25" drives
memory equ $600000  6 megabytes to initialise
 ifeq disk
favourite equ $1B
 else
favourite equ $80
 endc

* (c) Rainer W Thonnes 1984, 1987
* Edinburgh University Computer Science Dept
* All rights reserved

* Initialises RS232 port (ACIA), ethernet board,
* system bus mapping registers and main memory,
* thereby determining how much of it there is.
* Loads a supervisor into local RAM at $1000.
* The name of the file containing this supervisor,
* and the ethernet address of the file server from
* which it is read have default values which may be
* overridden by striking any key on the keyboard
* before the memory initialisation has completed.

* All exceptions are re-directed through a pseudo
* vector table starting at address $1000 (local RAM).

* There is an assembly-time option to include a driver
* for a local disk.  When this is included, specifying
* $80 as the remote file server ether address causes
* the local disk to be used instead for system booting.

* When loading off disk, one of two "boot areas" on the
* disk is used (determined by the position of the key
* switch on the front of the machine).  Each boot area
* is 1024 512-byte blocks long and contains a short
* directory of named files.

* Configuration variables (in rom)

gropelimit equ  $ffc
gropestart equ  $ff8
version    equ  $ff4
defstat    equ  $ff7
deffile    equ  $ff0

* Communication variables

memtop     equ  $3ffc
membot     equ  $3ff8
freetop    equ  $3ff4
freebot    equ  $3ff0
ffile      equ  $3fac
lstat      equ  $3fa8
lport      equ  $3fa9
rstat      equ  $3faa
rport      equ  $3fab

* Local store limits

ram        equ $1000
syssp      equ $3f00  (NB <= end of store - 32)

* VDU (ACIA) definitions

vdus equ $4000c1
vdud equ $4000c3
vinit equ 3
viof  equ $11
vrrfbit equ 0
vtrebit equ 1
vbrkbit equ 4

cr  equ 13
lf  equ 10
nl  equ 10
del equ 127

* Ethernet definitions

eths equ $7fffc      * Status register
ethd equ $7fffd      * Data register
ethc equ $7ffff      * Control register
einit  equ $40
eiof   equ 0
etebit equ 3
erdbit equ 2
ercbit equ 1
opn equ $80
cls equ $90
rdy equ $10
stx equ $20
dtx equ $30
ack equ $c0
nak equ $50
etx equ $0b
esa equ $05
ssa equ $07

* Other definitions

arbiter equ $f00003
map0    equ $080000
mapinc  equ $100000

  ifne disk

* Disk controller definitions

   ifeq dcon-'HFDC'
diskcsr equ $ed0000
   endc dcon='HFDC'
   ifeq dcon-'WD1k'
   org $7ffe0
diskcsr     ds.w 1
disksdh     ds.w 1
diskcylh    ds.w 1
diskcyll    ds.w 1
disksector  ds.w 1
disksectors ds.w 1
diskerror   ds.w 1
diskdata    ds.w 1
   endc dcon='WD1k'
   ifeq dcon-'7261'
   org $70000
diskbuf ds.b 4096  * Disk buffer on controller board
diskdbr ds.b 1     * 7261 data fifo
diskcsr ds.b 1     * 7261 control reg
diskbcr ds.w 1     * board control register
   endc dcon='7261'
  endc disk#0

*
* START OF ROM CODE
*

   org 0

   dc.l syssp   * Initial stack pointer
   dc.l begin   * Initial program counter
   dc.l v2      * Interrupt and Exception vectors
   dc.l v3
   dc.l v4
 nolist
 dc.l v5
 dc.l v6
 dc.l v7
 dc.l v8
 dc.l v9
 dc.l v10
 dc.l v11
 dc.l v12
 dc.l v13
 dc.l v14
 dc.l v15
 dc.l v16
 dc.l v17
 dc.l v18
 dc.l v19
 dc.l v20
 dc.l v21
 dc.l v22
 dc.l v23
 dc.l v24
 dc.l v25
 dc.l v26
 dc.l v27
 dc.l v28
 dc.l v29
 dc.l v30
 dc.l v31
 dc.l v32
 dc.l v33
 dc.l v34
 dc.l v35
 dc.l v36
 dc.l v37
 dc.l v38
 dc.l v39
 dc.l v40
 dc.l v41
 dc.l v42
 dc.l v43
 dc.l v44
 dc.l v45
 dc.l v46
 dc.l v47
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
 dc.l v23
   list
   dc.l v23
   dc.l v23
   dc.l v23

* Miscellaneous entry points

   move.l deffile,a0 * 400: reload (default filename)
   bra    reload     * 404: reload (A0=filename)
   bra    load       * 408: load file (A0) to (A1)+
   bra    lhex       * 40c: phex
   bra    whex       * 410: phex4
   bra    bhex       * 414: phex2
   bra    nhex       * 418: phex1
   bra    psym       * 41c: printsymbol
   bra    pstring    * 420: printstring

good macro
v\1 move.l \1*4+ram,-(sp)
    rts
    endm

bad macro
v\1 bsr badvector
    dc.w \1*4
    endm

* Unacceptable vector numbers are re-cast as
* address errors at the vector address

badvector move.l a0,-(sp) * save A0
    move.l 4(sp),a0       * @ vector address .w
    move.w #$dead,6(sp)   * value for IR
    move.w (a0),4(sp)     * vector address...
    move.l (sp),a0        * restore A0
    move.w #0,2(sp)       * ...zero-extended
    move.w #$1e,(sp)      * function code SPRnot
    move.l ram+12,-(sp)   * soft address error vector
    rts

    good <2>  bus error
    good <3>  address error
    good <4>  illegal
    good <5>  zero divide
    good <6>  chk
    good <7>  trapv
    good <8>  privilege
    good <9>  trace
    good <10> A emulator
    good <11> F emulator
    bad  <12>  reserved...
    bad   13
    bad   14
    bad   15
    bad   16
    bad   17
    bad   18
    bad   19
    bad   20
    bad   21
    bad   22
    bad  <23>  ...reserved
    good <24> spurious interrupt
    good <25> autointerrupt 1...
    good  26
    good  27
    good  28
    good  29
    good  30
    good <31> ...autointerrupt 7
    good <32> trap 0...
    good  33
    good  34
    good  35
    good  36
    good  37
    good  38
    good  39
    good  40
    good  41
    good  42
    good  43
    good  44
    good  45
    good  46
    good <47> ...trap 15

* Print character D0 on VDU
* preserving registers and SR

psym cmp.b #lf,d0
   beq.s psy
   cmp.b #cr,d0
   bne.s ps0
psy eor.b #cr!!lf,d0
   bsr.s ps0
   eor.b #cr!!lf,d0
   bra ps0
ps0 btst.b #vtrebit,vdus
   beq ps0
   move.b d0,vdud
ps1 btst.b #vtrebit,vdus
   beq ps1
   rts

* Print D0 in hex

lhex swap d0
   bsr.s whex
   swap d0
whex rol.w #8,d0
   bsr.s bhex
   rol.w #8,d0
bhex rol.b #4,d0
   bsr.s nhex
   rol.b #4,d0
nhex move.l d1,-(sp)
   moveq #15,d1
   and.b d0,d1
   cmp.b #9,d1
   ble.s nh1
   addq.b #7,d1
nh1 add.b #'0',d1
   exg d0,d1
   bsr psym
   exg d0,d1
   move.l (sp)+,d1
   rts

* Print string A0 on VDU
* length-prefixed but 0-terminated

pstring movem.l d0/d1/a0,-(sp)
   move.b (a0)+,d1
   beq.s ps3
ps2 move.b (a0)+,d0
   beq.s ps3
   bsr psym
   subq.b #1,d1
   bne ps2
ps3 movem.l (sp)+,d0/d1/a0
   rts

ptext macro
\* move.l a0,-(sp)
   lea t\@,a0
   bsr pstring
   bra.s e\@
t\@ dc.b 255,\1,0
   ds.w 0
e\@ move.l (sp)+,a0
   endm

breaktest macro
\* btst #vbrkbit,vdus
   bne abort
   endm

* Wait for ether station
* TX buffer to empty

flush breaktest
   btst.b #etebit,eths
   beq flush
   rts

* Read control character from ether station to D0

skipdc move.b ethd,d0
readcc breaktest
   move.b eths,d0
   btst #erdbit,d0
   bne skipdc         * Data: skip
   btst #ercbit,d0
   beq readcc         * No control: loop
   move.b ethc,d0     * Read control
   cmp.b #nak,d0      * Jump out if NAK
   beq gotnak
   rts

* Read data character from ether station

readdc breaktest
   move.b eths,d0
   btst #erdbit,d0
   beq readdc
   move.b ethd,d0
   rts

* Wait for RDY

rdywait bsr readcc
   cmp.b #rdy,d0
   bne rdywait
   bsr readdc
   rts

* Send DTX, wait for RDY, send STX

out bsr flush
   move.b #dtx,ethc
out1 bsr flush
   move.b lport,ethd
   bsr rdywait
   move.b #stx,ethc
   bsr flush
   move.b lport,ethd
   bsr flush
   rts

* Wait for DTX, send RDY, wait for STX

in bsr readcc
   cmp.b #dtx,d0
   bne in
   bsr readdc
   move.b #rdy,ethc
   bsr flush
   move.b lport,ethd
stxwait bsr readcc
   cmp.b #stx,d0
   bne stxwait
   bsr readdc
   rts

* Open a local port to the remote filestore

open bsr flush
   move.b #opn,ethc
   bsr out1
   move.b rstat,ethd
   bsr flush
   move.b rport,ethd
   bsr flush
   move.b #etx,ethc
   bsr flush
   rts

* Load file (A0) to (D0)+
* result: length in D0, endad in A0

load tst.b lport
  ifne disk
    beq diskload
  endc
   movem.l d1-d2/a1,-(sp)
   move.l d0,a1
   bsr out
   move.b #'Z',ethd   * Send Readfile command,
   bsr flush
   move.b #'0',ethd
   bsr flush
   moveq #0,d1
   move.b (a0)+,d1
   subq #1,d1
l1 move.b (a0)+,d0    * the filename,
   move.b d0,ethd
   bsr flush
   dbra d1,l1
   move.b #nl,ethd    * newline, and ETX.
   bsr flush
   move.b #etx,ethc
   bsr in             * Read response line packet
   bsr readdc
   cmp.b #'-',d0
   beq fserr
   bsr readcc         * skip to ETX
   moveq #0,d2        * Size counter
l2 bsr in             * Read data packet
   move #512,d1
l3 move.b eths,d0     * Wait for data or control
   btst #erdbit,d0
   bne.s l4           * data ->
   btst #ercbit,d0
   beq.s l3           * no control: loop
   move.b ethc,d0     * skip ETX
   tst d1             * was this a 512-byte block?
   beq l2             * yes: read another
   move.l d2,d0       * no: terminate
   movem.l (sp)+,d1-d2/a1
   rts
l4 move.b ethd,(a1)+  * read one character
   addq.l #1,d2       * count it
   subq #1,d1         * adjust intra-block count
   bra l3

 ifne disk                 * Disk handling routines
  ifeq dcon-'HFDC'         * Ambit-Pace controller
   ifeq disk-'2243'
cyls  equ 754
heads equ 11
   endc
   ifeq disk-'202E'
cyls  equ 640
heads equ 4
   endc
   ifeq disk-'204E'
cyls  equ 640
heads equ 8
   endc
* We assume 16 512-byte sectors per track

diska move.b diskcsr,d1         Wait for A0
   cmp.b #$a0,d1
   bne diska
   move.b d0,diskcsr            Send command code
dw1 move.b diskcsr,d1           Wait for A1
   cmp.b #$a1,d1
   bne dw1
   move.b #$ff,diskcsr          Send FF
* and fall through to
diskw movem.l d0-d7/a0-a6,-(sp) Wait >= 50 us
   movem.l (sp)+,d0-d7/a0-a6
   movem.l d0-d7/a0-a6,-(sp)
   movem.l (sp)+,d0-d7/a0-a6
   movem.l d0-d7/a0-a6,-(sp)
   movem.l (sp)+,d0-d7/a0-a6
   rts

diskb move.b #$ff,diskcsr      Send FF
   bsr diskw                   Wait 50 us
dw2 move.b diskcsr,d1          Wait for FF
   cmp.b #$ff,d1
   bne dw2
   move.b #$fe,diskcsr         Send FE
dw3 move.b diskcsr,d0          Wait for xx&80=0
   bmi dw3
   move.b diskcsr,d0           Get status
   move.b #0,diskcsr           Send 00
   moveq #$60,d1               Check for error
   and.b d0,d1
   bne.s dw4
   rts
dw4 bsr bhex
   lea diskmerr,a0
   bsr pstring
   bra abort
diskmerr dc.b 255,' disk error',0
   ds.w 0

diskreset move.b #0,diskcsr  Send initial 00
   move.b #$42,d0            Write buffer command
   bsr diska
   move.b #$ff,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   move.b #4,diskcsr
   move.b #(cyls-1)&255,diskcsr
   move.b #(cyls-1)>>8,diskcsr
   move.w #512-1-16+7,d0
dil move.b #0,diskcsr
   dbra d0,dil
   bsr diskb
   move.b #2,d0              Init command
   bsr diska
   bsr diskb
   rts

diskread movem.l d0-d3,-(sp)
   move.b #$21,d0            Read disc command
   bsr diska
   move.l (sp),d0            Byte number
   moveq #9,d1
   lsr.l d1,d0               Block number
   moveq #15,d1
   and d0,d1                 Sector number
   lsr.l #4,d0
   divu #heads,d0
   swap d0
   move d0,d2                Head number
   clr.w d0
   swap d0
   divu #cyls,d0
   clr.w d0
   swap d0                   Cylinder number
   move.b #0,diskcsr
   move.b d2,diskcsr
   move.b d0,diskcsr
   lsr #8,d0
   move.b d0,diskcsr
   move.b d1,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   move.b #0,diskcsr
   bsr diskb
   move.b #$41,d0           Read buffer command
   bsr diska
   move.w #511,d0
drl move.b diskcsr,(a0)+
   dbra d0,drl
   bsr diskb
   movem.l (sp)+,d0-d3
   rts

  endc dcon='HFDC'
  ifeq dcon-'WD1k'

diskwait move.w diskcsr,d0
   btst #7,d0               loop while busy
   bne diskwait
   move.w diskcsr,d0        inspect status
   btst #0,d0
   bne diskw1
   rts                      return if no error
diskw1 lea diskmerr,a0      otherwise report error
   bsr pstring
   lea diskcsr,a0
   movep.l 1(a0),d0
   bsr lhex
   movep.l 9(a0),d0
   bsr lhex
   move.l (sp),d0
   bsr lhex
   bra abort
diskmerr dc.b 255,'Disk error ',0
   ds.w 0

* Initialise controller
diskreset move.w #$20,diskerror (precomp)
   clr.w d7
   move.w d7,disksdh          drive 0
   move.w #$13,diskcsr        restore
   bsr diskwait
   move.w d7,diskcylh
   move.w d7,diskcyll
   move.w #$70,diskcsr        seek
   bsr diskwait
   move.w #8,disksdh          drive 1
   move.w #$13,diskcsr
   bsr diskwait
   move.w d7,diskcylh
   move.w d7,diskcyll
   move.w #$70,diskcsr
   bsr diskwait
   rts

* Read 512-byte-block D0>>9 to (A0)+
diskread movem.l d0-d3,-(sp)
   moveq #9,d1
   lsr.l d1,d0
   and.l #$3fff,d0
   moveq #15,d1
   and d0,d1
   add d1,d1         sector
   lsr #4,d0
   moveq #3,d2
   and d0,d2         track
   lsr #2,d0
   clr.l d3
   move.b d0,d3      cylinder
   lsr #5,d0
   and #8,d0
   or d0,d2          sdh
   move.w d1,disksector
   move.w d2,disksdh
   move.w #0,diskcylh
   move.w d3,diskcyll
   move.w #$20,diskcsr
   bsr diskwait
   move.w #255,d0
diskr1 move.b diskdata+1,(a0)+
   dbra d0,diskr1
   add.w #1,disksector
   move.w #$20,diskcsr
   bsr diskwait
   move.w #255,d0
diskr2 move.b diskdata+1,(a0)+
   dbra d0,diskr2
   movem.l (sp)+,d0-d3
   rts

  endc dcon='WD1k'
  ifeq dcon-'7261'

   ifeq disk-'2284'         * 10 tracks per cylinder
tracks equ 10
   endc disk='2284'
   ifeq disk-'2294'
tracks equ 16
   endc disk='2294'

parm macro
\* move.b \1,diskdbr
   endm

* Wait for controller
cwait move.b diskcsr,d0
   bmi cwait                * busy ->
   cmp.b diskcsr,d0
   bne cwait                * unstable ->
   rts

* Wait for SRQ
dwait moveq #16,d0
   and.b diskcsr,d0
   beq dwait
   move.b d0,diskcsr
   bsr cwait
   moveq #7,d0
   and.b diskdbr,d0
   rts

* Controller initialisation data
* Mode,DtlH+,DtlL,Etn,Esn,Gpl2,Mgpl1
cdata dc.b $40,$82,0,tracks-1,31,16,10
   ds.w 0

* Initialise controller
diskreset move.w #$8000,diskbcr
   moveq #-1,d0
   dbra d0,*
   move.w #0,diskbcr        * normal
   dbra d0,*
   moveq #6,d0
   lea cdata,a0
cloop parm (a0)+
   dbra d0,cloop
   move.b #$20,diskcsr      * specify
dwait7 bsr dwait
   cmp #7,d0
   bne dwait7
   move.b #$50,diskcsr      * recal
dwait8 bsr dwait
   tst d0
   bne dwait8
   rts

* Read 512-byte-block D0>>9 to (A0+)
diskread movem.l d0-d4/a1,-(sp)
   lsr.l #5,d0
   lsr.l #4,d0
   divu #32,d0
   swap d0
   move d0,d4     *sector
   clr.w d0
   swap d0
   divu #tracks,d0
   swap d0
   move d0,d3     *track
   swap d0
   move d0,d2     *cyll
   ror.w #8,d0
   move d0,d1     *cylh
   move.b #2,diskcsr     * clear fifo
   parm d1               * CylH
   rol.w #8,d0
   parm d2               * CylL
   move.b #$60,diskcsr   * Seek
dwait0 bsr dwait
   tst d0
   bne dwait0
   parm d3               * Head
   parm #0               * Flag
   parm d1               * CylH
   parm d2               * CylL
   parm d3               * Track
   parm d4               * Sector
   parm #1               * Nsectors
   move.b #$b0,diskcsr   * Read
   move.w #$1000,diskbcr * DMA in
   bsr cwait
*  clr.l d0
*  move.w d0,diskbcr
*  move.b diskcsr,d0
   move.w #0,diskbcr
   rol.w #8,d0
   move.b diskdbr,d0
   and.w #$efff,d0
   cmp.w #$4000,d0
   bne.s derr
   lea diskbuf,a1
   move.w #255,d0
mloop move.w (a1)+,(a0)+
   dbra d0,mloop
   movem.l (sp)+,d0-d4/a1
   rts
derr move.l a0,-(sp)
   move.w d0,-(sp)
   lea derrmess,a0
   bsr pstring
   move.w (sp)+,d0
   bsr whex
   moveq #' ',d0
   bsr psym
   move d1,d0
   bsr bhex
   move d2,d0
   bsr bhex
   moveq #' ',d0
   bsr psym
   move d3,d0
   bsr bhex
   moveq #' ',d0
   bsr psym
   move d4,d0
   bsr bhex
   moveq #nl,d0
   bsr psym
   bsr diskreset
   move.l (sp)+,a0
   movem.l (sp)+,d0-d4/a1
   bra diskread
derrmess dc.b 255,'Disk error ',0
   ds.w 0

  endc dcon='7261'

* Blocks 0,1 of the disk contains a directory, the
* layout of which is as follows:
* 1024 bytes in all:
* 1 longword checksum (such that the sum of the 128
*                 longwords is 0, using IBM byte sex)
* 42 24-byte file records
* 1 longword trailer which must be zero, as it is
*        deemed part of a truncated 43rd file record.

* Each file record looks like this:
* 1-longword length of file (number of bytes)
* 1-byte length of filename
* up to 19 bytes filename

* The byte-position on disk of file N is the position of
* file N-1 plus the size (rounded up to the next 512
* bytes) of file N-1.  The position of the first file,
* which is the directory block, is 0, and hence the
* directory will contain an entry for itself.
* A file record beginning with a 0 longword (i.e.
* describing a null file) terminates the list of file
* records in the directory.

* Routine to load (i.e. read) a file with name A0
* into memory at location D0.
* Result: D0=length, A0=address of next free byte

diskload movem.l d0/a0,-(sp)
*  bsr diskreset          *moved to more global code*
   lea -1024(sp),sp       allocate space into which to read directory
   move.l sp,a0
   clr.l d0
   bsr vdiskread          read first directory block
   move.l #512,d0
   bsr vdiskread          read second directory block
   move.w #255,d0         compute checksum
   clr.l d1
   move.l sp,a0
dl1 add.l (a0)+,d1
   dbra d0,dl1
   bne cserr              checksum fails ->
*  tst.l -4(a0)
*  bne diskerr            last longword non-zero ->
igncse clr.l d0           byte offset in disk of start of next file
   move.l 1024+4(sp),a1   address of filename to be searched for
   lea 8(sp),a0           address of first filename in directory
dl2 move.l -4(a0),d1      length of first (next) file
   beq diskerr            end reached (file not found) ->
   bsr   strc             compare filenames
   beq diskfound          file found ->
   add.l #511,d1          round length to multiple of block size
   and.l #-512,d1
   add.l d1,d0            note disk byte address of next file
   lea 24(a0),a0          onto next slot in directory
   bra dl2
diskfound move.l -4(a0),d1 note size (in bytes) of file
   lea 1024(sp),sp        deallocate directory block space
   move.l (sp),a0         memory address for file
   move.l a0,4(sp)
   move.l d1,(sp)         save size for result
dl3 bsr vdiskread         read first (next) block of file
   add.l #512,d0          increment disk address
   sub.l #512,d1          decrement bytes-to-go
   bgt dl3
   movem.l (sp)+,d0/a0    restore size and start address
   add.l d0,a0            compute end address
   rts
diskerr lea 1024(sp),sp
   move.l 4(sp),a0
   bsr pstring
   lea diskmnotfound,a0
   bsr pstring
   bra abort
diskmnotfound dc.b 255,' not in boot area',0
diskmcserr    dc.b 255,'Directory checksum error',cr,lf,0
   ds.w 0
cserr lea diskmcserr,a0
   bsr pstring
   bra igncse

keyswitch equ $400031

vdiskread move.l d0,-(sp)
   moveq #1,d0
   and.b keyswitch,d0
   lsl.w #3,d0
   swap d0                 <<19
   add.l (sp),d0
   bsr diskread
   move.l (sp)+,d0
   rts

* Compare (eq/neq) strings A0 and A1
* with simplified case relaxation
strc movem.l d0-d2/a0-a1,-(sp)
     clr.w d0
     move.b (a0)+,d0
     cmp.b (a1)+,d0
     bne.s strc9        * different length =>
     subq.b #1,d0
     beq.s strc9        * both null =>
strc1 move.b (a0)+,d1
     or.b #32,d1
     move.b (a1)+,d2
     or.b #32,d2
     cmp.b d1,d2
     dbne d0,strc1
strc9 movem.l (sp)+,d0-d2/a0-a1
     rts

 endc disk#0

* Read a character from ACIA to D0

rsym btst.b #vrrfbit,vdus
   beq rsym
   moveq #127,d0
   and.b vdud,d0
   cmp.b #del,d0
   beq abort
   bra psym         * to echo
   rts

* Read a hex number from ACIA to D0
* Terminating char to D1

rhex moveq #0,d1
rh1 bsr rsym
   or.b #32,d0
   sub.b #'0',d0
   bmi.s rh3
   cmp.b #9,d0
   ble.s rh2
   sub.b #7+32,d0
   cmp.b #9,d0
   ble.s rh3
   cmp.b #15,d0
   bgt.s rh3
rh2 lsl.l #4,d1
   add.b d0,d1
   bra rh1
rh3 add.b #'0',d0
   exg d0,d1
   rts

* Read filename to string(31) somewhere
* leaving A0 pointing at it

rname move.l 0,a0
   lea 1(a0),a1
   clr.b (a0)
   moveq #31,d1
   bra.s rn1
rn2 move.b d0,(a1)+
   addq.b #1,(a0)
rn1 bsr rsym
   cmp.b #' ',d0
   dble d1,rn2
   rts

*
*  MAIN ENTRY POINT
*

begin reset
   move.l 0,sp
   move.b #vinit,vdus
   move.b #viof,vdus

* Intercept any nasties

   move.l #nasty,d0
   move.w #48-1,d1
   lea ram,a0
nastyloop move.l d0,(a0)+
   dbra d1,nastyloop

* Initialise ether station and ACIA

   move.b #einit,eths
   move.b #eiof,eths
   ptext <cr,lf,'Boot firmware'>
 ifne dcon
ch1 equ dcon>>24
ch2 equ dcon>>16&255
ch3 equ dcon>>8&255
ch4 equ dcon&255
ch5 equ disk>>24
ch6 equ disk>>16&255
ch7 equ disk>>8&255
ch8 equ disk&255
   ptext <' ',ch1,ch2,ch3,ch4>
  ifne dcon-disk
   ptext <' ',ch5,ch6,ch7,ch8>
  endc
   ptext <' disk'>
 endc
   ptext <' version '>
   move.b version,d0
   bsr bhex
   moveq #'/',d0
   bsr psym
   move.b version+1,d0
   bsr bhex
   moveq #'/',d0
   bsr psym
   move.b version+2,d0
   bsr bhex
   moveq #nl,d0
   bsr psym

* Set up mapping registers (transparently)

   move.l #$ff800000+map0,a0
   move.l #$00800080,d0
   moveq #7,d1
maploop move.l d0,0(a0,d0.l)
   add.l #$00100010,d0
   dbra d1,maploop

* Initialise local store

   move.l #$aaaa,d0
   move.l #48*4+ram,a0
localloop move.w d0,(a0)+
   cmp.l sp,a0
   bne localloop

* Initialise main store, break out by bus error

   move.l #breakout,ram+8
   move.l gropestart,a0
   move.l a0,membot
   move.l gropelimit,d1
   sub.l a0,d1
   lsr.l #2,d1
   subq.l #1,d1
   move.l #$aaaaaaaa,d0
mainloop move.l d0,(a0)+
   dbra d1,mainloop
   addq.w #1,d1
   subq.l #1,d1
   bpl mainloop
   bra.s maindone
breakout move.l #maindone,ram+8
   move.b #0,arbiter   * (Attempt to) clear error in arbiter
maindone move.l a0,memtop
   sub.l gropestart,a0
   move.l a0,d0
   bsr lhex
   ptext <' bytes of main store',nl>

* Establish local ether station address etc

   move.l deffile,ffile
   clr.w lstat
   clr.w rstat
   move.b defstat,rstat
   move.b #esa,ethc   * Enquire station address
ssaloop bsr readcc
   cmp.b #ssa,d0
   bne ssaloop
   bsr readdc
   move.b d0,lstat
   ptext <'Ether station '>
   move.b lstat,d0
   bsr bhex
   ptext <' firmware version '>
   move.b #8,ethc     * Set peek/poke address
   bsr flush
   move.b #4,ethd
   bsr flush
   move.b #0,ethd
   bsr flush
   move.b #13,ethc    * Peek
   bsr readcc
   bsr readdc
   bsr bhex
   moveq #'/',d0
   bsr psym
   move.b #13,ethc
   bsr readcc
   bsr readdc
   bsr bhex
   moveq #'/',d0
   bsr psym
   move.b #13,ethc
   bsr readcc
   bsr readdc
   bsr bhex
   moveq #nl,d0
   bsr psym

* If a key has been pressed, ask which filestore
* to talk to, and which files to load.  Otherwise
* use defaults

   btst.b #vrrfbit,vdus
   beq which
ask move.b vdud,d0
   ptext 'Filestore:'
   bsr rhex
   tst.w d0
   beq.s ask1          * Keep default if 0
   move.b d0,rstat
ask1 ptext 'File:'
   bsr rname
   tst.b (a0)
   beq.s which         * Keep default if null
   move.l a0,ffile

* Which filestore?

which clr.b lport      * (Default: local disk)
   tst.b rstat
   bmi.s bootarea
*  cmp.b #$70,rstat
*  bne.s newfilestore
*
* Old filestore (fixed port/client assignments)
*
*  move.b #15,lport   * Local port 15
*  moveq #-16,d0      * Remote port = local station - 16
*  add.b lstat,d0
*  move.b d0,rport
*  bsr open
*  bsr out            * Send "boot" (amnesia) command
*  move.b #12,ethd
*  bsr flush
*  move.b #etx,ethc
*  bra loadsys

* New filestore (chat to establish port number)

newfilestore move.b #1,lport
   bsr open
   bsr out
   move.b #2,ethd
   bsr flush
   move.b #etx,ethc
   bsr in
   bsr readdc
   cmp.b #'0',d0
   bmi fserr
   sub.w #'0',d0
   move.b d0,rport
   bsr readcc
   bsr open
   bra loadsys

* Local disk

bootarea equ *
  ifne disk
   bsr diskreset
  endc

* fall into LOADSYS

* Now load the file

loadsys move.l ffile,a0
reload move.l #reload,ram+$20
   move.l 0,sp
   move.w #$2700,sr        * Acquire privilege
   move.l membot,freebot
   move.l memtop,freetop
   move.l #ram,d0
   bsr load

* Enter Loaded System

   move.l membot,a0
   movem.l (a0),d0-d7/a0-a6
   move.l a6,usp
   move.l ram,sp
   move.l ram+4,-(sp)
   rts

* Error reports

nasty ptext <'Unexpected exception',nl>
   move.b vdud,d0
nloop2 moveq #7,d2
nloop1 moveq #' ',d0
   bsr psym
   move.w (sp)+,d0
   bsr whex
   breaktest
   cmp.l #syssp,sp
   beq abort
   dbra d2,nloop1
   moveq #nl,d0
   bsr psym
   bra nloop2

gotnak ptext <'No ACK from station '>
   move.b rstat,d0
   bsr bhex
   ptext <' port '>
   move.b rport,d0
   bsr bhex
   moveq #nl,d0
   bsr psym
   bra abort

fserr bsr psym
fse1 bsr readdc
   bsr psym
   cmp.b #nl,d0
   beq.s fse2
   bra fse1
fse2 bsr readcc
   bra abort

abort ptext <nl,'Press any key to re-boot',nl>
waitnobreak move.b vdud,d0
   btst.b #vbrkbit,vdus
   bne waitnobreak
   move.b vdud,d0
wait btst.b #vrrfbit,vdus
   beq wait
   bra begin

* Configuration parameters

defaultfile dc.b 9,'fmac:nsys'

   org deffile
   dc.l defaultfile
   dc.l date<<8+favourite
   dc.l $800000
   dc.l $800000+memory

   end
