NatInstrGPIBDriver.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by Neil Gunther, May 17, 1985 11:22:31 am PDT
Last edited by Neil Gunther, November 5, 1985 4:55:51 pm PST
Last Edited by: Gasbarro January 17, 1986 12:22:27 pm PST
This module implements the NATIONAL INSTRUMENTS GPIB-796P interface functions for a D-machine possessing a Multibus adaptor. This implementation comprises 2 parts. The upper level PROCs conform to the procedural interface specified in GPIB.mesa; the lower level PROCs implement the board-specific calls. All GPIB drivers should conform to this organization.
For more information about the National Instruments GPIB-768P controller contact National Instruments, 12109 Technology Boulevard, Austin TX 78727 (800)531-5066.
The following is paraphrased from the original National Instruments documentation.
These procedures support synchronous, non-interrupt, non-DMA I/O, for a single interface board which is always both the system controller and the controller in charge. All procedures return the subset of the standard GPIB status bit vector consisting of just the SRQI and BusEND status bits.

The result of the last call is also available in the global variable, statusWord. If it was an I/O operation the actual count transferred is available in the global variable, byteCount. Before any other call is made InitializeController[] must be called to initialize the GPIB interface. At level 2, prior to calling DataRead[] or DataWrite[] the appropriate devices, including the interface board, must be addressed by calling Cmd[] with the proper addressing codes.
DIRECTORY
Ascii, Basics, GPIB, Process, RefText, Rope, XBus;
NatInstrGPIBDriver: 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
smallBuf: NAT = 16;
bigBuf: NAT = GPIB.maxReadBuffer;
*** Level 1: Implementation of GPIB.mesa ***
InitializeController: PUBLIC ENTRY PROC RETURNS [open: BOOL] = {[]←Init[]; open←TRUE};
FinalizeController: PUBLIC ENTRY PROC = {SetIdle[]};
SRQAsserted: PUBLIC ENTRY PROC RETURNS [asserted: BOOL] = {
asserted ← FALSE;
IF swRegister # 0 THEN {
swRegister ← 0H;
asserted ← TRUE;
};
};
Universal commands (all devices whether addressed or not)
Command: PUBLIC ENTRY PROC [sendMsg: Rope.ROPE] = {
sendBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
sendBuffer ← RefText.AppendRope[sendBuffer, sendMsg];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
DevicesClear: PUBLIC ENTRY PROC = {
[] ← LCmd[LIST[GPIB.devicesClear, GPIB.UnListen]]};
GoToLocal: PUBLIC ENTRY PROC = {
[] ← LCmd[LIST[GPIB.goToLocal, GPIB.UnListen]]};
GroupExecuteTrigger: PUBLIC ENTRY PROC = {
[] ← LCmd[LIST[GPIB.groupExecuteTrigger, GPIB.UnListen]]};
InterfaceClear: PUBLIC ENTRY PROC = {[] ← Clear[]};
LocalLockout: PUBLIC ENTRY PROC = {
[] ← LCmd[LIST[GPIB.localLockout, GPIB.UnListen]]};
RemoteEnable: PUBLIC ENTRY PROC = {[] ← SetRemote[TRUE]};
Selected Device Commands (only those devices addressed)
SelectedDeviceClear: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr]= {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.selectedDeviceClear, GPIB.UnListen]]};
SelectedGoToLocal: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.goToLocal, GPIB.UnListen]]};
SelectedExecuteTrigger: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device],GPIB.groupExecuteTrigger,GPIB.UnListen]]};
SelectedRemoteEnable: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← SetRemote[TRUE];
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GetTAD[device], GPIB.UnListen]];
};
Explicit Polling Routines
ParallelPollConfigure: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GPIB.parallelPollConfigure, GPIB.parallelPollEnable, GPIB.UnListen]];
};
ParallelPollUnconfigure: PUBLIC ENTRY PROC = {
[] ← LCmd[LIST[GPIB.UnListen, GPIB.parallelPollConfigure, GPIB.parallelPollDisable, GPIB.UnListen]];
};
SelectedParallelPollConfigure: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.parallelPollConfigure, GPIB.parallelPollEnable, GPIB.UnListen]];
};
SelectedParallelPollUnconfigure: PUBLIC ENTRY PROC [device: GPIB.DeviceAddr] = {
[] ← LCmd[LIST[GPIB.UnListen, GetLAD[device], GPIB.parallelPollConfigure, GPIB.parallelPollDisable, GPIB.UnListen]];
};
Read Specific Devices
SelectedReadSerialPoll: PUBLIC ENTRY 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 ENTRY 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 ENTRY PROC [device: GPIB.DeviceAddr, terminator: GPIB.Terminator ← EOI] RETURNS [recvMsg: Rope.ROPE] = {
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, ] ← DataRead[terminator ! ABORTED => CONTINUE];
sendBuffer.length ← 0;
sendBuffer ← RefText.AppendChar[sendBuffer, GPIB.UnTalk];
[] ← Cmd[sendBuffer];
RefText.ReleaseScratch[sendBuffer];
};
WriteDevice: PUBLIC ENTRY 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];
};
Private Procedures
GetLAD: PRIVATE INTERNAL PROC [device: GPIB.DeviceAddr] RETURNS [CHAR] = {
IF device > 30 THEN ERROR;
RETURN [LOOPHOLE[device+32]]; -- ASCII Listen address
};
GetTAD: PRIVATE INTERNAL PROC [device: GPIB.DeviceAddr] RETURNS [CHAR] = {
IF device > 30 THEN ERROR;
RETURN [LOOPHOLE[device+64]]; -- ASCII Talk address
};
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 Commands    Nat. 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 Registers   Nat. 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 Definitions     Nat. Instr. mnemonic
WRegister: TYPE = { -- WriteOnly
cmdDataOut,         -- cdor
intrptMask1,         -- imr1
intrptMask2,         -- imr2
serialPollMode,        -- spmr
addressMode,        -- admr
auxMode,          -- auxmr
address,          -- adr
endOfStr          -- eosr
};
RRegister: TYPE = { -- ReadOnly
dataIn,           -- dir
intrptStatus1,          -- isr1
intrptStatus2,         -- isr2
serialPollStatus,        -- spsr
addressStatus,        -- adsr
cmdPassThru,        -- cptr
address0,          -- adr0
address1          -- adr1
};
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: INTERNAL PROC [] RETURNS [WORD] = {
WriteReg[auxMode, chipReset];   -- NEC 7210
[] ← ReadReg[cmdPassThru]; -- clear registers by reading & trashing result
[] ← ReadReg[intrptStatus1];
[] ← ReadReg[intrptStatus2];
WriteReg[intrptMask1, 0C]; -- disable all interrupts
WriteReg[intrptMask2, 0C];
WriteReg[serialPollMode, 0C];
WriteReg[address, 0C];    -- set 796P TAD = 100B+100B (controller)
disable secondary addressing
WriteRegL[address, BITOR[mask.ARS, BITOR[mask.DT, mask.DL]]];
WriteRegL[addressMode, BITOR[mask.TRMI, BITOR[mask.TRMO, mask.ADMO]]];
WriteReg[endOfStr, 0C];
WriteReg[auxMode, clearIFC]; -- and by default enable system controller
WriteRegL[auxMode, BITOR[ICR, 5]]; -- set internal counter register N = 5
WriteRegL[auxMode, BITOR[PPR, mask.PPU]]; -- parallel poll unconfigure
WriteRegL[auxMode, BITOR[AUXRA, 0]];
WriteRegL[auxMode, BITOR[AUXRB, 0]];
WriteRegL[auxMode, BITOR[AUXRE, 0]];
WriteReg[auxMode, powerOn]; -- put chip online
IF monitorStatusWord THEN {
statusWord ← IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0;
BufferSW[];
};
RETURN[statusWord];
};
SetIdle: INTERNAL PROC = {
return controller to idle state or somesuch.
WriteReg[auxMode, chipReset];  
[] ← ReadReg[cmdPassThru]; -- clear registers by reading & trashing result
[] ← ReadReg[intrptStatus1];
[] ← ReadReg[intrptStatus2];
WriteReg[intrptMask1, 0C]; -- disable all interrupts
WriteReg[intrptMask2, 0C];
WriteReg[serialPollMode, 0C];
WriteReg[address, 0C];    -- set 796P TAD = 100B+100B (controller)
disable secondary addressing
WriteRegL[address, BITOR[mask.ARS, BITOR[mask.DT, mask.DL]]];
WriteRegL[addressMode, BITOR[mask.TRMI, BITOR[mask.TRMO, mask.ADMO]]];
WriteReg[endOfStr, 0C];
WriteReg[auxMode, clearIFC]; -- and by default enable system controller
WriteRegL[auxMode, BITOR[ICR, 5]]; -- set internal counter register N = 5
WriteRegL[auxMode, BITOR[PPR, mask.PPU]]; -- parallel poll unconfigure
WriteRegL[auxMode, BITOR[AUXRA, 0]];
WriteRegL[auxMode, BITOR[AUXRB, 0]];
WriteRegL[auxMode, BITOR[AUXRE, 0]];
};
LCmd: INTERNAL 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: INTERNAL PROC [sendBuffer: REF TEXT] RETURNS [WORD] = {
ships the global "sendBuffer"
s: CARDINAL ← 0;
WriteReg[auxMode, 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[cmdDataOut, sendBuffer.text[i]]; -- output command
WHILE BITAND[(s ← BITOR[s, ReadRegL[intrptStatus2]]), 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: INTERNAL PROC [terminateOn: GPIB.Terminator] RETURNS [ROPE, WORD] = {
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 addressed by calling Cmd.
recBuffer: REF TEXT ← RefText.ObtainScratch[bigBuf];
s: CARDINAL ← 0;
rope: Rope.ROPENIL;
[] ← ReadReg[dataIn]; -- krock to clear dataIn reg
WriteReg[auxMode, goToStandby]; -- if controller active state, go to standby
DO -- read unspecified number of bytes
Process.CheckForAbort[];
WHILE BITAND[(s ← ReadRegL[intrptStatus1]), mask.DI] = 0 DO
wait for Data In flag
Process.CheckForAbort[];
ENDLOOP;
recBuffer ← RefText.AppendChar[recBuffer, ReadReg[dataIn]]; -- store byte
SELECT terminateOn FROM
CR => IF recBuffer[recBuffer.length-1] = '\n THEN EXIT;
LF => IF recBuffer[recBuffer.length-1] = '\l THEN EXIT; -- IEEE 728 string terminator
ENDCASE => IF BITAND[s, mask.BusEND] # 0 THEN EXIT; -- EOI
IF recBuffer.length = recBuffer.maxLength THEN {
rope ← Rope.Concat[rope, Rope.FromRefText[recBuffer]];
recBuffer.length ← 0;
};
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[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0];
BufferSW[];
};
RETURN[rope, statusWord];
};
DataByteRead: INTERNAL 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 addressed by calling Cmd.
s: CARDINAL ← 0;
[] ← ReadReg[dataIn]; -- krock to clear dataIn reg
WriteReg[auxMode, goToStandby]; -- if controller active state, go to standby
Process.CheckForAbort[];
WHILE BITAND[(s ← ReadRegL[intrptStatus1]), mask.DI] = 0 DO
wait for Data In flag
Process.CheckForAbort[];
ENDLOOP;
c ← ReadReg[dataIn]; -- store byte
IF monitorStatusWord THEN {
statusWord ← IF BITAND[s, mask.BusEND] # 0 THEN BusEND ELSE 0;
statusWord ← BITOR[statusWord, IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0];
BufferSW[];
};
RETURN[c, statusWord];
};
DataWrite: INTERNAL PROC [buffer: ROPE] 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 addressed by calling Cmd.
WriteReg[auxMode, goToStandby]; -- if controller active state, go to standby (data mode)
buffer ← Rope.InlineFlatten[buffer];
FOR i: INT IN [0..Length[buffer]) DO
Process.CheckForAbort[];
WriteReg[cmdDataOut, Rope.InlineFetch[buffer, i]]; -- output byte
WHILE BITAND[ReadRegL[intrptStatus1], mask.D0] = 0 DO --wait for DataOut flag
Process.CheckForAbort[];
ENDLOOP;
REPEAT
FINISHED => WriteReg[auxMode, sendEOI]; -- EOI with last byte
ENDLOOP;  
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
Clear: INTERNAL 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[auxMode, setIFC];  
Process.Pause[ticks: 10];    -- 40 ticks = 1mS
WriteReg[auxMode, clearIFC];
IF monitorStatusWord THEN {  
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetRemote: INTERNAL PROC [set: BOOL] RETURNS [WORD] = {
WriteReg[auxMode, (IF set THEN setREN ELSE clearREN)];
IF monitorStatusWord THEN {  
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetStandby: INTERNAL PROC [] RETURNS [WORD] = {
Go to the controller standby state (Data mode) from the controller active state, i.e., deassert ATN.
WriteReg[auxMode, goToStandby];
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
SetCACS: INTERNAL 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[auxMode, takeAsynchControl];
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI] # 0 THEN SRQI ELSE 0);
BufferSW[];
};
RETURN[statusWord];
};
Wait: INTERNAL 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: INTERNAL PROC RETURNS [WORD] = {
Update GPIB status information.
RETURN[statusWord ← (IF BITAND[ReadRegL[intrptStatus2], mask.SRQI]#0 THEN SRQI ELSE 0)];
};
GetParaPoll: INTERNAL 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[auxMode, takeAsynchControl]; -- if standby, go to controller active state
WriteReg[auxMode, executeParaPoll];
c ← ReadReg[cmdPassThru];     -- store the response byte
IF monitorStatusWord THEN {
statusWord ← (IF BITAND[ReadRegL[intrptStatus2], 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 INTERNAL PROC [register: RRegister] RETURNS [char: CHAR] = {
addr: INTSELECT register FROM
dataIn     => 0,
intrptStatus1 => 1,
intrptStatus2 => 2,
serialPollStatus => 3,
addressStatus => 4,
cmdPassThru => 5, 
address0   => 6,
ENDCASE   => 7;
word: CARDINAL← XBus.IORead[addr+GPIBBaseAddr];
char ← LOOPHOLE[LowByte[word]];
};
ReadRegL: PRIVATE INTERNAL PROC [register: RRegister] RETURNS [word: CARDINAL] = {
addr: INTSELECT register FROM
dataIn     => 0,
intrptStatus1 => 1,
intrptStatus2 => 2,
serialPollStatus => 3,
addressStatus => 4,
cmdPassThru => 5, 
address0   => 6,
ENDCASE   => 7;
word ← XBus.IORead[addr+GPIBBaseAddr];
};
WriteReg: PRIVATE INTERNAL PROC [register: WRegister, dataByte: CHAR ] = {
addr: INTSELECT register FROM
cmdDataOut => 0,
intrptMask1 => 1,
intrptMask2 => 2,
serialPollMode => 3,
addressMode => 4,
auxMode => 5, 
address    => 6,
ENDCASE => 7;
XBus.IOWrite[addr+GPIBBaseAddr, LOOPHOLE[dataByte]];
};
WriteRegL: PRIVATE INTERNAL PROC [register: WRegister, dataWord: CARDINAL ] = {
addr: INTSELECT register FROM
cmdDataOut => 0,
intrptMask1 => 1,
intrptMask2 => 2,
serialPollMode => 3,
addressMode => 4,
auxMode => 5, 
address     => 6,
ENDCASE => 7;
XBus.IOWrite[addr+GPIBBaseAddr, dataWord];
};
END... of NatInstrGPIBDriver.mesa