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

"Version 8: We introduce Message Notification via Y1 and Y2. These two outputs transmit the same"
"serial data. Two-thirds of the way through reception of a message by the Message Detector, the"
"Message Router generates an Incoming Notification to alert any auxilliary circuit that RF power"
"from a known transmitter is present. Whenever the Message Router stores a clock message, it also"
"generates a Clock Transmission with the entire contents of the clock message. Provided that no"
"clock message is imminent, whenever the Message Router stores a data message, it generates a"
"Message Transmission with the contents of the message. Meanwhile, X1 is set by LWDAQ command,"
"and X2 provides Instant Sample Transmission as in Version 5."

"Version 9: Compatible with Version 8, but we fix several problems with message notification."
"We ensure that we send a data transmission notification only when the prior incoming"
"notification message applies to the data transmission."

"Version 10: Add support for set numbers. The completion code of a message, combined with the"
"channel number, allow us to calculate the set number. All original SCTs operated on set zero."
"The Message Router calculates the set number and compares it to its Set Select Register. Valid"
"set numbers are 0..13. The Message Router instructs the Message Detector as to which messages"
"to store based upon the set number. By default, the Message Router accepts only set zero messages."
"If we write a set number between 0 and 13 to the Set Select Register, the Message Router will"
"store only messages from the specified set number. If we write the value 15 to the register,"
"the Message Router will store all messages, even though their channel numbers overlap. This"
"last feature is to allow us to detect the presence of all transmitters in a system, but is"
"not intended for recording."


declarations
"Configuration parameters for diagnostic firmware."
  fake_transmit_data=0;
  fake_write_data=0;

"Message Notification codes. Each is four bits long."
  incoming_notification = ^hA;
  clock_transmission = ^hB;
  data_transmission = ^hC;
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"
EMPTY pin 93 istype 'reg'; "Empty Indicator"
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'; "X1 Output Value"
X2 pin 140 istype 'com'; "X2 Output Value"
Y1 pin 139 istype 'com'; "Y1 Output Value"
Y2 pin 138 istype 'com'; "Y2 Output Value"
MSGI pin 137; "Message Incoming"
CMIMM pin 136; "Clock Message Imminent"
CMST pin 135; "Clock Message Store"
SETDIN pin 147; "Data Input for Set Discriminator from Message Detector"
SETSHIFT pin 146; "Shift Data for Set Discriminator from Message Detector"
SETMATCH pin 145 istype 'reg'; "Output from Set Discriminator to Message Detector"
!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



"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"
ATR node istype 'com,keep'; "Address and Timestamp Reset"
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;

"Reset Message Detector."
RSTMD = 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;

"Configuration Register Select is DC3. When we address a control"
"register, bits DC16..DC13 are a four-bit register select address"
"and DC12..DC9 are a four-bit value to write to the four-bit register"
"In this version of the firmware we have the following registers"
"defined."

"Address    Function"
"0          Non-zero value sets X1 to HI."
"1          Four-bit Set Select Register."


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

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


"Set Discriminator"
"-----------------"

"Set discrimination is a function the Message Router provides for the"
"Message Detector because the Message Detector logic does not have the"
"capacity to perform the addition operation required to check that the"
"completion code and channel number match the set identifier written"
"to the set identifier register by the user through LWDAQ."

declarations
M23..M0 node istype 'reg,keep';  "Message Data"
message = [M23..M0];
channel_id = [M23..M20];
completion_code = [M3..M0];
SSR3..SSR0 node istype 'reg'; "Set Select Register bits"
ssr = [SSR3..SSR0];
equations

"We have a Set Selection Register we can set through the LWDAQ interface."
"with a command that has DC3 set, DC16..DC13 equal to 1, the address of the"
"register, and DC12..DC9 equal to the set value. The default value of the"
"resiter is fifteen (15), which is the code for acceptance of all sets."
ssr.clk = DCK;

"The initialization of the register takes place on a power-up or hardware"
"reset, but not when we send a command to reset the address and timestamp"
"registers. We initialize the Set Selection Register to the value that accepts"
"set zero, the original SCT set number."
ssr.aclr = RESET;

"We write to the set id with register address 1, and its value is in command"
"bits DC12..DC9."
when DC3 & ([DC16..DC13] == 1) then ssr := [DC12..DC9];
else ssr := ssr;

"Message data is clocked on !DCK as we shift bits out of a message decoder."
"Otherwise, the message data remains in place."
message.clk = !DCK;
message.aclr = RESET;
when SETSHIFT then { 
  [M23..M0] := [M22..M0,SETDIN];
} else {
  message:=message;
}

"Here is the set match calculation. It is one line, but it takes seventy-"
"nine product terms, for which there was no space in the Message Detector."
"The Set Select Register value fifteen (15) generates a match on all messages"
"regardless of their channel_id or completion_code. We calculate the setmatch"
"flag only when the transfer of the message bits into the local message resgister"
"is not taking place. During the transfer, the set match flag is zero."
SETMATCH.clk = DCK;
when !SETSHIFT then {
  SETMATCH := (ssr == 15) # (ssr == (completion_code - 15 + channel_id));
} else {
  SETMATCH := 0;
}

"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. The Message Router sends only"
"commands to flash the EMPTY and UPLOAD lights. The commands"
"to flash the channel activity and antenna activity lights"
"come from the Message Detector."

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 Immediate 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);


"Message Notifier"
"----------------"

"The Message Notifier arranges for notifications of incoming messages, clock"
"messages, and data messages to be transmitted serially on one of the fast"
"logic outputs, Y1 or Y2, or both."
declarations
  MSGID node istype 'reg'; "Message Incoming Delayed"
  MNS0..MNS3 node istype 'reg'; "Message Transmit State"
  mns = [MNS3..MNS0];
  TND node istype 'com,keep'; "Transmit Notification Done"
equations

"Message Incoming Delayed allows us to determine when MSGI is first asserte,"
"so we can send an INCOMING notification out on Y1 and Y2."
MSGID.clk = DCK;
MSGID := MSGI;

"The Message Notifier State machine controls the generation of serial message"
"triggers. When a clock message is imminent, the Message Detector will assert"
"CMIMM. When CMIMM is asserted, the mns machine ignores all activity except"
"the storage of a clock message. The storage of a clock message is indicated"
"by CMST, which is also asserted by the Message Detector. When CMIMM is not"
"asserted, the mns machine initiates the transmission of an Incoming"
"Notification whenever it sees a rising edge on the MSGI (Message Incoming)."
"Whenever a message is stored, the mns machine transmits the message. Because"
"the serial transmission takes 50 ns/bit * 37 bits = 1.85 us, the machine will"
"miss all messages stored for 1.85 us. At the end of clock or data message"
"transmission, the mns machine waits for MSGI to be un-asserted, so that it"
"will not arrive in the rest state when MSGI is asserted, having missed the"
"rising edge of MSGI, and so missed sending an Incoming Notification."
mns.clk = DCK;
mns.aclr = RESET;
state_diagram mns;
  "Rest state."
  state 0: 
    if CMST then {
      if (rcs == 1) & !SA0 & !SA1 then 3 else 0;
    }
    if !CMST & CMIMM then 0;
    if !CMST & !CMIMM then {
      if MSGI & !MSGID then 1;
      if MSGI & MSGID then {
        if (rcs == 1) & !SA0 & !SA1 then 3
        else 0
      } 
    }

  "Prepare Incoming Notification"
  state 1: goto 2;

  "Transmit Incoming Notification."
  state 2: if TND then 0 else 2;

  "Store ID byte in the Message Notification Register"
  state 3: goto 4;

  "Wait for HI content byte."
  state 4: if (rcs == 1) & SA0 & !SA1 then 5 else 4;

  "Store HI content byte in the Message Notification Register"
  state 5: goto 6;

  "Wait for LO content byte.:
   state 6: if (rcs == 1) & !SA0 & SA1 then 7 else 6;

  "Store LO content byte in the Message Notification Register"
  state 7: goto 8;

  "Wait for timestamp or firmware byte."
  state 8: if (rcs == 1) & SA0 & SA1 then 9 else 8;

  "Store timestamp or firmware byte in the Message Notification Register."
  state 9: goto 10;

  "Transmit Message Notification."
  state 10: if TND then 11 else 10;

  "Wait for !MSGI."
  state 11: if !MSGI then 0 else 11;

  "Wait for !MRDY and send an incoming notification which has a high"
  "probability of sampling the background power."
  state 12: if CMIMM then 0;
    if !CMIMM & MRDY then 12;
    if !CMIMM & !MRDY then 1;
equations

"The Message Notification Register stores a message for transmission serially."
declarations
  MNR0..MNR35 node istype 'reg'; "Message Notification Register"
  mnr = [MNR35..MNR0];
  MNRS node istype 'com,keep,pos'; "Message Notification Register Shift"
equations

mnr.clk = DCK;
mnr.ap = RESET;
when (mns == 0) then {
  mnr := 0;
}
when (mns == 1) then {
  [MNR35..MNR32] := incoming_notification;
  [MNR31..MNR0] := ^hFFFFFFFF;
}
when (mns == 2) then {
  when MNRS then mnr := [MNR34..MNR0,1]
  else mnr := mnr;
}
when (mns == 3) then {
  when CMST then {
    [MNR35..MNR32] := clock_transmission;
  } else {
    [MNR35..MNR32] := data_transmission;
  }
  [MNR31..MNR24] := message_data;
  [MNR23..MNR0] := [MNR23..MNR0];
}
when (mns == 4) then {
  mnr := mnr;
}
when (mns == 5) then {
  [MNR35..MNR32] := [MNR35..MNR32];
  [MNR31..MNR24] := [MNR31..MNR24];
  [MNR23..MNR16] := message_data;
  [MNR15..MNR0] := [MNR15..MNR0];
}
when (mns == 6) then {
  mnr := mnr;
}
when (mns == 7) then {
  [MNR35..MNR32] := [MNR35..MNR32];
  [MNR31..MNR16] := [MNR31..MNR16];
  [MNR15..MNR8] := message_data;
  [MNR7..MNR0] := [MNR7..MNR0];
}
when (mns == 8) then {
  mnr := mnr;
}
when (mns == 9) then {
  [MNR35..MNR8] := [MNR35..MNR8];
  [MNR7..MNR0] := message_data;
}
when (mns == 10) then {
  when MNRS then mnr := [MNR34..MNR0,1]
  else mnr := mnr;
}
when (mns == 11) then {
  mnr := mnr;
}


"The Notification Serializer transmits the Message Notification Register at 20 MBPS."
"When it's done, it asserts TND. After transmitting the start bit (LO) and the four"
"notification type bits, the serializer transmits trailing bits on an incoming"
"notification or proceeds with data or clock notification. These notifications"
"contain an eight-bit channel ID, sixteen bits of content, and eight bits of timestamp"
"or firmware version. Following the data or clock notification, there are trainling"
"bits. The purpose of the trailing bits is to give the circuit that receivers the"
"notifications time to process them before we allow the serializer to transmit another"
"notification."
declarations
  NSS0..NSS6 node istype 'reg'; "Message Notification Serializer"
  nss = [NSS6..NSS0];
  MNOUT node istype 'reg,keep'; "Message Notification Output"
  nss_ni_end = 20; "State in which we have transmitted the notification type."
  nss_tx_end = 80; "State in which we have finished transmitting data."
  nss_done = 120; "State in which we have finished with trailing bits."
equations

nss.clk = DCK;
nss.aclr = RESET;
when (nss == 0) then {
  when (mns == 2) # (mns == 10) then {
    nss := 1;
  } else {
    nss := 0;
  }
} 
when (nss >= 1) & (nss < nss_ni_end) then {
  nss := nss + 1;
}
when (nss == nss_ni_end) then {
  when (mns == 2) then nss:= nss_tx_end;
  else nss := nss_ni_end + 1;
}
when (nss > nss_ni_end) & (nss < nss_done) then {
  nss := nss + 1;
}
when (nss == nss_done) then {
  nss := 0;
}

TND = (nss == nss_done);

MNOUT.clk = DCK;
when (nss == 0) then {
  MNOUT := 1;
}
when (nss == 1) # (nss == 2) then {
  MNOUT := 0;
}
when (nss >= 3) & (nss <= nss_tx_end - 1) then {
  MNOUT := MNR35;
  MNRS = !NSS0;
}
when (nss >= nss_tx_end) then {
  MNOUT := 1;
}


"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 output is set by a LWDAQ commands."
X1.clk = DCK;
X1.aclr = RESET;
when DC3 & ([DC16..DC13] == 0) then X1 := DC9;
else X1 := X1;


"We transmit the immediate sample word on X2."
X2 = (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);

Y1 = MNOUT;
Y2 = MNOUT;


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


TP1 = MSGI;
TP2 = Y1;
TP5 = (nss > 0);

end