! Ambit disc controller module, speaking to RWT-style interface. ! Include before disc independent part. %externalstring(47) copyright ambit %alias "GDMR_(C)_DISC.AMBIT" = %c "Copyright (C) 1987 George D.M. Ross" %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 sector 0 mask = sectors 0 - 1 %constinteger sector 1 mask = sectors 1 - 1 %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 %ownbyte disc r int = 0 %constinteger dc initialise = 16_02 %constinteger dc initialise 1 = 16_07 %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, %integer seek required) %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: status "); phex2(disc status) printstring(", command "); phex2(command) %if a ## nil %start printstring(", address ") 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) ! bytes + -> write to controller ! bytes 0 -> no parameter part ! bytes - -> read from controller ! intwait # 0 iff interrupts are to be used %integer i, junk {} put sym('.'); put long(op); put sym('.') {} put sym('1') disc r int = disc r %while disc r int # 16_A0 {} put sym('2') disc w = op {} put sym('3') i = disc r %until i = 16_A1 {} put sym('4') disc w = 16_FF {} put sym('5') %for i = 1, 1, 50 %cycle; %repeat; ! Placate disc controller {} put sym('6') %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 r, D1 *dbra D0, rf %finish %finish {} put sym('7') disc w = 16_FF {} put sym('8') %for i = 1, 1, 50 %cycle; %repeat; ! Placate disc controller %if op & 16_40 = 0 %start ! No interrupt expected here %cycle {} put sym('9') %repeat %until disc r = 16_FF %else ! Interrupt expected ! %cycle {} put sym('W') semaphore wait(disc interrupt) ! %repeat %until disc r int = 16_FF %finish {} put sym('A') disc w = 16_FE ! %cycle {} put sym('B') semaphore wait(disc interrupt) ! %repeat %until disc r int & 16_80 = 0 {} put sym('C') disc status = disc r {} put sym('D') disc w = 0 semaphore wait(disc interrupt) {} put sym('#') %end %routine initialise disc %ownbytearray b0(0 : 15) = 255, 0, 0, { Pre-compensation } 0, 0, 0, { RWC } 4, { Buffered step } (cylinders 0 - 1) & 255, (cylinders 0 - 1) >> 8, { Max track } 0, 0, { Last user track (disabled) } 0, { Bad track mapping } 0, { Removable drive } 0, 0, 0 { Reserved, mbz } %ownbytearray b1(0 : 15) = 255, 0, 0, { Pre-compensation } 0, 0, 0, { RWC } 4, { Buffered step } (cylinders 1 - 1) & 255, (cylinders 1 - 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 %ownrecord(disc address fm) da = 0 %integer i %label h, x !! 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 a = 255; ! Arm the interface disc w = 0; ! Initialise the protocol ! Set up drive 0 command(dc write buffer, 16, b0(0), 512 - 16) %if disc status # 0 %start printstring("Disc init 0: write buffer status ") phex2(disc status); newline %stop %finish command(dc initialise, 0, null byte, 0) %if disc status # 0 %start printstring("Disc init 0: init status "); phex2(disc status) newline %stop %finish command(dc seek, 8, da_unit, 0) !! printstring("0 seek status "); phex2(disc status); newline drive 0 size = heads 0 * sectors 0 * cylinders 0 %if disc status = 0 ! Now for drive 1 command(dc write buffer, 16, b1(0), 512 - 16) %if disc status # 0 %start printstring("Disc init 1: write buffer status ") phex2(disc status); newline %stop %finish command(dc initialise 1, 0, null byte, 0) %if disc status # 0 %start printstring("Disc init 1: init status "); phex2(disc status) newline %stop %finish da_unit = 1 command(dc seek, 8, da_unit, 0) !! printstring("1 seek status "); phex2(disc status); newline drive 1 size = heads 1 * sectors 1 * cylinders 1 %if disc status = 0 %return H: D0 = 50 X: *move.l D1, D1 *dbra D0, X {} put sym('I') *move.b disc r, disc r int int signal semaphore(disc interrupt) return from interrupt *move.l D0, D0; ! In case of "optimisations" %end %routine split address(%integer block, unit, %record(disc address fm)%name address) %owninteger last cylinder = -1 %integer c, h, s address_unit = unit %if unit = 0 %start h = block // sectors 0; s = block - h * sectors 0 c = h // heads 0; h = h - c * heads 0 %else {%if unit = 1 h = block // sectors 1; s = block - h * sectors 1 c = h // heads 1; h = h - c * heads 1 %finish !! 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 %if c = last cylinder %start address_seek required = 0 %else last cylinder = c address_seek required = 1 %finish %end %integerfn do disc read(%integer block, n, %bytename buffer) %record(disc address fm) a %integer unit, sector mask %result = -2 %if n <= 0 unit = block >> unit shift; block = block & block mask !! printstring("Unit "); write(unit, 0) !! printstring(" block "); write(block, 0); newline %if unit = 0 %start %result = -2 %unless 0 <= block %and block + n <= drive 0 size sector mask = sector 0 mask %else {%if unit = 1 %result = -2 %unless 0 <= block %and block + n <= drive 1 size sector mask = sector 1 mask %finish disc reads = disc reads + 1 %cycle split address(block, unit, a) %if a_seek required # 0 %start command(dc seek, 8, a_unit, 0) analyse error(dc seek, a) %if disc status # 0 %finish %cycle command(dc read disc, 8, a_unit, 0) analyse error(dc read disc, a) %if disc status # 0 %if disc status & fatal = 0 %start command(dc read buffer, -512, buffer, 0) analyse error(dc read buffer, a) %if disc status # 0 %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 %integer unit, sector mask %result = -2 %if n <= 0 unit = block >> unit shift; block = block & block mask %if unit = 0 %start %result = -2 %unless 0 <= block %and block + n <= drive 0 size sector mask = sector 0 mask %else {%if unit = 1 %result = -2 %unless 0 <= block %and block + n <= drive 1 size sector mask = sector 1 mask %finish !! printstring("Disc write to "); write(block, 0); newline disc writes = disc writes + 1 %cycle split address(block, unit, a) %if a_seek required # 0 %start command(dc seek, 8, a_unit, 0) analyse error(dc seek, a) %if disc status # 0 %finish %cycle command(dc write buffer, 512, buffer, 0) analyse error(dc write buffer, a) %if disc status # 0 %if disc status & fatal = 0 %start command(dc write disc, 8, a_unit, 0) analyse error(dc write disc, a) %if disc status # 0 %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 %end %of %file