**    Heres a little utility that I have just made.
**    I thought what I wanted was on a fish disk but that program
**    only saved dumps of boot blocks into files that disassemblers can
**    read. So I decided to write one myself. Here it is
**    The command to use on this is
**    FileBootBlock df?: filename
**    there must be only one space between the drive specifier of your
**    filename will end up starting with spaces
**    It will read the blocks 0 and 1 of the drive given and save it as
**    a program file that can be run (heaven forbid) or disassembled
**    by programs like DIS and DSM
**    The only modifying it does is the the first 2 bytes of the block.
**    As all program file must start with a valid instruction I have
**    changed the first 2 bytes from 'DO' to $600A. This makes it into the
**    instruction BRA.S *+$C which will get to the start of the proper code

**    Have fun

**    John Veldthuis
**    21 Ngatai Street
**    Manaia, Taranaki
**    New Zealand
**    22 November 1988
**    Placed into the Public domain on this date


_LVOOpenLibrary equ -$228
_LVOCloseLibrary equ -$19e
_LVODoIO equ -$1c8
_LVOOpenDevice equ -$1bc
_LVOCloseDevice equ -$1c2

_LVOAllocEntry equ -$de
_LVOFreeEntry equ -$e4
_LVOOpen equ -$1e
_LVOClose equ -$24
_LVOWrite equ -$30
_LVOAllocSignal equ -$14a
_LVOFreeSignal equ -$150

Offsets     macro
\1          equ   soffset
soffset     set   soffset+\2
            endm
soffset     set   0

NEWLIST     macro
            move.l  \1,(\1)
            addq.l  #4,(\1)
            clr.l   4(\1)
            move.l  \1,8(\1)
            endm

            Offsets  dosbase,4
            Offsets  execbase,4
            Offsets  filehandle,4
            Offsets  buffer,4
            Offsets  port,4
            Offsets  filename,4
            Offsets  diskreq,4
            Offsets  task,4
            Offsets  mementry,4
            Offsets  unit,4
            Offsets  stdout,4

PA_SIGNAL        equ 0
LH_HEAD          equ 0
MEMF_PUBLIC      equ 1
MEMF_CHIP        equ 2
CMD_READ         equ 2
NT_MSGPORT       equ 4
NT_MESSAGE       equ 5
LN_TYPE          equ 8
LN_PRI           equ 9
TD_MOTOR         equ 9
MN_REPLYPORT     equ $e
MP_FLAGS         equ $e
LN_SIZE          equ $e
MP_SIGBIT        equ $f
MP_SIGTASK       equ $10
MN_LENGTH        equ $12
MP_MSGLIST       equ $14
IO_COMMAND       equ $1c
IO_ERROR         equ $1f
MP_SIZE          equ $22
IO_LENGTH        equ $24
IO_DATA          equ $28
IO_OFFSET        equ $2c
IOSTD_SIZE       equ $30
pr_COS           equ $a0
ThisTask         equ $114
MODE_NEWFILE     equ $3ee
MEMF_CLEAR       equ $10000

Start:
      lea      BASE(pc),a5
      move.l   4,a6
      move.l   a6,execbase(a5)
      movem.l  d0/a0,-(sp)
      move.l   ThisTask(a6),a0       ;find our task
      move.l   a0,task(a5)
      move.l   pr_COS(a0),stdout(a5) ;save output stream for messages
      moveq.l  #33,d0                ;version 33 or greater
      lea      DosLib(pc),a1
      jsr      _LVOOpenLibrary(a6)   ;open dos.library
      movem.l  (sp)+,d1/a0
      move.l   d0,dosbase(a5)
      bne.s    Lib1
NoLib move.l   #20,d0                ;no library, indicate error and stop
      rts
Lib1  moveq    #0,d0
      move.b   d0,-1(a0,d1.w)        ;zero end of Command line
1$    move.b   (a0)+,d0
      beq      CLIErr
      and.b    #%11011111,d0         ;change to uppercase
      cmp.b    #'D',d0               ;look for the D in DF?:
      bne.s    1$
      move.b   (a0)+,d0              ;dummy read to skip the F
      move.b   (a0)+,d0              ;get unit number
      sub.b    #'0',d0               ;make into a real number
      ext.w    d0                    ;sign extend to a word
      ext.l    d0                    ;sign extend to a long
      move.l   d0,unit(a5)           ;save unit number
2$    move.b   (a0)+,d0              ;search for space
      cmp.b    #' ',d0
      bne.s    2$
      move.l   a0,filename(a5)       ;save address of filename
      lea      Mem(pc),a0
      jsr      _LVOAllocEntry(a6)    ;allocate all memory in one go
      btst     #31,d0
      bne      MemErr                ;if bit 31 set then error getting mem
      move.l   d0,mementry(a5)       ;save for release
      move.l   d0,a0
      add.w    #Mem1-Mem,a0
      move.l   (a0),buffer(a5)       ;save address of read/write buffer
      bsr      CreatePort            ;create a reply port
      tst.l    d0
      beq      PError                ;no message port
      move.l   d0,d3
      move.l   d0,port(a5)           ;save for closing later
      move.l   mementry(a5),a0
      add.w    #Mem2-Mem,a0
      move.l   (a0),a0               ;make an IORequest block
      move.b   #NT_MESSAGE,LN_TYPE(a0)
      move.w   #IOSTD_SIZE,MN_LENGTH(a0)
      move.l   d3,MN_REPLYPORT(a0)
      move.l   a0,diskreq(a5)        ;save IO block address
      move.l   unit(a5),d0
      lea      TrackName(pc),a0
      move.l   diskreq(a5),a1
      moveq.l  #0,d1
      jsr      _LVOOpenDevice(a6)    ;open trackdisk on unit
      tst.l    d0
      bgt      TErr                  ;won't open, display error
      move.l   diskreq(a5),a1
      move.w   #CMD_READ,IO_COMMAND(a1)
      move.l   buffer(a5),IO_DATA(a1)
      move.l   #1024,IO_LENGTH(a1)
      move.l   #0,IO_OFFSET(a1)
      jsr      _LVODoIO(a6)          ;read boot block into buffer
      move.l   diskreq(a5),a1
      move.w   #TD_MOTOR,IO_COMMAND(a1)
      clr.l    IO_LENGTH(a1)
      jsr      _LVODoIO(a6)          ;turn motor off
      move.l   diskreq(a5),a1
      move.b   IO_ERROR(a1),d3       ;see what error there was
      jsr      _LVOCloseDevice(a6)   ;close trackdisk down
      cmp.b    #19,d3
      bgt      ReadErr               ;if an error display error
      move.l   buffer(a5),a0
      move.w   #$600A,(a0)           ;change first to bytes to BRA.S  *+$C
                                     ;so as not to upset relative addresses
      move.l   dosbase(a5),a6        ;get dosbase
      move.l   filename(a5),d1
      move.l   #MODE_NEWFILE,d2
      jsr      _LVOOpen(a6)          ;open file that bootblock goes in
      move.l   d0,filehandle(a5)     ;save for closing
      beq      OpenErr               ;didn't open for some reason
      lea      table(pc),a0          ;get first part of file
      move.l   a0,d2                 ;used to create a program file
      move.l   d0,d1                 ;filehandle into d1
      moveq    #32,d3                ;length of numbers
      jsr      _LVOWrite(a6)
      cmp.l    #32,d0
      bne      WriteErr
      move.l   buffer(a5),d2
      move.l   filehandle(a5),d1
      move.l   #1024,d3
      jsr      _LVOWrite(a6)         ;write out rest of block to file
      cmp.l    #1024,d0              ;see if it all got written out
      bne.s    WriteErr
      move.l   filehandle(a5),d1
      lea      hunkend(pc),a0
      move.l   a0,d2
      moveq    #4,d3
      jsr      _LVOWrite(a6)         ;write last bit of file
      cmp.l    #4,d0
      bne.s    WriteErr
Fin   move.l   filehandle(a5),d1
      beq.s    1$
      jsr      _LVOClose(a6)         ;close file if it opened
1$    move.l   execbase(a5),a6
      move.l   port(a5),d0
      beq.s    2$
      move.l   d0,a1
      bsr      DeletePort            ;delete port if one got made
2$    move.l   mementry(a5),d0
      beq.s    3$
      move.l   d0,a0
      jsr      _LVOFreeEntry(a6)     ;freememory if any got allocated
3$    move.l   dosbase(a5),a1
      jsr      _LVOCloseLibrary(a6)  ;close dos.library
      rts


MemErr:
      lea      MemMess(pc),a0
      move.l   a0,d2
      moveq    #47,d3
      bra.s    Err
Error:
CLIErr:
      lea      CLIMess(pc),a0
      move.l   a0,d2
      moveq    #36,d3
      bra.s    Err
ReadErr:
      lea      ReadMess(pc),a0
      move.l   a0,d2
      moveq    #36,d3
      bra.s    Err
WriteErr:
      lea      WriteMess(pc),a0
      move.l   a0,d2
      moveq    #28,d3
      bra.s    Err
OpenErr:
      lea      OpenMess(pc),a0
      move.l   a0,d2
      moveq    #25,d3
      bra.s    Err
PError:
      lea      PMess(pc),a0
      move.l   a0,d2
      moveq    #41,d3
      bra.s    Err
TErr
      lea      TMess(pc),a0
      move.l   a0,d2
      moveq    #39,d3
Err   move.l   stdout(a5),d1
      tst.l    d1
      beq      Fin               ;if no output stream
      move.l   dosbase(a5),a6
      jsr      _LVOWrite(a6)
      bra      Fin

CreatePort:
      move.l   a2,-(a7)
      move.l   mementry(a5),a2
      add.w    #Mem3-Mem,a2
      move.l   (a2),a2
      moveq    #-1,d0
      jsr      _LVOAllocSignal(a6)
      moveq    #-1,d1
      cmp.l    d0,d1   ;-1 indicates bad signal
      bne.s    cp_sigok
      move.l   (a7)+,a2
      moveq    #0,d0        ;otherwise indicate no port
      rts
cp_sigok:
      move.b   d0,MP_SIGBIT(a2)
      move.b   #PA_SIGNAL,MP_FLAGS(a2)
      move.b   #NT_MSGPORT,LN_TYPE(a2)
      clr.b    LN_PRI(a2)
      move.l   task(a5),d0
      move.l   d0,MP_SIGTASK(a2)
      lea.l    MP_MSGLIST(a2),a0  ;Point to list header
      NEWLIST  a0      ;Init new list macro
      move.l   a2,d0
      move.l   (a7)+,a2   ;cc's NOT affected
      rts

DeletePort:
      moveq    #-1,d0
      move.b   d0,LN_TYPE(a1)
      move.l   d0,MP_MSGLIST+LH_HEAD(a1)
      moveq    #0,d0
      move.b   MP_SIGBIT(a1),d0
      jsr      _LVOFreeSignal(a6)
      rts

table:
      dc.l     $3f3        ;Hunk_Header
      dc.l     0           ;no Hunk_Name
      dc.l     1           ;size of hunk table
      dc.l     0           ;first hunk
      dc.l     0           ;last hunk
      dc.l     256         ;number of longwords in hunk
      dc.l     $3e9        ;Hunk_Code
      dc.l     256         ;number of longwords in hunk

hunkend
      dc.l     $3f2        ;hunk end

BASE:
Dosbase     dc.l  0
Execbase    dc.l  0
Filehandle  dc.l  0
Buffer      dc.l  0
Port        dc.l  0
FileName    dc.l  0
DiskReq     dc.l  0
Task        dc.l  0
MemEntry    dc.l  0
Unit        dc.l  0
Stdout      dc.l  0

Mem         ds.b  LN_SIZE
            dc.w  3
Mem1        dc.l  MEMF_CHIP!MEMF_CLEAR
            dc.l  1024
Mem2        dc.l  MEMF_PUBLIC!MEMF_CLEAR
            dc.l  IOSTD_SIZE
Mem3        dc.l  MEMF_PUBLIC!MEMF_CLEAR
            dc.l  MP_SIZE

DosLib      dc.b  'dos.library',0
TrackName   dc.b  'trackdisk.device',0
MemMess     dc.b  'Not enough Memory to allocate required buffers',10
CLIMess     dc.b  'Usage:  FileBootBlock df?: filename',10
ReadMess    dc.b  'Disk Error while reading Boot Block',10
WriteMess   dc.b  'Error while writing to file',10
OpenMess    dc.b  'Error while opening file',10
PMess       dc.b  'Couldn''t create message port for disk IO',10
TMess       dc.b  'Couldn''t get access to specified drive',10

      end
