-- 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.