DIRECTORY AltoMicrocodeDefs: FROM "AltoMicrocodeDefs", D0MicrocodeDefs: FROM "D0MicrocodeDefs", --used if D0 ImageDefs: FROM "ImageDefs", InlineDefs: FROM "InlineDefs" USING [BITAND,BITOR], JasmineDefs: FROM "JasmineDefs", MemoryOps: FROM "MemoryOps" USING [MachineType,GetMemoryConfig], Mopcodes: FROM "Mopcodes", RamDefs: FROM "RamDefs", --used if AltoIIXM SystemDefs: FROM "SystemDefs" USING [AllocateSegment,FreeSegment]; JasmineUtil: PROGRAM IMPORTS AltoMicrocodeDefs, D0MicrocodeDefs, ImageDefs, InlineDefs, MemoryOps, RamDefs,SystemDefs,JasmineDefs EXPORTS JasmineDefs = BEGIN OPEN InlineDefs,JasmineDefs; --scanner settings Reverse: BOOLEAN = FALSE; DelaySetting: CARDINAL _ 13; SkipSamples: CARDINAL _ 0; ArraySize: CARDINAL = 1024; Time: CARDINAL _ 656; --38 usec ticks = 1/40 sec Late: CARDINAL _ 0; Bad: CARDINAL _ 0; ReadMode: CARDINAL _ 2; --Read,Step ScannerTaskBits: CARDINAL = 177376B; StepTime: CARDINAL _ 130; --200 steps/second TopBlank: CARDINAL _ 120; nDiscardElements: CARDINAL _ 0; nElements: CARDINAL _ ArraySize; currentScanLine: CARDINAL _ 177777B; --not active firstScanLine: CARDINAL _ 177777B; nScanLines: CARDINAL _ 77777B; FrontDelayCB: ScanCB _ [@DelayCB,0,CommandDELAY,StatusFREE,NIL]; DelayCB: ScanCB _ [NIL,0,CommandDELAY,StatusFREE,NIL]; Machine: MemoryOps.MachineType = MemoryOps.GetMemoryConfig[].AltoType; SetBLV: PUBLIC PROCEDURE[UNSPECIFIED] = MACHINE CODE BEGIN Mopcodes.zLIW,477B/256,477B MOD 256;Mopcodes.zJRAM; END; JasmineCleanupProc: PROCEDURE [why: ImageDefs.CleanupReason] = BEGIN SELECT why FROM Finish,Abort => BEGIN JasmineMotorOff[]; JasmineControllerOff[]; ImageDefs.RemoveCleanupProcedure[@JasmineCleanupItem]; END; OutLd => JasmineControllerOff[]; InLd => JasmineControllerOn[]; ENDCASE => ERROR; END; JasmineCleanupItem: ImageDefs.CleanupItem _ [NIL,177777B,JasmineCleanupProc]; JasmineInit: PUBLIC PROCEDURE = BEGIN ImageDefs.AddCleanupProcedure[@JasmineCleanupItem]; ScanCBHead^ _ NIL; ScanTime^ _ Time; SELECT Machine FROM AltoI,AltoII => ERROR; --must be an AltoIIXM AltoIIXM =>AltoMicrocodeDefs.LoadRam[]; D0 => NULL; ENDCASE => ERROR; --unimplemented machine type JasmineControllerOn[]; Init[]; JasmineSendCommand[SETDELAY,DelaySetting]; InitStartCommand[]; END; JasmineSetDelay: PUBLIC PROCEDURE [delay: [0..15]] = BEGIN DelaySetting _ delay; JasmineControllerOff[]; JasmineSendCommand[SETDELAY,DelaySetting]; JasmineControllerOn[]; END; JasmineSetResolution: PUBLIC PROCEDURE [skips: [0..15]] = BEGIN SkipSamples _ skips; InitStartCommand[]; END; --readOnly=1, readAndStep=2, readStepAndDelay=3 JasmineSetReadMode: PUBLIC PROCEDURE [readMode: [1..3]] = BEGIN ReadMode _ readMode; END; JasmineNewPage: PUBLIC PROCEDURE [pageLen: CARDINAL] = --[>100 = 250u, <100=inches] BEGIN JasmineStep[TopBlank,TRUE]; currentScanLine _ 0; END; JasmineEject: PUBLIC PROCEDURE = BEGIN IF firstScanLine # 177777B THEN BEGIN JasmineStep[currentScanLine,FALSE]; JasmineStep[TopBlank+50,FALSE]; firstScanLine _ 177777B; END; END; JasmineCoord: PUBLIC PROCEDURE [c: CARDINAL] RETURNS [CARDINAL] = BEGIN --(coord) returns # samples RETURN[c/(SkipSamples+1)]; END; JasmineSetWindow: PUBLIC PROCEDURE [xStart,xLen,yStart,yLen: CARDINAL] = BEGIN--in full resolution coords (250 microns) firstScanLine _ yStart; nScanLines _ yLen; IF Reverse THEN nDiscardElements _ ArraySize-(xStart+xLen) ELSE nDiscardElements _ xStart; nElements _ xLen; IF Machine = AltoIIXM THEN IF xLen < 500 THEN JasmineSetReadMode[3] ELSE JasmineSetReadMode[2]; END; JasmineSetTime: PUBLIC PROCEDURE [ticks: CARDINAL] = BEGIN--(ticks = 38usecond units) Time _ ticks; ScanTime^ _ Time; END; JasmineLoadRam: PUBLIC PROCEDURE [ramvals: POINTER TO ARRAY [0..ArraySize) OF RAMval] = BEGIN i: CARDINAL; load: dataOut _ [0,FALSE,LOAD,0]; we1: dataOut _ [0,FALSE,WE1,0]; we2: dataOut _ [0,FALSE,WE2,0]; we3: dataOut _ [0,FALSE,WE3,0]; JasmineControllerOff[]; JasmineSendCommand[SETDELAY,0]; --enable addr counting during load Init[]; IF Reverse THEN FOR i DECREASING IN [0..ArraySize) DO Pulse[load]; we1.data _ ramvals[i].q2;we2.data _ ramvals[i].q3;we3.data _ ramvals[i].q4; Pulse[we1]; Pulse[we2]; Pulse[we3]; ENDLOOP ELSE FOR i IN [0..ArraySize) DO Pulse[load]; we1.data _ ramvals[i].q2;we2.data _ ramvals[i].q3;we3.data _ ramvals[i].q4; Pulse[we1]; Pulse[we2]; Pulse[we3]; ENDLOOP; JasmineSendCommand[SETDELAY,DelaySetting]; Init[]; JasmineControllerOn[]; END; JasmineScanInit: PUBLIC PROCEDURE RETURNS [POINTER TO ScanHead] = BEGIN nBlocks: CARDINAL = 4; nBytes: CARDINAL = (nElements+SkipSamples)/(SkipSamples + 1); nDiscardCommands: CARDINAL= IF nDiscardElements/(SkipSamples+1)<=1 THEN 0 ELSE 1; wordsPerBlock: CARDINAL=(nBytes+1)/2 + SIZE[ScanCB]*(ReadMode+SkipSamples+nDiscardCommands); block: POINTER TO ScanHead _ SystemDefs.AllocateSegment[SIZE[ScanHead] +nBlocks*wordsPerBlock]; blockBase: POINTER TO ScanCB _ LOOPHOLE[block + SIZE[ScanHead]]; i: CARDINAL; block^ _ [firstCB: blockBase,nBlocks: nBlocks,nextBlock: 0, nCBsPerBlock: ReadMode+SkipSamples+nDiscardCommands, nScanLines: nScanLines]; IF (firstScanLine#177777B) AND (currentScanLine # firstScanLine) THEN BEGIN JasmineStep[firstScanLine-currentScanLine,TRUE]; currentScanLine _ firstScanLine; END; ScanCBHead^ _ NIL; ScanTime^ _ Time; DelayCB.link _ NIL; FOR i IN [0..nBlocks) DO NewReadCommand[block,i,@DelayCB.link];ENDLOOP; ScanCBHead^ _ @FrontDelayCB; RETURN[block]; END; JasmineScanClose: PUBLIC PROCEDURE [s: POINTER TO ScanHead] = BEGIN ScanCBHead^ _ NIL; UNTIL JasmineReadLine[s,FALSE] = NIL DO ENDLOOP; --to update currentScanLine count SystemDefs.FreeSegment[s]; END; JasmineReadLine: PUBLIC PROCEDURE [s: POINTER TO ScanHead,continue: BOOLEAN _ TRUE] RETURNS [POINTER TO PACKED ARRAY OF [0..377B]] = BEGIN thisBlock: CARDINAL _ s.nextBlock; lastBlock: CARDINAL _ IF thisBlock = 0 THEN s.nBlocks-1 ELSE thisBlock-1; nCBsPerBlock: CARDINAL _ s.nCBsPerBlock; lastBlockptr: POINTER TO ScanCB _ s.firstCB+lastBlock*nCBsPerBlock*SIZE[ScanCB]; thisBlockptr: POINTER TO ScanCB _ s.firstCB+thisBlock*nCBsPerBlock*SIZE[ScanCB]; thisBlockend: POINTER TO ScanCB _ thisBlockptr+(nCBsPerBlock-1)*SIZE[ScanCB]; blockStatus: JasmineCBStatus; IF s.nScanLines <= 0 THEN continue _ FALSE; IF (lastBlockptr.status = StatusFREE) AND continue THEN --queue up new command NewReadCommand[s,lastBlock,ScanCBHead]; UNTIL (thisBlockend.status < 0) OR (ScanCBHead^ = NIL) DO ENDLOOP; IF thisBlockptr.buffer = NIL THEN --was a discard BEGIN thisBlockptr.status _ StatusFREE; thisBlockptr _ thisBlockptr.link; UNTIL (thisBlockend.status < 0) OR (ScanCBHead^ = NIL) DO ENDLOOP; END; blockStatus _ thisBlockptr.status; s.nextBlock _ IF thisBlock = s.nBlocks-1 THEN 0 ELSE thisBlock+1; thisBlockptr.status _ StatusFREE; IF blockStatus = StatusDONE THEN BEGIN IF firstScanLine # 177777B THEN currentScanLine _ currentScanLine+SkipSamples+1; s.nScanLines _ s.nScanLines-(SkipSamples+1); RETURN[thisBlockptr.buffer]; END; IF NOT continue THEN RETURN[NIL]; IF blockStatus = StatusDATALATE THEN BEGIN Late _ Late+1; --CallSwat("DataLate") JasmineSetDelay[DelaySetting]; DelayCB.link _ thisBlockend.link; ScanCBHead^ _ @FrontDelayCB; RETURN[JasmineReadLine[s]]; END; Bad _ Bad+1; --CallSwat("Bad") RETURN[NIL]; --NextScanLine(s) END; JasmineStep: PUBLIC PROCEDURE [nSteps: INTEGER,forward: BOOLEAN] = BEGIN reversed: BOOLEAN = nSteps < 0; v: ScanCB; CBHandle: POINTER TO ScanCB _ @v; IF reversed THEN BEGIN forward _ NOT forward; nSteps _ -nSteps; END; --LOOK OUT! --if you access "v.foo", and if v.foo is --near the top of the local frame, it will be held in a microcode --register on the D0, and won't actually dereference the memory --location until the next process switch (at 60Hz) CBHandle.link _ NIL; CBHandle.command _ IF forward THEN CommandFORWARD ELSE CommandBACK; CBHandle.blank _ 0; UNTIL ScanCBHead^ = NIL DO ENDLOOP; ScanTime^ _ StepTime; THROUGH [1..nSteps] DO CBHandle.status _ StatusINUSE; ScanCBHead^ _ CBHandle; UNTIL CBHandle.status = StatusDONE DO ENDLOOP; ENDLOOP; ScanTime^ _ Time; END; --and the local procedures JasmineControllerOn: PUBLIC PROCEDURE = BEGIN SELECT Machine FROM AltoIIXM => BEGIN SetBLV[ScannerTaskBits];[] _ RamDefs.StartIO[100000B]; END; D0 => D0MicrocodeDefs.JumpRam[7010B]; ENDCASE => ERROR; END; JasmineControllerOff: PUBLIC PROCEDURE = BEGIN SELECT Machine FROM AltoIIXM => BEGIN SetBLV[177776B];[] _ RamDefs.StartIO[100000B]; END; D0 => D0MicrocodeDefs.JumpRam[7011B]; ENDCASE => ERROR; END; NewReadCommand: PUBLIC PROCEDURE [block: POINTER TO ScanHead,num: CARDINAL,scanHead: POINTER TO POINTER TO ScanCB] = BEGIN nDiscardBytes: CARDINAL _ BITAND[nDiscardElements/(SkipSamples+1),177776B]; nBytes: CARDINAL _ BITAND[(nElements+SkipSamples)/(SkipSamples + 1)+1,177776B]; nWords: CARDINAL _ (nBytes+1)/2; nCBsPerBlock: CARDINAL _ block.nCBsPerBlock; base: POINTER TO ScanCB _ block.firstCB + num*nCBsPerBlock*SIZE[ScanCB]; bufferBase: POINTER TO PACKED ARRAY OF [0..377B] _ LOOPHOLE[block.firstCB +(block.nBlocks)*nCBsPerBlock*SIZE[ScanCB]]; link,newLink: POINTER TO POINTER TO ScanCB; thisCB: POINTER TO ScanCB _ base; IF nDiscardBytes > 0 THEN BEGIN thisCB^ _ [link: thisCB + SIZE[ScanCB],blank: 0,command: CommandREAD, status: nDiscardBytes,buffer: NIL]; thisCB _ thisCB + SIZE[ScanCB]; END; thisCB^ _ [link: NIL,blank: 0,command: CommandREAD, status: nBytes,buffer: bufferBase + num*nWords]; IF ReadMode > 1 THEN BEGIN THROUGH [0..SkipSamples] DO thisCB.link _ thisCB + SIZE[ScanCB]; thisCB _ thisCB + SIZE[ScanCB]; thisCB^ _ [link: NIL,blank: 0,command: CommandFORWARD, status: StatusINUSE,buffer: ]; ENDLOOP; IF ReadMode > 2 THEN BEGIN thisCB.link _ thisCB + SIZE[ScanCB]; thisCB _ thisCB + SIZE[ScanCB]; thisCB^ _ [link: NIL,blank: 0,command: CommandDELAY, status: StatusINUSE,buffer: ]; END; END; --the following code doesn't work: -- UNTIL link^ eq NIL do link _ link^ --because if link = scanHead, then --between the test for "eq 0" and the assignment, scanHead may be zeroed --by the ucode, causing us to add a chain through 77400 (0^) link _ scanHead; DO newLink _ LOOPHOLE[link^]; IF newLink = NIL THEN EXIT; link _ newLink; ENDLOOP; link^ _ base; IF scanHead^ = NIL THEN scanHead^ _ base; END; Init: PUBLIC PROCEDURE = BEGIN JasmineSendCommand[LOAD,0];JasmineSendCommand[SCANSTART,0]; END; InitStartCommand: PUBLIC PROCEDURE = BEGIN StartCommand^ _ [blank:0,enable:FALSE,command:SCANSTART,data:SkipSamples]; END; JasmineMotorOff: PUBLIC PROCEDURE = BEGIN JasmineSendCommand[MOTORCTL,4]; END; JasmineSendCommand: PUBLIC PROCEDURE [command: JasmineCommand,data: [0..17B]] = BEGIN Pulse[[blank:0,enable: FALSE,command: command,data: data]]; END; (635)\f1 523b1B119b39B17b11B16b9B19b4B45b4B16b3B16b8B28b15B22b8B37b8B18b16B16b9B24b15B35b13B22b10B21b12B53b7B49b78B112b18B67f0 203f1 25b18B61b11B315f0 18f1 51b15B66f0 20f1 4f0 18f1 54b20B91f0 48b18B73f1b14B131f0b12B174f1b12B121b16B360b14B110b14B224f0 20f1 4f0 18f1 434f0 18f1 62b15B957b5B30b16B187b15B1545b5B115b11B218b233B330b28B215f0 20f1 188b14B1350f0 243f1 166b4B27f0 18f1 9f0 18f1 21b16B108b15B27f0 18f1 20f0b18f1B Pulse: PUBLIC PROCEDURE [d: dataOut] = BEGIN enable: dataOut = [0,TRUE,LOOPHOLE[0],0]; SELECT Machine FROM AltoIIXM => BEGIN Outport^ _ d; Outport^ _ InlineDefs.BITOR[d,enable]; Outport^ _ d; END; D0 => D0MicrocodeDefs.JumpRamArg[7012B,d]; ENDCASE => ERROR; END; END. \f1b5B