GPIBImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Last edited by Neil Gunther, November 5, 1985 4:55:51 pm PST
Last Edited by: Gasbarro April 24, 1986 11:37:59 am PST
Tim Diebert: September 11, 1986 12:18:30 pm PDT
DIRECTORY
Ascii, Basics, GPIB, Process, RefText, Rope, XBus;
GPIBImpl: CEDAR MONITOR
IMPORTS Basics, Process, RefText, Rope, XBus
EXPORTS GPIB = BEGIN
OPEN Basics, Rope;
Globals for Level 1
controller: GPIB.DeviceAddr ← 0;
Globals for Level 2 (GPIB-796P interface)
statusWord: WORD ← 0000H;
BusEND: WORD = LOOPHOLE[BITSHIFT[1, 13]];
SRQI: WORD = LOOPHOLE[BITSHIFT[1, 12]];
GPIBBaseAddr: LONG POINTER = LOOPHOLE[LONG[8000H]]; -- current setting for Multibus
monitorStatusWord: BOOLTRUE; --for debugging
swRegister: WORD ← statusWord; --for debugging
maxBytes: CARDINAL = LAST[CARDINAL]/4;
smallBuf: NAT = 16;
bigBuf: NAT = GPIB.maxReadBuffer;
*** Level 1: Implementation of GPIB.mesa ***
InitializeController: PUBLIC PROC RETURNS [open: BOOL] = {
[] ← Init[]; open ← TRUE;
};
FinalizeController: PUBLIC PROC = {
SetIdle[]
};
SRQAsserted: PUBLIC PROC RETURNS [asserted: BOOL] = {
asserted ← FALSE;
IF swRegister # 0 THEN {
swRegister ← 0H;
asserted ← TRUE;
};
};
Universal commands (all devices whether adred or not)
Command: PUBLIC PROC [sendMsg: Rope.ROPE] = {
sendBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
sendBuffer ← RefText.AppendRope[sendBuffer, sendMsg];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
DevicesClear: PUBLIC PROC = {
[] ← LCmd[LIST[GPIB.devicesClear, GPIB.UnListen]]};
GoToLocal: PUBLIC PROC = {
[] ← LCmd[LIST[GPIB.goToLocal, GPIB.UnListen]]};
GroupExecuteTrigger: PUBLIC PROC = {
[] ← LCmd[LIST[GPIB.groupExecuteTrigger, GPIB.UnListen]]};
InterfaceClear: PUBLIC PROC = {[] ← Clear[]};
LocalLockout: PUBLIC PROC = {
[] ← LCmd[LIST[GPIB.localLockout, GPIB.UnListen]]};
RemoteEnable: PUBLIC PROC = {[] ← SetRemote[TRUE]};
Selected Device Commands (only those devices adred)
SelectedDeviceClear: PUBLIC PROC [device: GPIB.DeviceAddr]= {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.selectedDeviceClear, GPIB.UnListen]]};
SelectedGoToLocal: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.goToLocal, GPIB.UnListen]]};
SelectedExecuteTrigger: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device],GPIB.groupExecuteTrigger,GPIB.UnListen]]};
SelectedGroupEnableTrigger: PUBLIC PROC [device: GPIB.DeviceAddr] = {ERROR};
SelectedRemoteEnable: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← SetRemote[TRUE];
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GetTAD[device], GPIB.UnListen]];
};
Explicit Polling Routines
ParallelPollConfigure: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GPIB.parallelPollConfigure, GPIB.parallelPollEnable, GPIB.UnListen]];
};
ParallelPollUnconfigure: PUBLIC PROC = {
[] ← LCmd[LIST[GPIB.UnListen, GPIB.parallelPollConfigure, GPIB.parallelPollDisable, GPIB.UnListen]];
};
SelectedParallelPollConfigure: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.parallelPollConfigure, GPIB.parallelPollEnable, GPIB.UnListen]];
};
SelectedParallelPollUnconfigure: PUBLIC PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.parallelPollConfigure, GPIB.parallelPollDisable, GPIB.UnListen]];
};
Read Specific Devices
PollDevice: PUBLIC PROC [device: GPIB.DeviceAddr, labels: GPIB.SRQLabels] = {ERROR};
SelectedReadSerialPoll: PUBLIC PROC [device: GPIB.DeviceAddr] RETURNS [statusByte: CHAR] = {
[] ← LCmd[LIST[GPIB.UnListen, GPIB.serialPollEnable, GetTAD[device], GetLAD[controller]]];
[statusByte, ] ← DataByteRead[];
[] ← LCmd[LIST[GPIB.serialPollDisable, GPIB.UnTalk]];
};
ReadStatusByte: PUBLIC PROC [device: GPIB.DeviceAddr] RETURNS [char: CHAR] = {
[] ← LCmd[LIST[GPIB.UnListen, GetTAD[device], GetLAD[controller]]];
[char, ] ← DataByteRead[! ABORTED => CONTINUE];
[] ← LCmd[LIST[GPIB.UnTalk]];
}; 
ReadDevice: PUBLIC PROC [device: GPIB.DeviceAddr, terminator: GPIB.Terminator ← EOI] RETURNS [recvMsg: Rope.ROPE, end: BOOL] = {
for efficiency, don't do any allocates here...
sendBuffer: REF TEXT ← RefText.ObtainScratch[smallBuf];
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
sendBuffer ← RefText.AppendChar[sendBuffer, GetTAD[device]];
sendBuffer ← RefText.AppendChar[sendBuffer, GetLAD[controller]];
[] ← Cmd[sendBuffer];
[recvMsg, , end] ← DataRead[terminator ! ABORTED => CONTINUE];
sendBuffer.length ← 0;
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnTalk];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
ReadOnInterrupt: PUBLIC PROC [device: GPIB.DeviceAddr, recvMsg: Rope.ROPE, labels: GPIB.SRQLabels] = {ERROR};
WriteDevice: PUBLIC PROC [device: GPIB.DeviceAddr, sendMsg: Rope.ROPE] = {
for efficiency, don't do do any allocates here...
sendBuffer: REF TEXT ← RefText.ObtainScratch[smallBuf];
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
sendBuffer ← RefText.AppendChar[sendBuffer, GetLAD[device]];
sendBuffer ← RefText.AppendChar[sendBuffer, GetTAD[controller]];
[] ← Cmd[sendBuffer];
[] ← DataWrite[sendMsg ! ABORTED => CONTINUE];
sendBuffer.length ← 0;
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
dev: GPIB.DeviceAddr;
buffer: Rope.ROPENIL;
bufferEmptyCV, bufferFullCV: CONDITION;
bufferEmpty: BOOLTRUE;
WriteDeviceBuffered: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr, sendMsg: Rope.ROPE, hold: BOOL] = {
ENABLE UNWIND => NULL;
UNTIL bufferEmpty DO
WAIT bufferEmptyCV;
ENDLOOP;
dev ← device;
buffer ← sendMsg;
bufferEmpty ← FALSE;
BROADCAST bufferFullCV;
IF hold THEN UNTIL bufferEmpty DO
WAIT bufferEmptyCV;
ENDLOOP;
};
BufferToDevice: ENTRY PROC = {
ENABLE UNWIND => NULL;
open: REF TEXTNEW[TEXT[smallBuf]];
close: REF TEXTNEW[TEXT[smallBuf]];
close ← RefText.AppendChar[close, GPIB.UnListen];
DO
WHILE bufferEmpty DO
WAIT bufferFullCV;
ENDLOOP;
open.length ← 0;
open ← RefText.AppendChar[open, GPIB.UnListen];
open ← RefText.AppendChar[open, GetLAD[dev]];
open ← RefText.AppendChar[open, GetTAD[controller]];
[] ← Cmd[open];
[] ← DataWrite[buffer ! ABORTED => CONTINUE];
[] ← Cmd[close];
bufferEmpty ← TRUE;
BROADCAST bufferEmptyCV;
ENDLOOP;
};
Printer Functions (see Tim Diebert)
WriteDeviceInitial: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr, sendMsg: Rope.ROPE] = BEGIN
ENABLE UNWIND => NULL;
sendBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
sendBuffer ← RefText.AppendChar[sendBuffer, GetLAD[device]];
sendBuffer ← RefText.AppendChar[sendBuffer, GetTAD[controller]];
[] ← Cmd[sendBuffer];
sendBuffer.length ← 0;
[] ← DataWrite[sendMsg, TRUE, FALSE ! ABORTED => CONTINUE];
RefText.ReleaseScratch[sendBuffer];
END;
WriteDeviceContinued: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr, sendMsg: Rope.ROPE,
last: BOOL] = BEGIN
ENABLE UNWIND => NULL;
sendBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
[] ← DataWrite[sendMsg, FALSE, last ! ABORTED => CONTINUE];
RefText.ReleaseScratch[sendBuffer];
END;
WriteDeviceBlock: PUBLIC ENTRY UNSAFE PROC [device: GPIB.DeviceAddr,
lp: LONG POINTER, quadWordCnt: CARDINAL, last: BOOL] = TRUSTED BEGIN
OPEN Basics;
ENABLE UNWIND => NULL;
dataWord: MACHINE DEPENDENT RECORD [a,b: CHAR] ← LOOPHOLE [lp^];
IF quadWordCnt < 1 THEN quadWordCnt ← 1;
FOR i: CARDINAL IN [0 .. quadWordCnt-1) DO
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
ENDLOOP;
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
lp ← lp + 1;
dataWord ← LOOPHOLE [lp^];
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.a, CARDINAL]];
IF last THEN WriteReg[auxmr, sendEOI]; -- EOI with last byte
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[dataWord.b, CARDINAL]];
END;
WriteDMABlock: PUBLIC UNSAFE PROC [device: GPIB.DeviceAddr,
multiBusAddress: LONG POINTER TO WORD, -- For Lupine --
byteCnt: CARDINAL, last: BOOL] = TRUSTED BEGIN
i: INTEGER; bp: Basics.BytePair; md: MACHINE DEPENDENT RECORD [b1, b0, b3, b2: BYTE];
i ← 0 - LOOPHOLE[byteCnt, INTEGER];
byteCnt ← LOOPHOLE[i, CARDINAL];
bp ← LOOPHOLE[byteCnt];
WriteReg[bcr0, LOOPHOLE[bp.low]];
WriteReg[bcr1, LOOPHOLE[bp.high]];
md ← LOOPHOLE[multiBusAddress];
WriteReg[acr0, LOOPHOLE[md.b0]];
WriteReg[acr1, LOOPHOLE[md.b1]];
WriteReg[acr2, LOOPHOLE[md.b2]];
IF last THEN WriteReg[ccfr, sendEOI];
WriteReg[imr1, LOOPHOLE[0]];
WriteReg[cr1, LOOPHOLE[0Bh]]; -- ~MIE, *Burst, ~CBRE, SC, 22.4 to 25.6 timeout
WriteReg[imr2, LOOPHOLE[20H]]; -- DMAO
WriteReg[cr0, LOOPHOLE[(IF last THEN 052H ELSE 012H)]];
WriteReg[cr0, LOOPHOLE[(IF last THEN 053H ELSE 013H)]];
END;
ReadDeviceInitial: PUBLIC ENTRY PROC [ device: GPIB.DeviceAddr] = BEGIN
sendBuffer: REF TEXT ← RefText.ObtainScratch[smallBuf];
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
sendBuffer ← RefText.AppendChar[sendBuffer, GetTAD[device]];
sendBuffer ← RefText.AppendChar[sendBuffer, GetLAD[controller]];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
WriteReg[auxmr, goToStandby]; -- if controller active state, go to standby
[] ← ReadRegL[sr];
END;
ReadDMABlock: PUBLIC UNSAFE PROC [device: GPIB.DeviceAddr,
multiBusAddress: LONG POINTER TO WORD, -- For Lupine --
byteCnt: CARDINAL, last: BOOLFALSE] = TRUSTED BEGIN
i: INTEGER; bp: Basics.BytePair; md: MACHINE DEPENDENT RECORD [b1, b0, b3, b2: BYTE];
i ← 0 - LOOPHOLE[byteCnt, INTEGER];
byteCnt ← LOOPHOLE[i, CARDINAL];
bp ← LOOPHOLE[byteCnt];
WriteReg[bcr0, LOOPHOLE[bp.low]];
WriteReg[bcr1, LOOPHOLE[bp.high]];
md ← LOOPHOLE[multiBusAddress];
WriteReg[acr0, LOOPHOLE[md.b0]];
WriteReg[acr1, LOOPHOLE[md.b1]];
WriteReg[acr2, LOOPHOLE[md.b2]];
IF last THEN WriteReg[ccfr, sendEOI];
WriteReg[imr1, LOOPHOLE[10H]]; -- Setup as listener
WriteReg[cr1, LOOPHOLE[4Bh]]; -- ~MIE, Burst, ~CBRE, SC, 22.4 to 25.6 timeout
WriteReg[imr2, LOOPHOLE[10H]]; -- DMAI
WriteReg[cr0, LOOPHOLE[02H]]; -- DMA en
WriteReg[cr0, LOOPHOLE[03H]]; -- GO
END;
ReadDMADone: PUBLIC PROC [device: GPIB.DeviceAddr] = BEGIN
sendBuffer: REF TEXT ← RefText.ObtainScratch[smallBuf];
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnListen];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
END;
CheckDMADone: PUBLIC PROC RETURNS [BOOL] = BEGIN
foo: CARDINAL ← ReadRegL[sr];
foo ← Basics.BITAND[foo, 80h];
Process.CheckForAbort[];
RETURN [foo # 0];
END;
Private Procedures
GetLAD: PRIVATE PROC [device: GPIB.DeviceAddr] RETURNS [CHAR] = {
IF device > 30 THEN ERROR;
RETURN [LOOPHOLE[device+32]]; -- ASCII Listen adr
};
GetTAD: PRIVATE PROC [device: GPIB.DeviceAddr] RETURNS [CHAR] = {
IF device > 30 THEN ERROR;
RETURN [LOOPHOLE[device+64]]; -- ASCII Talk adr
};
BufferSW: PRIVATE PROC = {
IF statusWord # 0 THEN swRegister ← statusWord;
};
*** Level 2: Board-specific Procedures ***
   NEC 7210 M a s k s a n d R e g i s t e r s
Auxiliary Controller CommandsNat. Instr. mnemonic
powerOn:   CHAR = 000C;  -- AUX-PON
chipReset:   CHAR = 002C; -- AUX—CR
sendEOI:   CHAR = 006C; -- AUX—SEOI
takeAsynchControl: CHAR = 021C; -- AUX—TCA
goToStandby:  CHAR = 020C; -- AUX—GTS
executeParaPoll:  CHAR = 035C;  -- AUX-EPP
setIFC:   CHAR = 036C; -- AUX—SIFC
clearIFC:   CHAR = 026C; -- AUX—CIFC
setREN:   CHAR = 037C;  -- AUX-SREN
clearREN:   CHAR = 027C; -- AUX—CREN
Control Masks for Hidden RegistersNat. Instr. mnemonic
ICR:   CARDINAL = 000040B;  -- Internal Counter Register
PPR:   CARDINAL = 000140B; -- Parallel Poll Register
AUXRA:   CARDINAL = 000200B; -- Aux Register A
AUXRB:  CARDINAL = 000240B; -- Aux Register B
AUXRE:   CARDINAL = 000300B;  -- Aux Register E
Controller Register DefinitionsNat. Instr. mnemonic
WRegister: TYPE = { -- WriteOnly
cdro,   -- cdor
imr1,   -- imr1
imr2,  -- imr2
spmr,  -- spmr
admr,  -- admr
auxmr,  -- auxmr
adr,  -- adr
eosr,  -- eosr
bcr0,  -- bcr 0
bcr1,  -- bcr hi
cr0,  -- cr0
ccfr,  -- ccfr
acr0,  -- acr0
acr1,  -- acr1
acr2,  -- acr2
cr1  -- cr1
};
RRegister: TYPE = { -- ReadOnly
dir,   -- dir
isr1,   -- isr1
isr2,  -- isr2
spsr,  -- spsr
adsr,  -- adsr
cptr,  -- cptr
adr0,  -- adr0
adr1,  -- adr1
bcr0,  -- bcr lo
bcr1,  -- bcr hi
sr,  -- SR
ccfr  -- ccfr
};
mask: RECORD [
DI:  CARDINALBITSHIFT[1, 0], -- Data In
D0:  CARDINALBITSHIFT[1, 1], -- Data Out
BusEND: CARDINALBITSHIFT[1, 4], -- End
CO:  CARDINALBITSHIFT[1, 3], -- Command Output
SRQI:  CARDINALBITSHIFT[1, 6], -- Service Request Input 
DMAI:  CARDINALBITSHIFT[1, 4], -- DMA Input Enable
DMAO:  CARDINALBITSHIFT[1, 5], -- DMA Output Enable
ADMO: CARDINALBITSHIFT[1, 0], -- Addr Mode bit 0
TRMO:  CARDINALBITSHIFT[1, 4], -- Transmit/Receive Mode bit 0
TRMI:  CARDINALBITSHIFT[1, 5], -- Transmit/Receive Mode bit 1 
DL:  CARDINALBITSHIFT[1, 5], -- Disable Listener
DT:  CARDINALBITSHIFT[1, 6], -- Disable Talker
ARS: CARDINALBITSHIFT[1, 7], -- Addr Reg Select
PPU:  CARDINALBITSHIFT[1, 4] -- Para Poll Unconfigure
]; 
G P I B - 7 9 6 P F u n c t i o n s
Init: PROC [] RETURNS [WORD] = {
WriteReg[auxmr, chipReset];   -- NEC 7210
[] ← ReadReg[cptr]; -- clear registers by reading & trashing result
[] ← ReadReg[isr1];
[] ← ReadReg[isr2];
WriteReg[imr1, 0C]; -- disable all interrupts
WriteReg[imr2, 0C];
WriteReg[spmr, 0C];
WriteReg[adr, 0C];    -- set 796P TAD = 100B+100B (controller)
disable secondary adring
WriteRegL[adr, BITOR[mask.ARS, BITOR[mask.DT, mask.DL]]];
WriteRegL[admr, BITOR[mask.TRMI, BITOR[mask.TRMO, mask.ADMO]]];
WriteReg[eosr, 0C];
WriteReg[auxmr, clearIFC]; -- and by default enable system controller
WriteRegL[auxmr, BITOR[ICR, 5]]; -- set internal counter register N = 5
WriteRegL[auxmr, BITOR[PPR, mask.PPU]]; -- parallel poll unconfigure
WriteRegL[auxmr, BITOR[AUXRA, 0]];
WriteRegL[auxmr, BITOR[AUXRB, 0]];
WriteRegL[auxmr, BITOR[AUXRE, 0]];
WriteReg[auxmr, powerOn]; -- put chip online
IF monitorStatusWord THEN {
statusWord ← IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0;
BufferSW[];
};
RETURN[statusWord];
};
ResetDMA: PROC = BEGIN
WriteReg[cr0, LOOPHOLE[0]];
END;
SetIdle: PROC = {
return controller to idle state or somesuch.
WriteReg[auxmr, chipReset];  
[] ← ReadReg[cptr]; -- clear registers by reading & trashing result
[] ← ReadReg[isr1];
[] ← ReadReg[isr2];
WriteReg[imr1, 0C]; -- disable all interrupts
WriteReg[imr2, 0C];
WriteReg[spmr, 0C];
WriteReg[adr, 0C];    -- set 796P TAD = 100B+100B (controller)
disable secondary adring
WriteRegL[adr, BITOR[mask.ARS, BITOR[mask.DT, mask.DL]]];
WriteRegL[admr, BITOR[mask.TRMI, BITOR[mask.TRMO, mask.ADMO]]];
WriteReg[eosr, 0C];
WriteReg[auxmr, clearIFC]; -- and by default enable system controller
WriteRegL[auxmr, BITOR[ICR, 5]]; -- set internal counter register N = 5
WriteRegL[auxmr, BITOR[PPR, mask.PPU]]; -- parallel poll unconfigure
WriteRegL[auxmr, BITOR[AUXRA, 0]];
WriteRegL[auxmr, BITOR[AUXRB, 0]];
WriteRegL[auxmr, BITOR[AUXRE, 0]];
};
LCmd: PROC [chars: LIST OF CHAR] RETURNS [w: WORD] = {
sendBuffer: REF TEXT ← RefText.ObtainScratch[smallBuf];
FOR l: LIST OF CHAR ← chars, l.rest WHILE l#NIL DO
sendBuffer ← RefText.AppendChar[sendBuffer, l.first];
ENDLOOP;
w ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
Cmd: PROC [sendBuffer: REF TEXT] RETURNS [WORD] = {
ships the global "sendBuffer"
s: CARDINAL ← 0;
WriteReg[auxmr, takeAsynchControl]; -- if on standby, go to controller active state
FOR i: NAT IN [0..sendBuffer.length) DO
s ← BITAND[s, BITNOT[mask.CO]]; -- clear saved copy of Command Output
WriteReg[cdro, sendBuffer.text[i]]; -- output command
WHILE BITAND[(s ← BITOR[s, ReadRegL[isr2]]), mask.CO] = 0 DO
wait for Command Output flag BITOR-ed to preserve SRQI
Process.CheckForAbort[]; -- escape route
ENDLOOP;
ENDLOOP;
IF monitorStatusWord THEN {
statusWord ← IF BITAND[s, mask.SRQI] # 0 THEN SRQI ELSE 0;
BufferSW[];
};
RETURN[statusWord];
};
DataRead: PROC [terminateOn: GPIB.Terminator] RETURNS [ROPE, WORD, BOOL] = {
Read unspecified number of bytes of data from the GPIB-796P interface into buffer. In addition to I/O complete, the read operation terminates on detection of EOI. Prior to beginning the read the interface is placed in the controller standby state. No handshake holdoffs are used so care must be exercised when taking control (i.e., asserting ATN) following DataRead. Prior to calling DataRead, the intended devices as well as the interface board itself must be adred by calling Cmd.
recBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
s: CARDINAL ← 0;
rope: Rope.ROPENIL;
end: BOOLFALSE;
byteCount: CARDINAL ← 0;
[] ← ReadReg[dir]; -- krock to clear dir reg
WriteReg[auxmr, goToStandby]; -- if controller active state, go to standby
DO -- read unspecified number of bytes
Process.CheckForAbort[];
WHILE BITAND[(s ← ReadRegL[isr1]), mask.DI] = 0 DO
wait for Data In flag
Process.CheckForAbort[];
ENDLOOP;
recBuffer ← RefText.AppendChar[recBuffer, ReadReg[dir]]; -- store byte
SELECT terminateOn FROM
CR => IF recBuffer[recBuffer.length-1] = '\n THEN {end ← TRUE; EXIT};
LF => IF recBuffer[recBuffer.length-1] = '\l THEN {end ← TRUE; EXIT}; -- IEEE 728 string terminator
ENDCASE => IF BITAND[s, mask.BusEND] # 0 THEN {end ← TRUE; EXIT}; -- EOI
IF byteCount > maxBytes THEN {end ← FALSE; EXIT};
IF recBuffer.length = recBuffer.maxLength THEN {
rope ← Rope.Concat[rope, Rope.FromRefText[recBuffer]];
recBuffer.length ← 0;
};
byteCount ← byteCount+1;
ENDLOOP;
rope ← Rope.Concat[rope, Rope.FromRefText[recBuffer]];
RefText.ReleaseScratch[recBuffer];
IF monitorStatusWord THEN {
statusWord ← IF BITAND[s, mask.BusEND] # 0 THEN BusEND ELSE 0;
statusWord ← BITOR[statusWord, IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0];
BufferSW[];
};
RETURN[rope, statusWord, end];
};
DataByteRead: PROC [] RETURNS [c: CHAR, w: WORD] = {
Read one byte of data from the GPIB-796P interface into buffer. In addition to I/O complete, the read operation terminates on detection of EOI. Prior to beginning the read the interface is placed in the controller standby state. No handshake holdoffs are used so care must be exercised when taking control (i.e., asserting ATN) following DataRead. Prior to calling DataRead, the intended devices as well as the interface board itself must be adred by calling Cmd.
s: CARDINAL ← 0;
[] ← ReadReg[dir]; -- krock to clear dir reg
WriteReg[auxmr, goToStandby]; -- if controller active state, go to standby
Process.CheckForAbort[];
WHILE BITAND[(s ← ReadRegL[isr1]), mask.DI] = 0 DO
wait for Data In flag
Process.CheckForAbort[];
ENDLOOP;
c ← ReadReg[dir]; -- store byte
IF monitorStatusWord THEN {
statusWord ← IF BITAND[s, mask.BusEND] # 0 THEN BusEND ELSE 0;
statusWord ← BITOR[statusWord, IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0];
BufferSW[];
};
RETURN[c, statusWord];
};
mBusCtl: POINTER = LOOPHOLE[2];
lBusOutData: POINTER = LOOPHOLE[2];
lBusInData: POINTER = LOOPHOLE[2];
mBusAddr: POINTER = LOOPHOLE[3];
lBusAddr: POINTER = LOOPHOLE[3];
DataWrite: PROC [buffer: ROPE, init, last: BOOLTRUE] RETURNS [WORD] = {
Write data bytes from buffer to the GPIB-796P. The write operation terminates only on I/O complete. By default, EOI is always sent along with the last byte. Prior to beginning the write the interface is placed in the controller standby state. Prior to calling DataWrite, the intended devices, as well as the interface board itself, must be adred by calling Cmd.
IF init THEN WriteReg[auxmr, goToStandby]; -- if controller active state, go to standby (data mode)
buffer ← Rope.InlineFlatten[buffer];
FOR i: INT IN [0..Length[buffer]) DO
XBus.IOWrite[GPIBBaseAddr, LOOPHOLE[Rope.InlineFetch[buffer, i]]];
DO
mumble: WORD ← XBus.IORead[GPIBBaseAddr + 1];
IF BITAND[mumble, mask.D0] # 0 THEN EXIT;
ENDLOOP;
ENDLOOP;  
IF last THEN WriteReg[auxmr, sendEOI]; -- EOI with last byte
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
Clear: PROC [] RETURNS [WORD] = {
Send IFC for at least 100 microseconds(4 ticks). Clear must be called prior to the first call to Cmd in order to initialize the bus and enable the interface to leave the controller idle state.
WriteReg[auxmr, setIFC];  
Process.Pause[ticks: 10];    -- 40 ticks = 1mS
WriteReg[auxmr, clearIFC];
IF monitorStatusWord THEN {  
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetRemote: PROC [set: BOOL] RETURNS [WORD] = {
WriteReg[auxmr, (IF set THEN setREN ELSE clearREN)];
IF monitorStatusWord THEN {  
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetStandby: PROC [] RETURNS [WORD] = {
Go to the controller standby state (Data mode) from the controller active state, i.e., deassert ATN.
WriteReg[auxmr, goToStandby];
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetCACS: PROC [] RETURNS [WORD] = {
Return to the controller active state (Command mode) from the controller standby state, i.e., assert ATN. Note that in order to enter the controller active state from the controller idle state, Clear must be called.
WriteReg[auxmr, takeAsynchControl];
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
Wait: PROC [for: WORD] = {
Check or wait for a GPIB event to occur. The mask argument is a bit vector corresponding to the status bit vector. It has a bit set for each condition which can terminate the wait. If the mask is 0 then no condition is waited on and the current status is simply returned. Note that since the hardware SRQI bit is volatile it will only be reported once for each occurrence of SRQ. If another function has returned the SRQI status bit, then a call to Wait with a mask containing SRQI will never return.
WHILE (BITAND[GetStatus[], for] = 0) DO
IF for = 0 THEN EXIT;
Process.CheckForAbort[];
ENDLOOP;
};
GetStatus: PROC RETURNS [WORD] = {
Update GPIB status information.
RETURN[statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI]#0 THEN SRQI ELSE 0)];
};
GetParaPoll: PROC [] RETURNS [ROPE, WORD] = {
Conduct a parallel poll and return the byte in buf. Prior to conducting the poll the interface is placed in the controller active state.
c: CHAR;
WriteReg[auxmr, takeAsynchControl]; -- if standby, go to controller active state
WriteReg[auxmr, executeParaPoll];
c ← ReadReg[cptr];     -- store the response byte
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[isr2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[Rope.FromChar[c], statusWord];
};
P r i v a t e R e g i s t e r O p e r a t i o n s
ReadReg: PRIVATE PROC [register: RRegister] RETURNS [char: CHAR] = INLINE {
addr: NATSELECT register FROM
dir  => 0,
isr1 => 1,
isr2 => 2,
spsr => 3,
adsr => 4,
cptr => 5, 
adr0  => 6,
adr1  => 7,
bcr0  => 8,
bcr1  => 9,
sr  => 0Ah,
ccfr => 0Bh,
ENDCASE => ERROR;
word: WORD ← XBus.IORead[LOOPHOLE[GPIBBaseAddr+addr]];
char ← LOOPHOLE[LowByte[word]];
};
ReadRegL: PRIVATE PROC [register: RRegister] RETURNS [word: CARDINAL] = INLINE {
addr: NATSELECT register FROM
dir  => 0,
isr1 => 1,
isr2 => 2,
spsr => 3,
adsr => 4,
cptr => 5, 
adr0  => 6,
adr1  => 7,
bcr0  => 8,
bcr1  => 9,
sr  => 0Ah,
ccfr => 0Bh,
ENDCASE => ERROR;
word ← XBus.IORead[LOOPHOLE[GPIBBaseAddr+addr]];
};
WriteReg: PRIVATE PROC [register: WRegister, dataByte: CHAR ] = INLINE {
addr: NATSELECT register FROM
cdro  => 0,
imr1  => 1,
imr2  => 2,
spmr => 3,
admr => 4,
auxmr  => 5,
adr  => 6,
eosr  => 7,
bcr0  => 8,
bcr1  => 9,
cr0  => 0Ah,
ccfr => 0Bh,
acr0  => 0Ch,
acr1  => 0Dh,
acr2  => 0Eh,
cr1  => 0Fh,
ENDCASE => ERROR;
XBus.IOWrite[LOOPHOLE[GPIBBaseAddr+addr], LOOPHOLE[dataByte]];
};
WriteRegL: PRIVATE PROC [register: WRegister, dataWord: CARDINAL ] = INLINE {
addr: NATSELECT register FROM
cdro  => 0,
imr1  => 1,
imr2  => 2,
spmr => 3,
admr => 4,
auxmr  => 5,
adr  => 6,
eosr  => 7,
bcr0  => 8,
bcr1  => 9,
cr0  => 0Ah,
ccfr => 0Bh,
acr0  => 0Ch,
acr1  => 0Dh,
acr2  => 0Eh,
cr1  => 0Fh,
ENDCASE => ERROR;
XBus.IOWrite[LOOPHOLE[GPIBBaseAddr+addr], dataWord];
};
Initialization
TRUSTED {Process.Detach[FORK BufferToDevice[]]};
END... of GPIBImpl.mesa