"
module P302701A

title 'P302701A'

"Message Router for the Data Receiver A3027A"
"==========================================="

"Version 1, The Message Router reads messages from the Message Detector and stores"
"them in RAM. It receives LWDAQ commands and Data Strobes. Upon a Data Strobe, it"
"reads a message from RAM and uploads it to the LWDAQ Driver. This version is based"
"upon P3007C07.abl, the code from the Data Receiver (A3018)."

"Version 2, The message readout from the Message Detector is now byte by byte with"
"each byte independent. We implement flashing of the UPLOAD and EMPTY indicator lights"
"with SCK and the indicator module."

"Version 3, Add pins for the FRAM."

"Version 4, No changes."

"Version 5: Add Immediate Sample Transmission on X2 output."

"Version 6: X1 and X2 are outputs that are controlled individually by LWDAQ commands. We"
"divert Immediate Sample Transmission to the Y2 output and leave Y1 for the Message Detector"
"to use for transmission of a pulse when Decoder One is active."

"Version 7: As 6, but the X1 output emits 1-ms pulses 25 times per second when X1 is asserted"
"by command word."


declarations
  fake_transmit_data=0;
  fake_write_data=0;
equations

"Pins"
declarations
A pin 36; "LVDS input"
B pin 38 istype 'com'; "LVDS output"
LB pin 37 istype 'com'; "Loop Back"
!RESET pin 39; "Hardware Reset Input"
!RSTMD pin 152; "Reset Message Detector"			
DCK pin 154; "Data Clock, 40 MHz"
SCK pin 172; "Slow Clock 2048 Hz"
!RW pin 84 istype 'com'; "RAM Write"
!RCE pin 50 istype 'reg'; "RAM Chip Enable"
!ROE pin 62 istype 'com'; "RAM Output Enable"
RA18..RA0 pin 58, 59, 60, 61, 72, 73, 74, 75, 76, 77, 80, 
  81, 82, 83, 51, 52, 53, 54, 57 istype 'com'; "RAM Address"
ram_addr = [RA18..RA0];
RD7..RD0 pin 63, 64, 70, 71, 85, 86, 48, 49 istype 'com'; "RAM Data"
ram_data = [RD7..RD0];
UPLOAD pin 94 istype 'reg'; "Upload Indicator, through monostable"
EMPTY pin 93 istype 'reg'; "Empty Indicator, direct to LED"
MRDY pin 160; "Message Ready"
MDS pin 161 istype 'com,pos'; "Message Data Strobe"
MD7..MD0 pin 171, 170, 169, 168, 165, 164, 163, 162; "Message Data"
message_data = [MD7..MD0];
TP1,TP2,TP5 pin 10, 20, 30 istype 'com'; "Test Points"
MDCIN pin 158; "Message Detector Code, In from Message Detector"
DBCIN pin 106; "Display Board Code, In from Display Board"
DBC pin 159 istype 'com'; "Display Board Code, Out to Message Detector"
MDC pin 108 istype 'com'; "Message Detector Code, Out to Display Board"
MRC pin 107 istype 'reg'; "Message Router Code, Out to Display Board"
DCKB pin 105 istype 'com'; "DCK for Display Board"
X1 pin 141 istype 'reg';
X2 pin 140 istype 'reg';
Y2 pin 139 istype 'com';
!FS pin 5 istype 'reg'; "FRAM Select"
FQ pin 6; "FRAM Serial Output"
FC pin 23 istype 'reg'; "FRAM Serial Clock"
FD pin 24 istype 'com'; "FRAM Serial Input"
equations


"Global Nodes"
declarations
ATR node istype 'com'; "Address and Timestamp Reset"
equations


"Reset Signals"
"-------------"


"The RESET signal from U11 goes low for 300 ms after power-up and whenever"
"any switch or logic output pulls it low. The ATR signal goes hi when we"
"receive a reset command from the LWDAQ. We send RSTMD to the Mesage"
"Detector when either of these is asserted."

RSTMD = RESET # ATR;


"LWDAQ Command and Address Decoding"
"----------------------------------"

"This LWDAQ receiver uses the 40-MHz data clock to generate"
"the DA and DDA signals. We synchronise the incoming serial"
"logic signal, A, with the data clock."

declarations
SA node istype 'reg'; "Synchronized A"
DSA node istype 'reg'; "Delayed SA"
DA node istype 'com,keep'; "Delayed A Rising Edge"
DDA node istype 'com,keep'; "Delayed DA"
AA node istype 'reg'; "Address Active"
DAA node istype 'reg'; "Delayed AA"
CA node istype 'reg'; "Command Active"
DCA node istype 'reg'; "Delayed CA"
ER,Q1..Q16 node istype 'reg'; "Receiver Bits"
LT3..LT0 node istype 'reg'; "LWDAQ Timer"
lt = [LT3..LT0];
AS node istype 'reg'; "Address Strobe"
CS node istype 'reg'; "Command Strobe"
DS node istype 'reg'; "Data Strobe"
DC1..DC16 node istype 'reg';"Device Command Bits"
DA0..DA15 node istype 'reg';"Device Address Bits"
WAKE node istype 'com'; "Wake"
DTX node istype 'com'; "Device Transmit"
ISTS node istype 'com'; "Immediate Sample Transmit Select"
equations

"We synchronize A with DCK, and provide a delayed"
"version of A that allows us to detect edges."
[SA,DSA].clk = DCK;
[SA,DSA].aclr = RESET;
SA := A;
DSA := SA;

"This timer allows us to generate the Delayed A (DA)"
"and Double-Delayed A (DDA) signals for serial reception."
lt.clk = DCK;
lt.aclr = RESET;
when lt==0 then {
  when SA & !DSA then lt:=1
  else lt:=0;
} else {
  when lt==9 then lt:=0
  else lt:=lt+1;
}
DA = (lt==4);
DDA = (lt==9);

"We use DCK to clock the receiver registers, and RESET to"
"clear them."
[ER,Q1..Q16,AA,DAA,AS,CA,DCA,CS,DS,DC1..DC16,DA0..DA15].clk = DCK;
[ER,Q1..Q16,AA,DAA,AS,CA,DCA,CS,DS,DC1..DC16,DA0..DA15].aclr = RESET;

"We move bits along the shift register on DA."
when DA then [ER,Q1..Q16] := [SA,ER,Q1..Q15];
else [ER,Q1..Q16] := [ER,Q1..Q16];

"Address Active provides a pulse that begins with DDA"
"on the start bit of an address transmission, and ends"
"with the stop bit of an address transmission. Delayed"
"AA allows us to create Address Strobe, or AS. Address"
"Strobe provides a pulse at the end of an address"
"reception. We clock the receiver bits into the address"
"register on a rusing edge of AS."
when DDA then AA := (!AA & !CA & !SA & !ER) # (AA & !SA)
else AA := AA;
DAA := AA;
AS := DAA & !AA;
when AS then [DA0..DA15] := [Q1..Q16]
else [DA0..DA15] := [DA0..DA15];

"Command Active provides a pulse that begins with DDA"
"on the start bit of a command transmission, and ends"
"with the stop bit of a command transmission. Delayed"
"CA allows us to create Command Strobe, or CS. Command"
"strobe provides a pulse at the end of each command"
"reception. We clock the receiver bits into the command"
"register on a rusing edge of CS."
when DDA then CA := (!AA & !CA & !SA & ER) # (CA & !SA)
else CA := CA;
DCA := CA;
CS := DCA & !CA;
when CS then [DC1..DC16] := [Q1..Q16]
else [DC1..DC16] := [DC1..DC16];

"Data Strobe identifies a solitary low pulse on A. A"
"solitary low pulse, combined with DTX, indicates that"
"the drivers is expecting this device to upload eight"
"bits of data."
DS := DDA & SA & !AA & !CA;

"Address and Timestamp Reset"
ATR = DC1 # RESET;

"Device Transmit Bit"
DTX = DC5;

"We loop back A to B so long as DTX is not set."
when !DTX then B = A;

"We enable the return LVDS driver when DC7 is set."
LB = DC7;

"WAKE bit."
WAKE = DC8;

"Immediate Sample Transmit Select"
ISTS = DC2;

"X1 Output Select is DC3"
"X2 Output Select is DC4"


"FRAM Controller"
"---------------"

"The FRAM Controller will allow the Message Router to read and"
"write from the FRAM."



"Data Transmitter"
"----------------"

"The transmitter sends bytes back to the driver. It waits for"
"DS combined with DTX (DC5). When it receives DS and DTX, it"
"waits for Transmission Byte Load (TBL). The transmitter uses"
"DCK to time its serial transmission to the driver. It transmits"
"a leading zero followed by the eight bits of the transmission"
"byte (tb)."

declarations
TS4..TS0 node istype 'reg'; "Transmit State"
TBD7..TBD0 node istype 'reg'; "Transmission Bits"
ts=[TS4..TS0];"Transmission State"
tbd=[TBD7..TBD0]; "Transmission Byte Data"
TBL node istype 'com,pos,keep'; "Transmitter Byte Load"
TBO node istype 'com,keep'; "Transmitter Bit Out"
equations

"The Transmit Byte, tb, holds a byte for transmission to"
"the LWDAQ driver."
tbd.clk = DCK;
tbd.aclr = RESET;

"The Transmitter State, ts, controls serial transmission"
"to the LWDAQ driver of the Transmit Byte."
"We assert Transmit Byte Load, TBL, elsewhere in the code"
"when we want to clock ram_data.pin into the Transmit Byte."
ts.clk = DCK;
ts.aclr = RESET;
state_diagram ts;
  state 0:if DS & DTX then 1 else 0;
  state 1:
    if !DTX then 0;
    if DTX & TBL then 2;
    if DTX & !TBL then 1;
  state 2:goto 3;"Start Bit"
  state 3:goto 4;"Start Bit"
  state 4:goto 5;"TBD7"
  state 5:goto 6;"TBD7"
  state 6:goto 7;
  state 7:goto 8;
  state 8:goto 9;
  state 9:goto 10;
  state 10:goto 11;
  state 11:goto 12;
  state 12:goto 13;
  state 13:goto 14;
  state 14:goto 15;
  state 15:goto 16;
  state 16:goto 17;
  state 17:goto 18;
  state 18:goto 19;"TBD0"
  state 19:goto 20;"TBD0"
  state 20:goto 0;"Stop Bit"
equations;

"TBO is the output of the bit transmitter. It passes through"
"the LVDS return and so along the cables to the driver."
TBO = (
    (ts==0)  & 1   "Idle Bit 1"
  # (ts==1)  & 1   "Idle Bit 1"
  # (ts==2)  & 0   
  # (ts==3)  & 0
  # (ts==4)  & TBD7
  # (ts==5)  & TBD7
  # (ts==6)  & TBD6
  # (ts==7)  & TBD6
  # (ts==8)  & TBD5
  # (ts==9)  & TBD5
  # (ts==10) & TBD4
  # (ts==11) & TBD4
  # (ts==12) & TBD3
  # (ts==13) & TBD3
  # (ts==14) & TBD2
  # (ts==15) & TBD2
  # (ts==16) & TBD1
  # (ts==17) & TBD1
  # (ts==18) & TBD0
  # (ts==19) & TBD0
  # (ts==20) & 1   "Stop Bit 1"
);

"We return TBO to the driver when DTX is set."
when DTX then B = TBO;

"We load the transmitter byte from the RAM data bus. When"
"some other part of the firmware asserts TBL."
when !fake_transmit_data then {
  when TBL then tbd:=ram_data.pin;
  else tbd:=tbd;
}

"We can generate fake data to check for errors in the"
"upload to the LWDAQ driver, as opposed to errors in"
"RF reception."
when fake_transmit_data then {
  TBL = 1;
  when (ts==20) then {tbd:=tbd+1;} else {tbd:=tbd;}
}


"Address Counters"
"----------------"

"We have two address counters, one for storage and one for transmission."
"The Message Router transmits bytes from RAM to the LWDAQ Driver and"
"stores bytes to RAM from the Message Detector."

declarations
SA18..SA0 node istype 'reg'; "Store Address"
store_addr = [SA18..SA0];
sab0=[SA7..SA0]; "Store Address byte zero"
sab1=[SA15..SA8]; "Store address byte one"
sab2=[SA18..SA16]; "Store address byte two"
SAC0,SAC1 node istype 'com'; "Store Address Carry"
SAI node istype 'com,pos,keep'; "Store Address Increment"
TA18..TA0 node istype 'reg'; "Transmit Address"
transmit_addr = [TA18..TA0];
tab0=[TA7..TA0]; "Transmit address byte zero"
tab1=[TA15..TA8]; "Transmit address byte one"
tab2=[TA18..TA16]; "Transmit address byte two"
TAC0,TAC1 node istype 'com,keep'; "Transmit Address Carry"
TAI node istype 'com,pos,keep'; "Transmit Address Increment"
!AE0 node istype 'com,keep'; "Addresses Equal Byte 0"
!AE1 node istype 'com,keep'; "Addresses Equal Byte 1"
!AE2 node istype 'com,keep'; "Addresses Equal Byte 2"
AE node istype 'com'; "Addresses Equal"
equations

"The store address is the RAM address at which we store"
"data."
store_addr.clk = DCK;
store_addr.aclr = ATR;
SAC0 = (sab0==^hFF);
SAC1 = (sab1==^hFF);
when SAI then {
  sab0 := sab0+1;
  when SAC0 then sab1 := sab1+1;
  else sab1 := sab1;
  when SAC1 & SAC0 then sab2 := sab2+1;
  else sab2 := sab2;
} else {
  store_addr := store_addr;
}

"The transmit address is the RAM address from which"
"we read data to transmit."
transmit_addr.clk = DCK;
transmit_addr.aclr = ATR;
TAC0 = (tab0==^hFF);
TAC1 = (tab1==^hFF);
when TAI then {
  tab0 := tab0+1;
  when TAC0 then tab1 := tab1+1;
  else tab1 := tab1;
  when TAC1 & TAC0 then tab2 := tab2+1;
  else tab2 := tab2;
} else {
  transmit_addr := transmit_addr;
}

"Address Equal is true when the store address equals the"
"transmit address."
AE0 = (sab0 == tab0);
AE1 = (sab1 == tab1);
AE2 = (sab2 == tab2);
AE = AE0 & AE1 & AE2;


"RAM Controller"
"--------------"

"The RAM Controller arbitrates between storing messages from the"
"Message Detector and transmitting mesages to the LWDAQ Driver."
"It gives priority to bytes waiting to be stored. When it sees"
"MRDY it stores the byte presented by the Message Detector on the"
"message data. When it sees the transmitter state machine waiting"
"to transmit a byte, and provided MRDY is not asserted, the RAM"
"Controller retrieves a byte from RAM and passes it to the byte"
"transmitter. Note that the RAM Controller deals only in bytes. It"
"does not know about the four-byte structure of messages. It just"
"keeps reading bytes from the Message Detector until there are no"
"more bytes to read."

declarations
RDOE node istype 'com,keep'; "RAM Data Output Enable (from this chip)"
RCS2..RCS0 node istype 'reg'; "Ram Controller State"
rcs=[RCS2..RCS0];
FWD0..FWD7 node istype 'reg,pos'; "Fake Write Data"
fwd=[FWD7..FWD0];
equations

"The Fake Write Data is what we write to RAM when we want"
"to test if writing to RAM is reliable. We use the LWDAQ"
"Terminal Instrument to read blocks of data from the Data"
"Receiver and look at them on the screen to wath for glitches."
fwd.clk = DCK;
fwd.aclr = RESET;
when SAI then fwd:=fwd+1 else fwd:=fwd;

"The RAM Controller responds to new messages in preference"
"to a request to upload data over the LWDAQ interface."
"If the RAM buffer is empty, which we mark with AE,"
"address equal, the RAM Controller waits until there"
"is another byte to transmit before it loads the transmit"
"buffer with the byte and permits transmission."
rcs.clk = DCK;
rcs.aclr = RESET;
state_diagram rcs;
  state 0:
    if MRDY then 1 
    else if (ts==1) & !AE then 5
    else 0;
  state 1:goto 2;   "store byte"
  state 2:goto 3;   "increment storage address"
  state 3:goto 4;   "wait for MRDY to settle"
  state 4:goto 0;   "wait for MRDY to settle"
  state 5:goto 6;   "load transmit byte from ram"
  state 6:goto 0;   "increment transmit address"
equations


ram_data.oe = RDOE;
RCE.clk = DCK;

when (rcs==0) then {  "rest state"
  ram_addr = store_addr
  ram_data = 0;
  RW = 0;
  ROE = 0;
  RCE := 0;
  RDOE = 1;
} 
when (rcs==1) then { "store byte from Message Detector"
  ram_addr = store_addr;
  when !fake_write_data then {
    ram_data = message_data; 
  } else {
    ram_data=fwd;
  }
  RW = 1;
  ROE = 0;
  RCE := 1;
  RDOE = 1;
}
when (rcs==2) then {  "increment storage address"
  ram_addr = store_addr;
  when !fake_write_data then {
    ram_data = message_data;
  } else {
    ram_data=fwd;
  }
  RW = 1;
  ROE = 0;
  RCE := 0;
  RDOE = 1;
  SAI = 1;
  MDS = 1;
}
when (rcs==3) then {  "wait for MRDY to settle"
  ram_addr = store_addr;
  ram_data=0;
  RW = 1;
  ROE = 0;
  RCE := 0;
  RDOE = 1;
}
when (rcs==4) then {  "wait for MRDY to settle"
  ram_addr = store_addr;
  ram_data=0;
  RW = 1;
  ROE = 0;
  RCE := 0;
  RDOE = 1;
}
when (rcs==5) then {
  ram_addr = transmit_addr; 
  ram_data = 0; "load transmit byte from ram"
  RW = 0;
  ROE = 1;
  RCE := 1;
  RDOE = 0;
}
when (rcs==6) then {
  ram_addr = transmit_addr;
  ram_data = 0; "increment transmit address"
  RW = 0;
  ROE = 1;
  RCE := 0;
  TAI = 1;
  TBL = 1;
  RDOE = 0;
}


"Indicators Lamps"
"----------------"

"The Message Router has two indicator lamps: UPLOAD and EMPTY."

UPLOAD.ap = DS;
UPLOAD.clk = SCK;
UPLOAD := 0;

EMPTY.ap = AE;
EMPTY.clk = SCK;
EMPTY := 0;



"Display Board Interface"
"-----------------------"

"The Display Board has a bunch of lights controlled by the"
"Message Detector Code and the Message Router Code. It also"
"can send codes back to the Message Router with its own"
"Display Board Code. Here we drive the signals to the Display"
"Board in a simple manner."

DBC = DBCIN;
MDC = MDCIN;
DCKB = DCK;


declarations
MRCS0..MRCS3 node istype 'reg';
mrcs = [MRCS3..MRCS0];
equations


mrcs.clk = DCK;
mrcs.aclr = RESET;
mrcs:=mrcs+1;

MRC.clk = !DCK;
MRC := (mrcs == 1) 
  # (mrcs == 2) & UPLOAD
  # (mrcs == 3) & EMPTY;


"Immediate Sample Transmission"
"-----------------------------"

declarations
ISTC7..ISTC0 node istype 'reg'; "Immediate Sample Transmit Counter"
istc = [ISTC7..ISTC0];
istc_divisor = 160;
ISTCK node istype 'reg'; "Immediate Sample Transmit Clock"
ISTID7..ISTID0 node istype 'reg'; "Immediate Sample Transmit ID"
ISMATCH node istype 'com,keep'; "Immediate Sample Match"
istid = [ISTID7..ISTID0]; 
STS2..STS0 node istype 'reg'; "Sample Transmit State"
sts = [STS2..STS0];
ISW15..ISW0 node istype 'reg'; "Immediate Sample Word"
isw = [ISW15..ISW0];
ISTS4..ISTS0 node istype 'reg'; "Immediate Sample Transmit State"
ists = [ISTS4..ISTS0];
ISTD node istype 'com,keep'; "Immediate Sample Transmit Done"
equations

"The ISTS bit in the Command Word controls when we store the upper"
"command bits as the channel ID we will match for the immediate sample"
"transmit."
istid.clk = DCK;
istid.aclr = RESET;
when ISTS then istid := [DC16..DC9];
else istid := istid;

"The IST clock is some integer fraction of the data clock."
istc.clk = DCK;
istc.aclr = RESET;
when istc == 0 then istc := istc_divisor-1;
else istc := istc - 1;
ISTCK.clk = DCK;
ISTCK := (istc == 0);

"Immediate Sample Match detects the storage of a sample with the"
"same ID as is stored in istid."
ISMATCH = !SA0 & !SA1 & (message_data == istid);

"The Sample Transmit State initiates the serial transmission."
sts.clk = DCK;
sts.aclr = RESET;
state_diagram sts;
  state 0:if (rcs==1) & ISMATCH then 1 else 0;
  state 1:if (rcs==1) then 2 else 1;
  state 2:if (rcs==1) then 3 else 2;
  state 3:if ISTD then 4 else 3;
  state 4:if !ISTD then 0 else 4;
equations;

"The Immesiate Sample Word will contain the sixteen-bit sample."
isw.clk = DCK;
when (sts==0) then isw := 0;
when (sts==1) then {
  [ISW15..ISW8] := message_data;
  [ISW7..ISW0] := [ISW7..ISW0];
}
when (sts==2) then {
  [ISW15..ISW8] := [ISW15..ISW8];
  [ISW7..ISW0] := message_data;
}
when (sts==3) then {
  isw := isw;  
}
when (sts==4) then {
  isw := 0;
}


"The Immediate Sample Transmit state machine controls the"
"transmission of individual sample bits."
ists.clk = ISTCK;
ists.aclr = RESET;
when (sts==3) & (ists==0) then ists:=1;
when (ists>=1) & (ists<=17) then ists:=ists+1;
when (ists==18) & (sts==3) then ists:=18;
when (ists==18) & (sts!=3) then ists:=0;
ISTD = (ists==18);


"Digital Input-Output"
"--------------------"

"The Digital I/O connections are brought through the Message Detector."
"Here we generate output signals that will be routed through the Message"
"Detector, or accept input signals from the Message Detector."


"The X1 and X2 outputs are set by LWDAQ commands. The DC3 and DC4 bits"
"select the X1 and X2 outputs respectively and the DC9 bit determines"
"enables X1 and sets X2."
declarations
  X1EN node istype 'reg';
  X1DIV0..X1DIV6 node istype 'reg';
  x1div = [X1DIV6..X1DIV0];
  x1divend = 82;
equations

X1EN.clk = DCK;
X1EN.aclr = RESET;
when DC3 then X1EN := DC9;
else X1EN := X1EN;

x1div.clk = SCK;
x1div.aclr = RESET;
when (x1div == x1divend) & X1EN then x1div := 0;
when (x1div == x1divend) & !X1EN then x1div := x1divend;
when (x1div != x1divend) then x1div := x1div + 1;

X1.clk = !SCK;
X1 := (x1div == 0) # (x1div == 1);

X2.clk = DCK;
X2.aclr = RESET;
when DC4 then X2 := DC9;
else X2 := X2;


"We transmit the immediate sample word on Y2."
Y2 = (ists==0) 
  # ISW15 & (ists==2)
  # ISW14 & (ists==3)
  # ISW13 & (ists==4)
  # ISW12 & (ists==5)
  # ISW11 & (ists==6)
  # ISW10 & (ists==7)
  # ISW9 & (ists==8)
  # ISW8 & (ists==9)
  # ISW7 & (ists==10)
  # ISW6 & (ists==11)
  # ISW5 & (ists==12)
  # ISW4 & (ists==13)
  # ISW3 & (ists==14)
  # ISW2 & (ists==15)
  # ISW1 & (ists==16)
  # ISW0 & (ists==17)
  # (ists==18);


"Test Points"
"-----------"


TP1 = 1;
TP2 = UPLOAD;
TP5 = MRC;

end