-- ColorVersatecDriverImpl.mesa -- Jim Gasbarro 10-Dec-84 13:29:11 -- Tim Diebert, 5-Sep-86 9:50:00 DIRECTORY ColorVersatecDriver, ColorVersatecUtils, DicentraInputOutput, Inline, OthelloDefs, PDQueue USING [LogMessage], Process, SpecialRuntime; ColorVersatecDriverImpl: MONITOR IMPORTS OthelloDefs, ColorVersatecUtils, DicentraInputOutput, Inline, PDQueue, Process, SpecialRuntime EXPORTS ColorVersatecDriver = BEGIN bpi: CARDINAL = ColorVersatecDriver.bpi; pageWidthInches: CARDINAL = ColorVersatecDriver.pageWidthInches; white: CARDINAL = ColorVersatecDriver.white; wordsPerScan: CARDINAL = ColorVersatecDriver.wordsPerScan; versatecBaseAdd: DicentraInputOutput.IOAddress = LOOPHOLE[LONG[4000H]]; ColorPreamble: TYPE = MACHINE DEPENDENT RECORD [ escape: [0..256) ← 9BH, -- escape header: CHARACTER, byteCountHigh: [0..256) ← 0, byteCountLow: [0..256) ← 4, lengthHigh: [0..256) ← 0, lengthLow: [0..256) ← 0, modeAndColor: ModeAndColor, reserved: [0..256) ← 0 ]; CommandPreamble: TYPE = MACHINE DEPENDENT RECORD [ escape: [0..256) ← 9BH, -- escape header: CHARACTER, byteCountHigh: [0..256) ← 0, byteCountLow: [0..256) ← 0 ]; ModeAndColor: TYPE = MACHINE DEPENDENT RECORD [ padding: [0..16) ← 0, mode: ColorVersatecDriver.ColorMode, color: ColorVersatecDriver.Color ← Black ]; -- Controller registers ControllerRegister: TYPE = { dMABaseLow, wordCountReg, unused2, unused3, unused4, unused5, unused6, unused7, i8237CommandStatus, request, writeSingleMask, mode, clearBytePointer, i8237MasterClear, clearMask, writeAllMask, dMABaseHigh, interruptCommandStatus, versatecControlStatus, versatecProgrammedDataOut, unused14, unused15, interruptEnableRegister, boardReset }; -- i8237 Command Register (08, Write) disablei8237: CARDINAL = 04H; memToMemTransfer: CARDINAL = 01H; -- i8237 Status Register (08, Read) ch0Request: CARDINAL = 10H; ch0ReachedTermCount: CARDINAL = 01H; -- i8237 Internal Request Register (09, Write) setInternalRequestChan0: CARDINAL = 04H; -- i8237 Single Mask Register (0A, Write) clearInternalMaskChan0: CARDINAL = 00H; -- i8237 Mode Register (0B, Write) chanCharacteristics: CARDINAL = 48H; -- i8237 Byte Pointer FF Command (0C, Write) clearPointer: CARDINAL = 00H; -- i8237 Master Clear (0D, Write) powerUp: CARDINAL = 00H; -- i8237 Temporary Register (0D, Read) -- unused -- -- i8237 Clear Mask Register (0E, Write) -- unused -- -- i8237 Mask Register (0F, Write) -- unused -- Interrupt Command Register Bits (11H, Write) clearVersatecChannel: CARDINAL = 80H; clearAttnInterrupt: CARDINAL = 40H; disableAttn: CARDINAL = 20H; enableAttn: CARDINAL = 10H; clearDone: CARDINAL = 08H; setDoneOnComplete: CARDINAL = 04H; setDoneOnReady: CARDINAL = 02H; transferOdd: CARDINAL = 01H; -- Interrupt Status Register Bits (11H, Read) -- unused = 80H; attn: CARDINAL = 40H; latchedEOP: CARDINAL = 20H; memoryError: CARDINAL = 10H; done: CARDINAL = 08H; doneOnTransferComplete: CARDINAL = 04H; doneOnVersatecReady: CARDINAL = 02H; oddTransfer: CARDINAL = 01H; -- Versatec Control Register Bits (12H, Write) plotMode: CARDINAL = 80H; sPPMode: CARDINAL = 40H; -- unused = 20H; sendRemoteEOT: CARDINAL = 10H; sendRemoteFF: CARDINAL = 08H; sendRemoteLineTerm: CARDINAL = 04H; sendRemoteClear: CARDINAL = 02H; sendRemoteReset: CARDINAL = 01H; -- Versatec Status Register Bits (12H, Read) inPlotMode: CARDINAL = 80H; inSPPMode: CARDINAL = 40H; -- unused = 20H; dataRequest: CARDINAL = 10H; isReady: CARDINAL = 08H; hasPaper: CARDINAL = 04H; isOnLine: CARDINAL = 02H; isOK: CARDINAL = 01H; -- PUBLIC PROCEDURES AND VARIABLES K64Words: LONG CARDINAL = LONG[64]*1024; PlotBuffer: PUBLIC PROC [wordCount: LONG CARDINAL, hyperOffset: LONG CARDINAL] = BEGIN WHILE wordCount>0 DO toNextBoundary: LONG CARDINAL ← K64Words - Inline.LowHalf[hyperOffset]; xferSize: CARDINAL ← CARDINAL[MIN[wordCount, toNextBoundary, K64Words-1]]; IF Inline.HighHalf[ColorVersatecUtils.hyperStart+hyperOffset] # Inline.HighHalf[ColorVersatecUtils.hyperStart+hyperOffset+xferSize-1] THEN ERROR; VersatecDMASend[wordCount: xferSize, hyperOffset: hyperOffset]; hyperOffset ← hyperOffset + xferSize; wordCount ← wordCount - xferSize; ENDLOOP; END; VersatecDMASend: ENTRY PROC [wordCount: CARDINAL, hyperOffset: LONG CARDINAL] = BEGIN loopCnt: CARDINAL ← 0; -- For timeout check.... messageSent: BOOL ← FALSE; addr: LONG CARDINAL = LOOPHOLE[ColorVersatecUtils.hyperStart + hyperOffset]; -- WHILE DMABusy[] DO ENDLOOP; -- Clear byte pointer FF, don't need to do this, but I'm paranoid... WriteByte[clearPointer, clearBytePointer]; -- The i8237 wants word addresses in the low two bytes of the base address WriteByte[Inline.LowByte[Inline.LowHalf[addr]], dMABaseLow]; WriteByte[Inline.HighByte[Inline.LowHalf[addr]], dMABaseLow]; -- The i8237 wants a byte address in the high order byte of the base address WriteByte[Inline.LowByte[Inline.HighHalf[addr * 2]], dMABaseHigh]; -- The i8237 wants the transfer count in words -- NOTE: The 8237 transfers wordCount + 1 words, I subtract 1 to nomalize WriteByte[Inline.LowByte[wordCount - 1], wordCountReg]; WriteByte[Inline.HighByte[wordCount - 1], wordCountReg]; -- Clear odd/even byte count FF, Clear Done, set Done on Xfer complete WriteByte[0CH, interruptCommandStatus]; -- Stop Clearing Done, set Done on Xfer complete WriteByte[04H, interruptCommandStatus]; -- Let'er rip WriteByte[clearInternalMaskChan0, writeSingleMask]; EnableInterrupts[]; WHILE DMABusy[] DO WAIT cv↑; loopCnt ← loopCnt + 1; IF loopCnt > 3 AND NOT messageSent THEN BEGIN PDQueue.LogMessage["DMA to Versatec timeout!!!! Boot needed!!!\n\l"]; messageSent ← TRUE; END; ENDLOOP; DisableInterrupts[]; END; EnableInterrupts: PROC [] = BEGIN WriteByte[01H, interruptEnableRegister]; END; DisableInterrupts: PROC [] = BEGIN WriteByte[00H, interruptEnableRegister]; END; DMABusy: PROC [] RETURNS [BOOLEAN] = BEGIN bits: CARDINAL ← ReadByte[interruptCommandStatus]; IF Inline.BITAND[bits, memoryError] # 0 THEN ERROR; RETURN[Inline.BITAND[bits, done] = 0]; END; VersatecIsOK: PUBLIC PROC [] RETURNS [BOOLEAN] = BEGIN -- has paper and is on line bits: CARDINAL ← ReadByte[versatecControlStatus]; RETURN[Inline.BITAND[bits, isOK] # 0]; END; InitVersatecDMA: PROC [] = BEGIN mask: WORD; VersatecInitialCheckout[]; -- Reset the world WriteByte[0, boardReset]; WriteByte[0, i8237MasterClear]; -- Clear Versatec channel, clear Done, set Done on transfer complete WriteByte[9CH, interruptCommandStatus]; WriteByte[0CH, interruptCommandStatus]; WriteByte[sendRemoteClear, versatecControlStatus]; -- Set operational mode on all i8237 channels WriteByte[chanCharacteristics+0, mode]; WriteByte[chanCharacteristics+1, mode]; WriteByte[chanCharacteristics+2, mode]; WriteByte[chanCharacteristics+3, mode]; [cv, mask] ← SpecialRuntime.AllocateNakedCondition[]; [] ← DicentraInputOutput.SetWakeupMask[bits: mask, intLevel: display]; Process.SetTimeout[cv, Process.SecondsToTicks[300]]; END; VersatecInitialCheckout: PUBLIC PROC [] = BEGIN WHILE NOT VersatecIsOK[] DO OthelloDefs.WriteLine["Versatec is Offline or out of paper"]; Process.Pause[Process.SecondsToTicks[2]]; IF NOT VersatecIsOK[] THEN BEGIN OthelloDefs.WriteLine[" Versatec is Offline or out of paper"]; Process.Pause[Process.SecondsToTicks[3]]; END; ENDLOOP; END; SetColorMode: PUBLIC PROC [inches: CARDINAL, mode: ColorVersatecDriver.ColorMode, color: ColorVersatecDriver.Color ← Black, cmdOffset: CARDINAL] = BEGIN p: LONG POINTER ← @preamble; preamble: ColorPreamble ← [ header: 'P, -- color header preamble lengthLow: inches, -- length in inches modeAndColor: [mode: mode, color: color] ]; SetPrintMode[]; ColorVersatecUtils.HyperStore [sourcePtr: p, destOffset: cmdOffset, wordCount: SIZE[ColorPreamble]]; VersatecDMASend [wordCount: SIZE[ColorPreamble], hyperOffset: cmdOffset]; SetPlotMode[]; END; Rewind: PUBLIC PROC [cmdOffset: CARDINAL] = BEGIN p: LONG POINTER ← @preamble; preamble: CommandPreamble ← [header: 'W]; -- rewind SetPrintMode[]; ColorVersatecUtils.HyperStore [sourcePtr: p, destOffset: cmdOffset, wordCount: SIZE[CommandPreamble]]; VersatecDMASend [wordCount: SIZE[CommandPreamble], hyperOffset: cmdOffset]; SetPlotMode[]; END; SetPrintMode: PROC [] = BEGIN WriteByte[0H, versatecControlStatus]; END; SetPlotMode: PROC [] = BEGIN WriteByte[80H, versatecControlStatus]; END; SendEOT: PUBLIC PROC [] = BEGIN bits: CARDINAL ← ReadByte[versatecControlStatus]; WriteByte[Inline.BITOR[Inline.BITAND[bits, plotMode], sendRemoteEOT], versatecControlStatus]; END; FormFeed: PUBLIC PROC [] = BEGIN bits: CARDINAL ← ReadByte[versatecControlStatus]; WriteByte[Inline.BITOR[Inline.BITAND[bits, plotMode], sendRemoteFF], versatecControlStatus]; END; SendRLT: PUBLIC PROC [] = BEGIN bits: CARDINAL ← ReadByte[versatecControlStatus]; WriteByte[Inline.BITOR[Inline.BITAND[bits, plotMode], sendRemoteLineTerm], versatecControlStatus]; END; -- BEWARE HACKED TO BE BACKWARDS baseAddress: DicentraInputOutput.IOAddress = LOOPHOLE[LONG[4010H]]; ReadByte: PROC [y: ControllerRegister] RETURNS [CARDINAL] = BEGIN byteOffset: CARDINAL = y.ORD; IF (byteOffset MOD 2) # 0 THEN RETURN[DicentraInputOutput.InputByteEven[baseAddress+byteOffset/2]] ELSE RETURN[DicentraInputOutput.InputByteOdd[baseAddress+byteOffset/2]]; END; WriteByte: PROC [x: CARDINAL, y: ControllerRegister] = BEGIN byteOffset: CARDINAL = y.ORD; IF (byteOffset MOD 2) # 0 THEN DicentraInputOutput.OutputByteEven[x, baseAddress+byteOffset/2] ELSE DicentraInputOutput.OutputByteOdd[x, baseAddress+byteOffset/2]; END; cv: LONG POINTER TO CONDITION; InitVersatecDMA[]; END.