"
module P302702A

title 'P302702A'

"Message Detector for the Data Receiver A3027A."
"=============================================="

"Version 1: Based upon P3007C07, the Message Detector contains eight"
"independent Message Decoders. The decoders are identical and defined"
"in a separate source file as a module. The Message Detector watches"
"the eight decoders. When a message arrives in one of them, the Decoder"
"transfers the message ID, its data value, and the current timestamp"
"to the Message Router of the A3027, through the message_data pins."

"The timestamp is a twenty-four bit counter running off the RCK clock,"
"which is 32.768 kHz. A message consists of an eight-bit ID, of which"
"the top four bits are always zero, followed by a sixteen-bit data"
"value, and then the lower eight bits of the timestamp."

"The Message Detector generates clock messages every 128 cycles of"
"RCK, and transfers these to the Message Router. A clock message"
"consists of an eight-bit ID byte that is zero, the top and middle bytes"
"of the timestamp, and a final byte that, instead of containing the"
"lower eight bits of the timestamp, which would at this time always"
"be zero, contains the Message Detector firmware version number."

"The firmware version numbers of the Data Recevier (A3018) went from"
"1 to the current value 7, leaving room to go to 19. The Data Receiver"
"(A3027) numbers start at 20."

"The A3027 serial inputs and outputs connect to the Message Detector."
"In this version of the code, we do nothing with these connections."

"This version of the code takes a minute to compile. It uses most of"
"the GLB inputs and logic clusters. We may not be able to fit much more"
"functionality into the chip. There are more logic lines available to"
"transfer signals to the Message Router, where we could do work that"
"the Message Detector cannot accommodate. Alternatively, we may be able"
"to improve the efficiency of the existing functions by building a byte"
"multiplexer in front of the final message data selector for the transfer"
"to the Storage Controller."

declarations
  firmware_version=^d27;
  fake_message_data=0;
equations


"Pins"
declarations
!RESET pin 70;"Hardware Reset"			
ARCK pin 120; "Asynchronous 32.768 kHz reference clock input"
DCK pin 66; "Data Clock 40 MHz"
TP3, TP4, TP6 pin 10, 20, 30 istype 'com'; "Test Points"
MRDY pin 62 istype 'com,pos'; "Message Ready"
MDS pin 61; "Message Data Strobe"
MD7..MD0 pin 51, 52, 53, 54, 57, 58, 59, 60 istype 'com'; "Message Data"
SCK pin 50 istype 'com'; "Slow Clock Output, 2.048 kHz"
DBC pin 63; "Display Board Code"
MDC pin 64 istype 'com,keep'; "Message Detector Code"
message_data = [MD7..MD0];
Q1..Q8 pin 39, 35, 175, 165, 152, 174, 112, 103; "Demodulator Outputs"
RECEIVE pin 148 istype 'com'; "Receiving a Message"
X1 pin 146;
X2 pin 145;
Y1I pin 169;
Y1O pin 168 istype 'com';
Y1EN pin 158 istype 'com';
Y2I pin 170;
Y2O pin 162 istype 'com';
Y2EN pin 159 istype 'com';
equations


"Reference Clock"
"---------------"

"The reference clock is exactly 30.768 kHz, and we use it for"
"our longer time measurements."

declarations
RCK node istype 'reg';
equations

RCK.clk = DCK;
RCK := ARCK;


"Time Stamp"
"----------"

declarations
STAMP23..STAMP0 node istype 'reg'; "Time Stamp"
timestamp=[STAMP23..STAMP0];
tsb0=[STAMP7..STAMP0];
tsb1=[STAMP15..STAMP8];
tsb2=[STAMP23..STAMP16];
TSC1..TSC0 node istype 'com,keep'; "Time Stamp Carry"
TSS1..TSS0 node istype 'reg'; "Time Stamp State"
tss=[TSS1..TSS0];
TSCNT node istype 'com,keep'; "Time Stamp Continue"
TSCC1..TSCC0 node istype 'reg'; "Time Stamp Clock Control"
tscc=[TSCC1..TSCC0];
SCREST node istype 'com,keep'; "Storage Controller Rest"
equations

"We increment the timestamp only when the Storage Controller"
"is at rest. Otherwise we might increment the timestamp half-way"
"through storing a clock message, or half-way through storing"
"a transmitter message. In that case, the message would have"
"timestamp zero before the clock message marking the return"
"of the lower byte of the timestamp to zero has itself been stored"
"in memory."
tscc.clk = DCK;
tscc.aclr = RESET;
state_diagram tscc;
  state 0:if RCK then 1 else 0; "TSCC1 is low"
  state 1:if SCREST then 2 else 1; "TSCC1 stays low"
  state 2:goto 3; "TSCC1 goes high"
  state 3:if !RCK then 0 else 3; "TSCC1 stays high"
equations;

"We clock the timestamp with TSCC1. We cannot increment the"
"timestamp unless the Storage Controller is at rest. In order"
"to maintain the count of RCK rising edges, the Storage"
"Controller must return to its rest state within 30 us of each"
"rising edge of RCK."
timestamp.clk = TSCC1;
timestamp.aclr = RESET;
tsb0:=tsb0+1;
TSC0=(tsb0==255);
when TSC0 then tsb1:=tsb1+1;
else tsb1:=tsb1;
TSC1=(tsb1==255);
when TSC0 & TSC1 then tsb2:=tsb2+1;
else tsb2:=tsb2;

"When the timestamp returns to zero, we request that the"
"Storage Controller transfer a clock message to the"
"Message Router."
tss.clk = DCK;
tss.aclr = RESET;
state_diagram tss;
  state 0:if tsb0==0 then 1 else 0;
  state 1:if TSCNT then 2 else 1;
  state 2:if tsb0==0 then 2 else 0;
equations;

"The Slow Clock we pass to the Message Router is 2.048 kHz. This"
"clock is used to flash display lamps."
SCK = STAMP3;


"Message Decoders"
"----------------"

"The message decoders are defined in a separate ABEL file as"
"a module. We can substitute the generator code for the decoder"
"so as to generate an ascending-value series of messages with"
"sufficient frequency for good viewing on an analog scope."

declarations
decoder interface (Q, CNT, CK, RST, S -> RDY, M);
generator interface (Q, CNT, CK, RST, S -> RDY, M);
decoder1 functional_block decoder;
decoder2 functional_block decoder;
decoder3 functional_block decoder;
decoder4 functional_block decoder;
decoder5 functional_block decoder;
decoder6 functional_block decoder;
decoder7 functional_block decoder;
decoder8 functional_block decoder;
equations

decoder1.Q = Q1;
decoder1.CK = DCK;
decoder1.RST = RESET;
decoder2.Q = Q2;
decoder2.CK = DCK;
decoder2.RST = RESET;
decoder3.Q = Q3;
decoder3.CK = DCK;
decoder3.RST = RESET;
decoder4.Q = Q4;
decoder4.CK = DCK;
decoder4.RST = RESET;
decoder5.Q = Q5;
decoder5.CK = DCK;
decoder5.RST = RESET;
decoder6.Q = Q6;
decoder6.CK = DCK;
decoder6.RST = RESET;
decoder7.Q = Q7;
decoder7.CK = DCK;
decoder7.RST = RESET;
decoder8.Q = Q8;
decoder8.CK = DCK;
decoder8.RST = RESET;


"Message Selector"
"----------------"

"The Message Selector has to select one of the Message Decoders"
"and read out its message. There may be only one decoder with a"
"message available, in which case our selection is simple. But"
"with eight independent decoders, we may have all eight of them"
"receiving the same message, and asserting their RDY outputs at"
"the same time, or within one clock cycle of one another. In"
"this case, the Message Selector chooses the lowest-numbered"
"decoder with a message available, and does not change its"
"selection until this message has been read out and transferred"
"to the Message Router. The selection takes place when the"
"Storage Controller, which performs the transfers, is in its"
"rest state."

"The Message Selector must read out the message one bit at"
"a time. Serial exchanges are far more efficient in their use"
"of registers and AND-arrays than parallel exchanges. The"
"Storage Controller initiates this serial exchange with the"
"FETCH signal, and the Message Selector organises the shifting"
"of the message into the M19..M0 with the help of the fetch"
"shift state machine and the SHIFT signal."

"The Message Selector directs the MDCNT signal from the Storage"
"Controller to the correct Message Decoder."

"The Message Selector retains the value of the previous message"
"so long as another Message Decoder has a message to present."
"If this next message is identical to the previous message, the"
"Message Selector asserts MATCH, which tells the Storage Controller"
"that it should assert MDCNT but not transfer the message."

"In future versions of the code, we will implement a more efficient"
"and far-reaching detection of duplicates. So long as the detection"
"of duplicates spans only the period for which MDRDY is asserted"
"continuously, we can be certain that we should not store two"
"messages from the same channel number, unless that channel number"
"is 15, in which case we make an exception for slow data messages"
"on the same channel from multiple transmitters."

declarations
MIN node istype 'com,keep';
M19..M0 node istype 'reg,keep';
message = [M19..M0];
MDRDY node istype 'com,keep';
MDCNT node istype 'com,keep';
SHIFT node istype 'com,keep';
FETCH node istype 'com,keep';
FDONE node istype 'com,keep';
FS4..FS0 node istype 'reg';
fss = [FS4..FS0];
MSEL2..MSEL0 node istype 'reg';
msel = [MSEL2..MSEL0];
sel_1 = 0;
sel_2 = 1;
sel_3 = 2;
sel_4 = 3;
sel_5 = 4;
sel_6 = 5;
sel_7 = 6;
sel_8 = 7;
MATCH node istype 'reg,keep,pos';
equations


msel.clk = DCK;
msel.aclr = RESET;
when SCREST then {
  when decoder1.RDY then msel := sel_1
  else when decoder2.RDY then msel := sel_2
  else when decoder3.RDY then msel := sel_3
  else when decoder4.RDY then msel := sel_4
  else when decoder5.RDY then msel := sel_5
  else when decoder6.RDY then msel := sel_6
  else when decoder7.RDY then msel := sel_7
  else when decoder8.RDY then msel := sel_8
  else msel := sel_1;
} else {
  msel := msel;
}

when msel == sel_1 then MIN = decoder1.M;
when msel == sel_2 then MIN = decoder2.M;
when msel == sel_3 then MIN = decoder3.M;
when msel == sel_4 then MIN = decoder4.M;
when msel == sel_5 then MIN = decoder5.M;
when msel == sel_6 then MIN = decoder6.M;
when msel == sel_7 then MIN = decoder7.M;
when msel == sel_8 then MIN = decoder8.M;

MATCH.clk = DCK;
fss.clk = DCK;
fss.aclr = RESET;
when fss == 0 then {
  when FETCH then fss:=1 else fss:=0;
  MATCH := 1;  
} 
when (fss>=1) & (fss<=20) then {
  fss:=fss+1;
  when MIN != M19 then MATCH := 0
  else MATCH := MATCH
}
when (fss>=21) then {
  when !FETCH then fss:=0 else fss:=21;
  MATCH := MATCH;
}

SHIFT = (fss>=1) & (fss<=20);
FDONE = (fss==21);

message.clk = !DCK;
message.aclr = !MDRDY;
when SHIFT then { 
  [M19..M0] := [M18..M0,MIN];
} else {
  message:=message;
}

decoder1.CNT = (msel == sel_1) & MDCNT;
decoder2.CNT = (msel == sel_2) & MDCNT;
decoder3.CNT = (msel == sel_3) & MDCNT;
decoder4.CNT = (msel == sel_4) & MDCNT;
decoder5.CNT = (msel == sel_5) & MDCNT;
decoder6.CNT = (msel == sel_6) & MDCNT;
decoder7.CNT = (msel == sel_7) & MDCNT;
decoder8.CNT = (msel == sel_8) & MDCNT;

decoder1.S = (msel == sel_1) & SHIFT;
decoder2.S = (msel == sel_2) & SHIFT;
decoder3.S = (msel == sel_3) & SHIFT;
decoder4.S = (msel == sel_4) & SHIFT;
decoder5.S = (msel == sel_5) & SHIFT;
decoder6.S = (msel == sel_6) & SHIFT;
decoder7.S = (msel == sel_7) & SHIFT;
decoder8.S = (msel == sel_8) & SHIFT;

MDRDY = decoder1.RDY
  # decoder2.RDY
  # decoder3.RDY
  # decoder4.RDY
  # decoder5.RDY
  # decoder6.RDY
  # decoder7.RDY
  # decoder8.RDY;


"Storage Controller"
"------------------"

"The Storage Controller provides the process that transfers"
"byte to the Message Router. It transfers the four bytes of"
"a clock message whenever a new clock message is ready. It"
"waits for a new message to be fetched from its Message Decoder"
"and transfers the message one byte at a time."

declarations
SCS3..SCS0 node istype 'reg'; "Storage Controller State"
scs=[SCS3..SCS0];
equations

"The state names for the Storage Controller."
declarations
  scs_rest = 0;
  scs_clock_id = 1;
  scs_clock_hi = 2;
  scs_clock_mid = 3;
  scs_clock_fv = 4;
  scs_clock_done = 5;
  scs_message_fetch = 6;
  scs_message_id = 7;
  scs_message_hi = 8;
  scs_message_lo = 9;
  scs_message_ts = 10;
  scs_message_done = 11;
equations

"The Storage Controller transfers clock messages and transmitter"
"messages to the Message Router. It transfers clock messages in preference"
"to transmitter messages, but clock messages occur only once every"
"256 cycles of RCK, so they are rare compared to transmitter messages,"
"which occur 64 cycles of RCK for 512 SPS, and there may be fourteen"
"transmitters running at once. Note that the Storage Controller always"
"uses the current value of the time stamp lower byte when it transfers"
"a message to the Message Router."
scs.clk = DCK;
scs.aclr = RESET;
state_diagram scs;
  "In the rest state, we are waiting for a message to handle."
  state scs_rest:
    if (tss==1) then scs_clock_id 
    else if MDRDY then scs_message_fetch
    else scs_rest;

  "We transfer the clock id, high byte of timestamp, middle byte of timestamp"
  "and the firmware version number that constitute a clock message.:
  state scs_clock_id:if MDS then scs_clock_hi else scs_clock_id; 
  state scs_clock_hi:if MDS then scs_clock_mid else scs_clock_hi;
  state scs_clock_mid:if MDS then scs_clock_fv else scs_clock_mid; 
  state scs_clock_fv:if MDS then scs_clock_done else scs_clock_fv;

  "We have transferred the clock message, so indicate to the timestamp counter"
  "that it can continue counting up."
  state scs_clock_done:goto scs_rest;

  "We fetch the message from the message decoder."
  state scs_message_fetch:
    if FDONE & !MATCH then scs_message_id;
    if FDONE & MATCH then scs_message_done;
    if !FDONE then scs_message_fetch;

  "We transfer the message id, high byte of data, low byte of data, and the"
  "low byte of the timestamp that constitute a transmitter message."
  state scs_message_id:if MDS then scs_message_hi else scs_message_id;
  state scs_message_hi:if MDS then scs_message_lo else scs_message_hi;
  state scs_message_lo:if MDS then scs_message_ts else scs_message_lo;
  state scs_message_ts:if MDS then scs_message_done else scs_message_ts;

  "We are done with the message, so indicate to the decoder that produced the"
  "message that it can continue detecting further messages."
  state scs_message_done:goto scs_rest;
equations

"Fetch message out of the Message Decoder."
FETCH = (scs==scs_message_fetch);

"Tell the Message Decoder to continue."
MDCNT = (scs==scs_message_done);

"Tell the timestamp that we have transferd the clock"
"message"
TSCNT = (scs==scs_clock_done);

"We indicate that the storage controller is not at rest, so"
"the timestamp controller can refrain from incrementing the"
"timestamp."
SCREST = (scs==scs_rest);

"The Message Ready bit indicates to the Message Router that we"
"have a byte to store in RAM."
MRDY = (scs == scs_clock_id) 
  # (scs == scs_clock_hi)
  # (scs == scs_clock_mid)
  # (scs == scs_clock_fv)
  # (scs == scs_message_id)
  # (scs == scs_message_hi)
  # (scs == scs_message_lo)
  # (scs == scs_message_ts);


"Fake Message Data"
"-----------------"

"If we have problems with a Data Receiver, we can track them down with"
"the help of the fake message data, which is activated by the fake message"
"data constant."

declarations
FMD0..FMD7 node istype 'reg,pos'; "Fake Message Data"
fmd=[FMD7..FMD0];
equations

"The Fake Message Data is what we send to the Message Router instead"
"of real data to test if writing and reading from RAM are 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."
fmd.clk = DCK;
fmd.aclr = RESET;
when MDS then fmd:=fmd+1 else fmd:=fmd;


"Byte Multiplexer"
"----------------"

"Here we select which bytes to assert on the message data."
"Note that a bug in the ABEL compiler means that the code"
"does not compile properly if you make an outer conditional"
"with !fake_message_data and a sequence of inner conditionals"
"with the state vector. Instead, we have to put the fake"
"message conditional inside the state vector conditional, and"
"the code compiles correctly."
when (scs==scs_clock_id) then { "Clock Message ID"
  when fake_message_data then message_data=fmd
  else message_data = 0; 
}
when (scs==scs_clock_hi) then { "High Byte of Timestamp"
  when fake_message_data then message_data=fmd
  else message_data = tsb2; 
}
when (scs==scs_clock_mid) then { "Middle Byte of Timestamp"
  when fake_message_data then message_data=fmd
  else message_data = tsb1; 
}
when (scs==scs_clock_fv) then {  "Firmwave Version"
  when fake_message_data then message_data=fmd
  else message_data = firmware_version;
}
when (scs==scs_message_id) then { "Message ID"
  when fake_message_data then message_data=fmd
  else message_data = [0,0,0,0,M19..M16]; 
}
when (scs==scs_message_hi) then { "High Byte of Sample"
  when fake_message_data then message_data=fmd
  else message_data = [M15..M8]; 
}
when (scs==scs_message_lo) then { "Low Byte of Sample"
  when fake_message_data then message_data=fmd
  else message_data = [M7..M0]; 
}
when (scs==scs_message_ts) then { "Low Byte Timestamp"
  when fake_message_data then message_data=fmd
  else message_data = tsb0; 
}


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

"These are prototype equations for the Message Detector Code that"
"will be received on the auxilliary Display Board, there to cause"
"lights to flash. Here we have code that sends eight bits containing"
"the selected decoder number, so that we can flash lights that"
"indicate which antennas are receiving messages."

declarations
  DCS3..DCS0 node istype 'reg';
  dcs = [DCS3..DCS0];
equations

dcs.clk = DCK;
when dcs==0 then {
  when FETCH then dcs:=1 else dcs:=0;
}
when (dcs<=1) & (dcs<=9) then dcs:=dcs+1;
when dcs>=10 then {
  when FETCH then dcs:=10 else dcs:=0;
}

when dcs==0 then MDC = 0;
when dcs==1 then MDC = 1;
when dcs==2 then MDC = 0;
when dcs==3 then MDC = 0;
when dcs==4 then MDC = 0;
when dcs==5 then MDC = 0;
when dcs==6 then MDC = 0;
when dcs==7 then MDC = MSEL2;
when dcs==8 then MDC = MSEL1;
when dcs==9 then MDC = MSEL0;
when dcs==10 then MDC = 0;


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

TP3 = 0;
TP4 = FETCH;
TP6 = M0;


end