-- ColorVersatecDriverImpl.mesa -- Jim Gasbarro 24-Feb-84 18:43:30 DIRECTORY ColorVersatecDriver, ColorVersatecUtils, DicentraInputOutput, Inline, OthelloDefs, Process; ColorVersatecDriverImpl: MONITOR IMPORTS ColorVersatecUtils, DicentraInputOutput, Inline, OthelloDefs, Process 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: PROC [wordCount: CARDINAL, hyperOffset: LONG CARDINAL] = BEGIN 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]; WHILE DMABusy[] DO ENDLOOP; 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: PROC [] RETURNS [BOOLEAN] = BEGIN -- has paper and is on line bits: CARDINAL _ ReadByte[versatecControlStatus]; RETURN[Inline.BITAND[bits, isOK] # 0]; END; InitVersatecDMA: PROC [] = BEGIN WHILE NOT VersatecIsOK [] DO ENDLOOP; -- 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]; END; VersatecInitialCheckout: PUBLIC PROC [] = BEGIN WHILE NOT VersatecIsOK[] DO OthelloDefs.WriteLine["Versatec is Offline"]; Process.Pause[Process.SecondsToTicks[2]]; ENDLOOP; InitVersatecDMA[]; 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; InitVersatecDMA[]; END.