! Mouse disc process for old eightinchester portable filestore ! ! Requests are sent via the standard send/receive message operations. ! P1: request code -- 0 = get disc status, 1 = read, 2 = write ! P2: block number (0 <= P2 < disc size) ! P3: buffer address %option "-low-nonstandard-nocheck-nodiag-nostack-noline" %include "MOUSE:MOUSE.INC" %systemroutinespec phex2(%integer what) %systemroutinespec phex(%integer what) %externalroutinespec FS insert(%string(31) name, %integer value) %externalroutinespec FS lookup(%string(31) name, %integername value) %ownrecord(queue fm) disc queue = 0 %ownrecord(semaphore fm) disc sema = 0 %ownrecord(mailbox fm) disc mailbox = 0 %owninteger disc reads = 0 %owninteger disc writes = 0 %owninteger disc HW = 0 %ownrecord(semaphore fm) disc interrupt = 0 %Ownrecord(interrupthandlerfm) ih %Owninteger waiting = 0 %owninteger direction = 0 { disk characteristics } %constant %integer restore step rate = 3, { 1.5ms } seek step rate = 0, { 10us } sectors per block = 2, blocks per track = 16, tracks per cylinder = 4, cylinders per drive = 256, number of drives = 1, size = 1*256*4*16 { 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) writer %routine Reset Drive %integer drive=0 writer_precomp = 16_20 { precomp from track 128 onward } ! %for drive = 0,1,1 %cycle waiting=1 writer_size drive head = drive << 3 writer_command = restore semaphore wait (disc interrupt) waiting=1 writer_cylinder high = 0 writer_cylinder low = 0 writer_command = seek { subsequent seeks at 10us step rate } semaphore wait (disc interrupt) ! %repeat Putstring("Drive reset");putsym(10) %End %predicate report error (%integer block) %if read_status & error # 0 %start putstring("Disk err:");putlong(read_errorregister); putsym(':');putlong(block);putsym(10) %true %Finish %false %End %routine initialise disc @0(a6)%Record(Interrupthandlerfm) nih %label x ih_pc = addr(x) ih_a4 = a4 Add Interrupt Handler (ih,4) Reset Drive %Return x: !putsym('?') %if read_status & busy = 0 %start ! putsym('=') %if waiting = 1 %start !putsym('*') signal Semaphore (disc interrupt) waiting = 0 %finish %Finish *movem.l nih_pc,a1/a4/a6 *jmp (a1) %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 = 0;! remainder // cylinders per drive ! %signal %event 9,3 %if drive >= number of drives writer_sector number = block * sectors per block writer_size drive head = drive << 3 + head writer_cylinder high = cylinder >> 8 writer_cylinder low = cylinder %end %integerfn disc read(%integer block, n, %bytename buffer) %Integer sector ,byte %label r1,r2,loop disc reads = disc reads + 1 %while n > 0 %cycle setup task file (block) !putsym('R');putlong(block);putsym(10) %for sector = 0,1,1 %cycle waiting = 1 writer_command = read sector semaphore wait (disc interrupt) %result=0 %if report error(block) ! %for byte = 1,1,256 %cycle ! buffer = read_data register ! buffer == buffer[1] ! %Repeat *movea.l buffer,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)+ *dbra d0,loop writer_sectornumber=read_sectornumber + 1 %Repeat ! writer_command=readsector ! semaphore wait (disc interrupt) ! d0 = 255 ! a0 = addr(buffer) ! a1 = addr(read_data register) !r1: *move.b (a1), (a0)+ ! *dbra d0,r1 ! ! buffer == buffer[256] ! writer_sectornumber=read_sectornumber + 1 ! writer_command=readsector ! semaphore wait (disc interrupt) ! d0 = 255 ! a0 = addr(buffer) ! a1 = addr(read_data register) !r2: *move.b (a1), (a0)+ ! *dbra d0,r2 buffer == buffer[512] n = n - 1; block = block + 1 %Repeat %result = 0 %end %integerfn disc write(%integer block, n, %bytename buffer) %integer sector, byte %label loop disc writes = disc writes + 1 %while n > 0 %cycle setup task file (block) !putsym('W');putlong(blocK);putsym(10) %for sector = 0, 1, 1 %cycle waiting = 1 writer_command = write sector *movea.l buffer, 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) *dbra d0, loop semaphore wait (disc interrupt) %result = -1 %if report error (block) writer_sectornumber=read_sector number + 1 %Repeat buffer == buffer[512] n = n - 1 ; block = block + 1 %Repeat %Result = 0 %end %owninteger requests pending = 0 %ownrecord(queue fm) pending queue = 0 !! %routine dump queue(%string(63) where) !! %record(message fm)%name m !! printstring(where) !! m == record(addr(pending queue)) !! %cycle !! %if addr(m) = addr(pending queue) %start !! printstring("*TAIL*") !! newline !! %return !! %finish !! phex(addr(m)) !! printstring(" (") !! writer(m_i(2), 0) !! printstring(") ") !! %repeat !! %end %routine change direction direction = \direction ! %if direction = 0 %then putstring("->") %else putstring("<-") ! putlong(disc reads) ! putsym(10) %End %routine do pending %ownrecord(queue fm)%name next == nil %record(message fm)%name x requests pending = requests pending - 1 %if requests pending = 0 %start ! Only one thing on the queue x == record(addr(pending queue_forward)) next == nil ! direction = \direction; !? change direction %else x == record(addr(next)) %if direction = 0 %start x == record(addr(pending queue_forward)) %if x == nil x_queue_backward_forward == x_queue_forward x_queue_forward_backward == x_queue_backward next == x_queue_forward %else x == record(addr(pending queue_backward)) %if x == nil x_queue_backward_forward == x_queue_forward x_queue_forward_backward == x_queue_backward next == x_queue_backward %finish ! next == nil %and direction = \direction %if next == pending queue next == nil %and change direction %if next == pending queue %finish %if x_i(1) = 1 %start ! Read buffer x_i(1) = disc read(x_i(2), x_i(4), byteinteger(x_i(3))) %else ! writebuffer x_i(1) = disc write(x_i(2), x_i(4), byteinteger(x_i(3))) %finish send message(x, x_reply, nil) %end %routine add pending(%record(message fm)%name x) %record(message fm)%name m %if requests pending <= 0 %start ! Queue is empty pending queue_forward == x_queue x_queue_backward == pending queue x_queue_forward == pending queue pending queue_backward == x_queue requests pending = 1 disc HW = 1 %if disc HW = 0 %return %finish m == record(addr(pending queue)) %cycle m == record(addr(m_queue_forward)) %if addr(m) = addr(pending queue) %or m_i(2) > x_i(2) %start x_queue_forward == m_queue x_queue_backward == m_queue_backward m_queue_backward_forward == x_queue m_queue_backward == x_queue requests pending = requests pending + 1 disc HW = requests pending %if disc HW < requests pending %return %finish %repeat %end %routine pending request(%record(message fm)%name x) %if x_i(1) = 0 %start ! Status enquiry x_i(1) = 0 x_i(2) = size x_i(3) = 0; ! Meantime send message(x, x_reply, nil) %else %if x_i(1) = 1 %or x_i(1) = 2 add pending(x) %else %if x_i(1) = 3 x_i(1) = 0 x_i(2) = disc reads x_i(3) = disc writes x_i(4) = disc HW; disc HW = 0; ! Clear? send message(x, x_reply, nil) %else ! Unrecognised request x_i(1) = -1 send message(x, x_reply, nil) %finish %end %routine disc process %record(message fm)%name x %integer lasttime %label end initialise disc Putstring ("Disc Process (Mini) running");putsym(10) %cycle x == receive message(disc mailbox) pending request(x) %cycle %cycle x == dequeue(disc mailbox_queue) %exit %if x == nil semaphore wait(disc mailbox_semaphore) pending request(x) %repeat %if requests pending > 0 %then do pending %c %else %exit %repeat %repeat %end %externalroutine start disc %record(process fm)%name p %ownrecord(runqueuefm) r=0 %integer i %label z ! i = read_status {just in case} ! i = set SR(0) putstring("Starting disc");putsym(10) disc mailbox_semaphore == disc sema p == current process r_interrupter == p_target_interrupter r_processes_forward == r_processes r_processes_backward == r_processes requeue(r, p_target_queue_header) p == create process(8192, addr(z), r, r_processes) FS insert("FUJI2243_REQUESTS", addr(disc mailbox)) %return z: disc process %end %end %of %file