"
module P2064

title 'TCPIP-VME Interface (A2064)'

"Compilation Notes: Be sure to merge the constraints in"
"this file with those in the constraint file A2064F.lci."
"The constraint file tells the compiler to set all I/O to"
"3.3V CMOS, and to use slow slew rate. The slow slew rate"
"causes less interference along the long tracks of the A2064"
"printed circuit board."

"Version 4: [14-DEC-09] Add compiler directives that allow"
"this code to be compiled for A2064A or A2064F depending upon"
"the hardware_version_num constant. The two versions require"
"different code because the rcm_data lines are in reverse order"
"in the RCM3200."

"Version 4: [10-DEC-09] We still see pixels ADDED during data"
"transfer from an A2037A in neighboring slot. Problem stops"
"with extender card. Problem occurs with artificial images"
"whose background intensity is 0, 1, or 2 counts, but no"
"other values (tried many, including 4, 8, 16, 32, 64, 128)."
"It turns out that the default constraint file for this chip"
"sets all the inputs to expect 1.8V CMOS levels, which means"
"that they are still switching when a logic line is bouncing"
"around between 0V and 1V, which is the case for the CDS line"
"from the RCM. We set all inputs and outputs to 3.3V logic"
"and merge the input file constraints with the compiler's"
"constraint file to produce code that shows no pixel skipping."
"The skipping was caused in the following way. The !CDSIN line"
"was going LO and triggering DS0 and other strobes. These"
"strobes, in running parallel to long tracks with CDSIN, would"
"provoke a spike on CDSIN with subsequent oscillation of CDS"
"and DS0. When the A2037A slave received !DS0 at exactly the"
"right moment, it would abandon its read cycle and go into its"
"cycle-termination state. The slave would not increment its"
"address counter. The spikes were mitigated by 1's in data"
"because the data lines float HI, and so we get edges only when"
"we have 0's in the data."

"Version 4: [30-OCT-09] Investigating the source of the"
"pixel-shifting errors that occur only with A2064F, not"
"A2064A (RCM2200). We see pixels LOST as we are reading"
"from local RAM portal. We correct this by synchronising"
"LRSEL with CK."

"Version 3: [31-JAN-08] Add hardware id and version read-
"back. The hardware id is 64 for the 2064, and the version
"number is 1 for the F-version, 0 being the A-version.


declarations
firmware_version_num=4;
test_version=0; "set to 1 to compile the test code"
hardware_id=64; "A2064 hardware identifier"
hardware_version_num=1; "A2064F"

"Rabbit Controller Module"
!LNK pin 48; "ethernet link from RCM"
!ACT pin 37; "ethernet active from RCM"
!LED1..!LED4 pin 5..8;
CSW pin 175; "configuration switch"

"Test Pins"
!TP1..!TP8 pin 9..12,14..17 istype 'com,pos';

"Control Address/Data from RCM"
CA0..CA5 pin 62,63,60,61,58,59 istype 'com';
RCD0..RCD7 pin 49,50,36,52,51,54,53,57;
!CDSIN pin 38; "control data strobe input"
!CW pin 35; "control write"
!RESET pin 161; "hardware reset"

"VME Bus"
VA1..VA31 pin 82,84,86,93,95,97,99,81,83,85,87,94,96,98,100,103,105,107,
  109,112,114,116,118,77,76,75,74,73,72,71,70 istype 'com'; "vme address"
!DS0,!DS1 pin 117,115 istype 'reg,pos'; "vme data strobes"
!AS pin 80 istype 'reg,pos'; "vme address strobe"
!LWORD pin 113; "vme longword"
!IACK pin 111 istype 'pos,keep'; "vme interrupt acknowledge"
VAM0..VAM5 pin 108,106,104,102,125,126 istype 'reg,keep'; "vme address modifier"
!WRITE pin 127 istype 'com,keep'; "vme write"
VD0..VD7 pin 145,141,140,139,138,137,136,135 istype 'com'; "vme data"
!VDEN0..!VDEN1 pin 150,142 istype 'com'; "vme data enable"
VDCK0..VDCK1 pin 149,147 istype 'com'; "vme data clock"
VDIR pin 148 istype 'com'; "vme direction"

"VME Address Buffers"
!AB pin 123 istype 'com';  "select real time data transfer A->B"
!BA pin 120 istype 'com';  "select real time data transfer B->A"
ADIR pin 121 istype 'com'; "address buffer direction, assert for A->B"
!OE pin 174; "buffer output enable"
ACLKAB pin 124 istype 'com'; "clock data from A->B"
ACLKBA pin 122 istype 'com'; "clock data from B->A"

"Clock Bus"  
FCK pin 66; "fast clock (80 MHz) in from oscillator"
CKOUT pin 64 istype 'com';"clock (80 MHz) out"
CK pin 68; "clock (80 MHz) in from CKOUT"

"Nodes"
CDS node istype 'reg,keep'; "control data strobe"
DBA0..DBA31 node istype 'reg,keep'; "slave driver base address"
!LDA node istype 'reg,keep'; "local data access"
BAZ node istype 'com,keep'; "base address zero"
RCMOE node istype 'com,keep'; "rcm data output enable"
VA0 node istype 'com'; "vme address bit zero"
VMEOE node istype 'com'; "vme data output enable"
RPD0..RPD7 node istype 'reg'; "ram portal virtual data"
LRSEL node istype 'reg'; "local ram select"
VMSEL node istype 'reg'; "vme select"

"Constants"
id_addr=0;  "hardware id location (byte)"
hv_addr=18; "hardware version number location (byte)"
fv_addr=19; "firmware version number location (byte)"
cs_addr=40; "configuration switch address (byte)"
dba_addr=42;"driver base address location (byte)"
vam_addr=46;"vme addr modifier location (byte)"
ram_portal_addr=63; "ram portal address location"


"Sets"
control_addr=[CA5..CA0]; "control address"
driver_base_addr=[DBA31..DBA0]; "slave driver base address"
vme_addr_modifier=[VAM5..VAM0]; "vme address modifier"
dba0=[DBA7..DBA0];	"first byte of vme address"
dba1=[DBA15..DBA8]; 	"second byte of vme address"
dba2=[DBA23..DBA16]; 	"third byte of vme address"
dba3=[DBA31..DBA24]; "fourth byte of vme address"
vme_data=[VD7..VD0]; "vme data bus"
ram_portal_data=[RPD7..RPD0]; "ram portal virtual data"
@if (hardware_version_num==0) {
  rcm_data=[RCD7..RCD0]; "RCM2200 interface data"
}
@if (hardware_version_num==1) {
  rcm_data=[RCD0..RCD7]; "RCM3200 interface data"
}
equations


"Clocks"
"======"

"CKOUT drives the CK global clock input."
CKOUT=FCK;


"RCM to Controller Interface"
"==========================="

"We synchronize the RCM data strobe with CK."
CDS.clk = CK;
CDS := CDSIN;

"We drive the RCM data lines on any Control Interface read."
RCMOE = !CW & CDS;
rcm_data.oe = RCMOE;

"The rcm_data is equal to the vme_data only when the master is"
"communicating with a slave. We clock VMSEL on the falling edge"
"of CK because CDS and LDA are clocked on the rising edge."
VMSEL.clk = !CK;
VMSEL := CDS & !CW & !LDA;
when VMSEL then rcm_data=vme_data.pin;

"We drive the VME data lines on any Control Interface write."
VMEOE = CW & CDS;
vme_data.oe = VMEOE;
when CW then vme_data=rcm_data.pin;

"We access the local ram portal when we read from the ram"
"portal address with the local base address."
LRSEL.clk = !CK;
LRSEL := CDS & !CW & LDA & (control_addr==ram_portal_addr);
when LRSEL then rcm_data=ram_portal_data;


"VME Interface Configuration"
"==========================="

"We arrange the bytes of the VME Base Address in big-endian order"
"within the Controller's address space."
driver_base_addr.clk=CK;
driver_base_addr.aclr=RESET;

when CDS & CW & (control_addr==dba_addr+3) then 
  dba0:=rcm_data.pin;
else dba0:=dba0.fb;
when CDS & CW & (control_addr==dba_addr+2) then 
  dba1:=rcm_data.pin;
else dba1:=dba1.fb;
when CDS & CW & (control_addr==dba_addr+1) then 
  dba2:=rcm_data.pin;
else dba2:=dba2.fb;
when CDS & CW & (control_addr==dba_addr+0) then 
  dba3:=rcm_data.pin;
else dba3:=dba3.fb;

vme_addr_modifier.clk=CK;
when RESET then vme_addr_modifier:=^h3D
else {
  when CDS & CW & (control_addr==vam_addr) then 
    vme_addr_modifier:=[RCD5..RCD0].pin;
  else vme_addr_modifier:=vme_addr_modifier;
}

"Base address zero helps our logic compiler."
BAZ = (driver_base_addr==0);

"We access local data when the driver base address is zero,"
"or we write to the driver base address or the vme modifier."
LDA.clk = CK;
LDA := BAZ
  # (control_addr==dba_addr+3)
  # (control_addr==dba_addr+2)
  # (control_addr==dba_addr+1)
  # (control_addr==dba_addr+0)
  # (control_addr==vam_addr);

"Here we compute the VME address from the RCM interface"
"address and the drier base address."
[VA31..VA1] = [DBA31..DBA6,CA5..CA1];


"VME Address Buffers"
"==================="

"VME Address buffers are set to place the address bits onto"
"the VME backplane in realtime and function as outputs only."
"A is the output from this chip, B is the address on the"
"backplane."

OE=1; "enable buffer outputs"
ADIR=1; "set buffer direction A->B"
AB=1; "enable realtime operation A->B"
BA=1; "enable realtime operation B->A"
ACLKAB=0; "never clock data A->B"
ACLKBA=0; "never clock data B->A"


"VME Data Buffers"
"==============="

"None of our cycles are long-word address or interrupt"
"acknowledgements."
LWORD=0;
IACK=0;

"The VME data buffers drive the VME data lines on RCM"
"write cycles, and drive the controller data lines on"
"read cycles."
VDIR=CW;

"We use the RCM write bit for the VME write bit."
WRITE=CW;

"The VA0 bit is a virtual one we use to stop us getting"
"confused about two-byte, one-byte, and four-byte read"
"cycles."
VA0=CA0;

"The VME data strobes are DS0 and DS1. We activate"
"them whenever we have CDS from the RCM and the access"
"is not local. We clock with the falling edge of CK"
"because CDS and LDA are clocked on the rising edge."
"Our firmware supports only byte-wise reads from the VME"
"address space. The code below prohibits DS0 and DS1 from"
"being asserted at the same time."
[DS0,DS1,AS].clk = !CK;
when CDS & !LDA then {
  DS0 := VA0;
  DS1 := !VA0;
  AS := 1;
}

"We enable the VME data buffers whenever we have VME"
"data strobes, one for each buffer."
VDEN0=DS0;
VDEN1=DS1;

"We clock outgoing data into our 74646 buffers with the"
"following two signals on VME write cycles. The data must"
"be valid at the rising edge of these clocks, having passed"
"from the RCM through the controller to the buffer." 
VDCK0=DS0;
VDCK1=DS1;



"Readback Registers"
"================="

when CDS & !CW & LDA & (control_addr==cs_addr) then 
  rcm_data=[0,0,0,0,0,0,0,!CSW];

when CDS & !CW & LDA & (control_addr==fv_addr) then 
  rcm_data=firmware_version_num;

when CDS & !CW & LDA & (control_addr==id_addr) then
  rcm_data=hardware_id;

when CDS & !CW & LDA & (control_addr==hv_addr) then
  rcm_data=hardware_version_num;


"The local ram portal provides virtual data for"
"a local ram portal. Every time we read from the"
"local ram portal at address ram_portal_addr, the"
"data increments by one."
ram_portal_data.aclr = RESET;
ram_portal_data.clk = LRSEL;
ram_portal_data := ram_portal_data + 1;


 
"LEDs"
"===="

"The LEDs provide diagnostic signals. The test point"
"LEDs have pins on the board you can use with a scope"
"probe."
when (!CSW # !RESET) & (test_version!=1) then {
  LED1 = 1;
  LED2 = LNK; 
  LED3 = ACT; 
  LED4 = !LDA;
  TP1 = CSW;
  TP2 = VD0;
  TP3 = RCD0;
  TP4 = WRITE;
  TP5 = CDS;
  TP6 = DS0 # DS1;
  TP7 = CDS & (control_addr==ram_portal_addr);
  TP8 = VMSEL;
} 

declarations
T24..T0 node istype 'reg'; "timer"
timer=[T24..T0]; "timer"
countbits=[T24..T21]; "top timer bits"
equations

"The test firmware creates a moving spot of light"
"on the front panel LEDs. The spot changes direction"
"when you press the configuration switch, and stops"
"when you press reset."

"Because this timer just counts up, we can define it"
"as one counter and trust that the compiler will figure"
"out that it can impement the counter with T-type"
"flip-flops and no fancy logic."
timer.clk=CK;
timer.aclr=RESET;
timer:=timer+1;

"We use the counter top four bits to drive the LEDs."
when !CSW & (test_version==1) then {
  LED1=(countbits==15);
  LED2=(countbits==14);
  LED3=(countbits==13);
  LED4=(countbits==12);
  TP1=(countbits==11);
  TP2=(countbits==10);
  TP3=(countbits==9);
  TP4=(countbits==8);
  TP5=(countbits==7);
  TP6=(countbits==6);
  TP7=(countbits==5);
  TP8=(countbits==4);
}

"We change direction when we press the CSW switch."
when CSW & (test_version==1) then {
  LED1=(countbits==4);
  LED2=(countbits==5);
  LED3=(countbits==6);
  LED4=(countbits==7);
  TP1=(countbits==8);
  TP2=(countbits==9);
  TP3=(countbits==10);
  TP4=(countbits==11);
  TP5=(countbits==12);
  TP6=(countbits==13);
  TP7=(countbits==14);
  TP8=(countbits==15);
}

end