! Disq IO procedures for Mini-Filestore
 %option "-nostack"

%include "inc:util.imp"
%routinespec intwait

! Block-level access routines for mini-file-store
! FDC, 12.12.83
! changes on 19.12.83:
!   step rate from 1.5ms to 10 us (buffered by disc controller)
!   data transfers from/to WD1000 programmed in assembler
!
! changes on 8.1.84:
!   step rate set to 1.5ms on first restore because there were
!   sporadic TR000 errors at 10us.

{ disk characteristics }
%constant %integer restore step rate   =     3,       { 1.5ms }
                   seek step rate      =     0,       { 10us }
                   size                = 16_20,
                   sectors per block   = 2,
                   blocks per track    = 16,
                   tracks per cylinder = 4,
                   cylinders per drive = 256,
                   number of drives    = 2

{ disk controller commands }
%constant %integer restore      = 16_10 + restore step rate,
                   seek         = 16_70 + seek step rate,
                   read sector  = 16_20,               { + 8 for DMA }
                   write sector = 16_30,
                   format track = 16_50

{ status values }
%constant %integer busy          = 16_80,
                   ready         = 16_40,
                   write fault   = 16_20,
                   seek complete = 16_10,
                   data request  = 16_08,
                   error         = 16_01
 
{ disk controller task file }
%record %format mfsr (%short status,
                      %short size drive head,
                      %short cylinder high,
                      %short cylinder low,
                      %short sector number,
                      %short sector count,
                      %short error register,
                      %short data register)

%record %format mfsw (%short command,
                      %short size drive head,
                      %short cylinder high,
                      %short cylinder low,
                      %short sector number,
                      %short sector count,
                      %short precomp,
                      %short data register)

@ 16_7ffe0 %record (mfsr) read
@ 16_7ffe0 %record (mfsw) write

%own %integer BL Display Error = 1

%routine wait(%string(20) cmd)

  %routine report byte(%string(20) text, %integer byte)
    printstring(text)   
    phex2(byte)
    newline
  %end
 
  %cycle
    intwait
  %repeat %until read_status & busy = 0
  %if read_status & error # 0 %start
    %if BL Display Error # 0 %start
      newline
      printstring("Mini-file-store error on ")
      printstring(cmd)
      printstring(" command")
      newline
      report byte("Status:          ", read_status)
      report byte("Size/Drive/Head: ", read_size drive head)
      report byte("Cylinder high:   ", read_cylinder high)
      report byte("Cylinder low:    ", read_cylinder low)
      report byte("Sector number:   ", read_sector number)
      report byte("Sector count:    ", read_sector count)
      report byte("Error register:  ", read_error register)
      report byte("Data register:   ", read_data register)
    %finish
    %signal %event 9,3
  %finish
%end
 
%external %routine BL Reset
  %integer drive
  write_precomp = 16_20             { precomp from track 128 onward }
  %for drive = 0,1,1 %cycle
    write_size drive head = drive << 3
    write_command = restore
    wait("restore")
    write_cylinder high = 0
    write_cylinder low = 0
    write_command = seek            { subsequent seeks at 10us step rate }
    wait("seek")
  %repeat
%end

%routine setup task file(%integer block number)
  %integer drive, cylinder, head, block, remainder

  block     = rem(block number, blocks per track)
  remainder = block number // blocks per track
  head      = rem(remainder, tracks per cylinder)
  remainder = remainder // tracks per cylinder
  cylinder  = rem(remainder, cylinders per drive)
  drive     = remainder // cylinders per drive
  %signal %event 9,3 %if drive >= number of drives
  write_sector number   = block * sectors per block
  write_size drive head = drive << 3 + head
  write_cylinder high   = cylinder >> 8
  write_cylinder low    = cylinder
%end

%external %routine BL Read Block(%integer block number, block)
!                                 %byte %array %name block(0:511))
  %integer byte, sector

  setup task file(block number)
  %for sector = 0,1,1 %cycle
    write_command = read sector
    wait("read sector")
!   %for byte = sector * 256, 1, 255 + sector * 256 %cycle
!     block(byte) = read_data register
!   %repeat
    *movea.l block,a0
    *move.l  sector,d0
    *lsl     #8,d0
    *adda.l  d0,a0
    *move.l  #63,d0
    *lea     16_7ffef,a1
loop:
    *move.b  (a1),(a0)+
    *move.b  (a1),(a0)+
    *move.b  (a1),(a0)+
    *move.b  (a1),(a0)+
!    *move.b  16_7ffef,d1
!    *lsl     #8,d1
!    *move.b  16_7ffef,d1
!    *lsl     #8,d1
!    *move.b  16_7ffef,d1
!    *lsl     #8,d1
!    *move.b  16_7ffef,d1
!    *move.l  d1,(a0)+
!    *dbra    d0,#-34
    *dbra    d0,loop
    write_sector number = read_sector number + 1 { assumes even      }
                                                         { sectors per track }
  %repeat
%end

%external %routine BL Write Block(%integer block number, block)
{                                  %byte %array %name block(0:511))
  %integer byte, sector

  setup task file(block number)
  %for sector = 0,1,1 %cycle
    write_command = write sector
!   %for byte = sector * 256, 1, 255 + sector * 256 %cycle
!     write_data register = block(byte)
!   %repeat
    *movea.l block,a0
    *move.l  sector,d0
    *lsl     #8,d0
    *adda.l  d0,a0
    *move.l  #63,d0
    *lea     16_7ffef,a1
loop:
    *move.b  (a0)+,(a1)
    *move.b  (a0)+,(a1)
    *move.b  (a0)+,(a1)
    *move.b  (a0)+,(a1)
!    *move.l  (a0)+,d1
!    *rol     #8,d1
!    *move.b  d1,16_7ffef
!    *rol     #8,d1
!    *move.b  d1,16_7ffef
!    *rol     #8,d1
!    *move.b  d1,16_7ffef
!    *rol     #8,d1
!    *move.b  d1,16_7ffef
!    *dbra    d0,#-36
    *dbra    d0,loop
    wait("write sector")
    write_sector number = read_sector number + 1 { assumes even      }
                                                         { sectors per track }
  %repeat
%end

%routine do(%integer op,bytes,da,ub)
  %cycle
    %if op=0 %start
      bl read block(da>>9,ub)
    %else
      bl writeblock(da>>9,ub)
    %finish
    ub = ub+512; da = da+512; bytes = bytes-512
  %repeatuntil bytes<=0
%end

%constinteger dwrite=1,dread=2,dverify=4

%integerfn xtransfer(%integer func,bytes,disqaddr,%integername buf)
%integer lives=0
  %onevent 9 %start
    %result = -1
  %finish
  do(1, bytes,disqaddr,addr(buf)) %if func&dwrite#0
  do(0,  bytes,disqaddr,addr(buf)) %if func&dread#0
  %result = bytes
%end

%owninteger accepted=0,count=-1,xf=0,xn,xa,xm

@16_3f90 %integer intsp
@16_3f94 %integer mysp

%routine intwait
  *movem.l d5-d7/a4-a6,-(sp)
  *move.l sp,mysp
  *move.l intsp,sp
  *movem.l (sp)+,d2-d7/a1-a6
  *move.l 16_374c,a0
  *jsr (a0)
  *movem.l d2-d7/a1-a6,-(sp)
  *move.l sp,intsp
  *move.l mysp,sp
  *movem.l (sp)+,d5-d7/a4-a6
%end

%externalroutine startup
%ownintegerarray stack(-2048:1) = 16_55555555(*)
{}printstring("Mini Filestore Version 15/05/84"); newline
  mysp = addr(stack(0))
  *move.l (sp)+,a0
  *mfsr d1
  *move #16_2400,d0
  *trap #0
  *move.l a0,-(sp)
  *move.w d1,-(sp)
  *movem.l d0-d1/a0,-(sp)
  *movem.l d2-d7/a1-a6,-(sp)
  *move.l sp,intsp
  *move.l mysp,sp
  bl reset
  %cycle
    intwait %until count=0 {xf#0
    accepted = 1
    count = xtransfer(xf,xn,xa,integer(xm))
  %repeat
%end

@16_ff8003 %byte interrupt register

%externalroutine show disq status
  printstring("Disq: Co="); phex(count)
  printstring(" By="); phex(xn)
  printstring(" Bl="); phex(xa>>9)
  %unless xa&511=0 %start
    printsymbol('.'); phex(xa&511)
  %finish
  printstring(" Bu="); phex(xm)
  printstring(" Op="); phex(xf)
  newline
%end

%externalroutine kick disq
  interrupt register = 1
%end

%externalintegermap transfer(%integer f,n,a,%integername m)
%owninteger started=0
  started = 1 %and startup %if started=0
  %if count=0 %start
    printstring("Disq request while driver busy"); newline
    %while count=0 %cycle; %repeat
  %finish
  count = 0; xm = addr(m); xa = a; xn = n; xf = f
  accepted = 0
  %cycle
    kick disq
    %result == count %unless accepted=0
  %repeat
%end

%endoffile
