! Mouse/filestore disc process for Fuji 2243 80 Mb Winchester with Ambit ! controller and RWT interface. New Mouse version. ! Requests are sent via the standard send/receive message operations. ! P1: request code -- 0 = get disc status, 1 = read, 2 = write ! P2: block number ! P3: buffer address ! P4: number of blocks ! (0 <= P2 < (P2 + P4) <= disc size) %externalstring(47) copyright %alias "GDMR_(C)_2243" = %c "Copyright (C) 1987 George D.M. Ross" %option "-low-nonstandard-nocheck-nodiag-noline" %include "Moose:Mouse.Inc" %conststring(31) request mailbox name = "FUJI2243_REQUESTS" %systemroutinespec phex2(%integer what) %systemroutinespec phex(%integer what) %constinteger read bit = 16_01 %constinteger write bit = 16_02 %constinteger intwait bit = 16_04 %constinteger int bit = 16_08 %constinteger doing bit = 16_10 %constinteger adding bit = 16_20 %owninteger disc reads = 0 %owninteger disc writes = 0 %owninteger disc HW = 0 %ownrecord(semaphore fm) disc interrupt = 0 %constinteger heads = 11 %constinteger sectors = 16, sector mask = sectors - 1 %constinteger cylinders = 754 %constinteger size = heads * sectors * cylinders %constinteger unit shift = 28 %constinteger block mask = \(16_FFFFFFFF << unit shift) @16_ED0000 %readonly %volatile %byte disc r; ! Read data @16_ED0000 %writeonly %byte disc w; ! Write data @16_ED0001 %writeonly %byte disc a; ! Arm interrupts @16_ED0001 %readonly %volatile %byte disc d; ! Disarm interrupts %constinteger dc initialise = 16_02 %constinteger dc read disc = 16_21 %constinteger dc write disc = 16_22 %constinteger dc drive status = 16_25 !constinteger dc seek = 16_28 %constinteger dc read buffer = 16_41 %constinteger dc write buffer = 16_42 %recordformat disc address fm(%byte unit, head, %byte track l, track h, %byte sector, %byte z1, z2, z3) %ownbyte null byte = 0 %ownbyte disc status = 0 %constinteger fatal = 16_40 %owninteger soft errors = 0 %owninteger hard errors = 0 %routine analyse error(%integer command, %record(disc address fm)%name a) printstring("Disc error "); phex2(disc status) space; phex2(command) %if a ## nil %start space write(a_unit, 0); printstring("U ") phex2(a_track h); phex2(a_track l) printstring("T ") phex2(a_head); printstring("H ") phex2(a_sector); print symbol('S') %finish %if disc status & fatal = 0 %start soft errors = soft errors + 1 printstring(" (soft)") %else hard errors = hard errors + 1 printstring(" (*HARD*)") %finish newline %end %routine command(%integer op, bytes, %bytename buffer, %integer fill, intwait) ! bytes + -> write to controller ! bytes 0 -> no parameter part ! bytes - -> read from controller ! intwait # 0 iff interrupts are to be used %integer i, junk i = disc r %until i = 16_A0 disc w = op i = disc r %until i = 16_A1 disc w = 16_FF %for i = 1, 1, 50 %cycle; %repeat; ! Placate disc controller %if bytes > 0 %start ! Write to controller D0 = bytes - 1 A0 = addr(buffer) wl:*move.b (A0)+, disc w *dbra D0, wl %if fill > 0 %start D0 = fill - 1 wf:*move.b #0, disc w *dbra D0, wf %finish %else %if bytes < 0 D0 = -bytes - 1 A0 = addr(buffer) rl:*move.b disc r, (A0)+ *dbra D0, rl %if fill > 0 %start D0 = fill - 1 rf:*move.b disc w, D1 *dbra D0, rf %finish %finish disc w = 16_FF %for i = 1, 1, 50 %cycle; %repeat; ! Placate disc controller %if intwait = 0 %start i = disc r %until i = 16_FF %else %cycle disc a = 255; ! Arm interrupts !! put sym('W'); !put sym(13) semaphore wait(disc interrupt) !! put sym('C'); !put sym(13) i = disc r %repeat %until i = 16_FF %finish disc w = 16_FE i = disc r %until i & 16_80 = 0 disc status = disc r disc w = 0 %end %routine initialise disc %ownbytearray b(0 : 15) = 255, 0, 0, { Pre-compensation } 0, 0, 0, { RWC } 4, { Buffered step } (cylinders - 1) & 255, (cylinders - 1) >> 8, { Max track } 0, 0, { Last user track (disabled) } 0, { Bad track mapping } 0, { Removable drive } 0, 0, 0 { Reserved, mbz } %ownrecord(interrupt handler fm) handler = 0 %integer i %label h !! printstring("Initialise disc: ") !! write(sectors, 0); printstring("s ") !! write(heads, 0); printstring("h ") !! write(cylinders, 0); print symbol('c') !! newline setup semaphore(disc interrupt) setup interrupt handler(handler, addr(h)) add interrupt handler(handler, 3) disc w = 0 command(dc write buffer, 16, b(0), 512 - 16, 0) %if disc status # 0 %start printstring("Disc init: write buffer status ") phex2(disc status); newline %stop %finish command(dc initialise, 0, null byte, 0, 1) %if disc status # 0 %start printstring("Disc init: init status "); phex2(disc status) newline %stop %finish %return ! Interrupt handler -- merely reawaken the disc process h: *move.b disc d, D0; ! Disarm the interface !! put sym('I'); !put sym(13) int signal semaphore(disc interrupt) !! put sym('R'); !put sym(13) return from interrupt *move.l D0, D0; ! In case of "optimisations" %end %routine split address(%integer block, %record(disc address fm)%name address) %integer c, h, s address_unit = block >> unit shift; block = block & block mask h = block // sectors; s = block - h * sectors c = h // heads; h = h - c * heads !! printstring("Split address "); write(block, 0) !! printstring(" -> ") !! write(c, 0); printstring("c ") !! write(h, 0); printstring("h ") !! write(s, 0); print symbol('s'); newline address_head = h address_sector = s address_track l = c & 255; address_track h = c >> 8 address_z1 = 0; address_z2 = 0; address_z3 = 0 %end %integerfn do disc read(%integer block, n, %bytename buffer) %record(disc address fm) a %result = -2 %if n <= 0 %result = -2 %unless 0 <= block %and block + n <= size disc reads = disc reads + 1 %cycle split address(block, a) %cycle command(dc read disc, 8, a_unit, 0, 1) %if disc status = 0 %start command(dc read buffer, -512, buffer, 0, 0) analyse error(dc read buffer, a) %if disc status # 0 %else analyse error(dc read disc, a) %finish %result = disc status ! 16_80000000 %if disc status & fatal # 0 n = n - 1; %result = 0 %if n <= 0 block = block + 1 buffer == buffer [512] a_sector = (a_sector + 1) & sector mask %repeat %until a_sector = 0 %repeat %end %integerfn do disc write(%integer block, n, %bytename buffer) %record(disc address fm) a %result = -2 %if n <= 0 %result = -2 %unless 0 <= block %and block + n <= size !! printstring("Disc write to "); write(block, 0); newline disc writes = disc writes + 1 %cycle split address(block, a) %cycle command(dc write buffer, 512, buffer, 0, 0) %if disc status = 0 %start command(dc write disc, 8, a_unit, 0, 1) analyse error(dc write disc, a) %if disc status # 0 %else analyse error(dc write buffer, a) %finish %result = disc status ! 16_80000000 %if disc status & fatal # 0 n = n - 1; %result = 0 %if n <= 0 block = block + 1 buffer == buffer [512] a_sector = (a_sector + 1) & sector mask %repeat %until a_sector = 0 %repeat %end ! The part above is drive-dependent. The part below is drive-independent. %include "GDMR_H:Disc.Indep" ! Start it off as an independent process %begin start disc %end %of %program