"
module P2100A

title 'P2100A'

"Version 2: [09-JAN-08] We add connections for the
"analog multiplexer and ADCs. We remove the message
"receiver code of P3007C04, which we don't need. Add
"Instruction Processor and Analog Multiplexer."

"Version 1: [27-DEC-07] This is the P3007C04 code, modified 
"to account for the new pin assignments in the A2100, but
"not including the new outputs that drive the CMOS switches. 
"We set the A3007C's comparator input (C) to zero, so the 
"firmware will receive no messages, and store only timestamps.
"We set the message clock equal to the data clock, and use an 
"80-MHz clock input to generate the data clock and synchronise 
"the reference clock.

declarations
  firmware_version=1;
  min_sync_edges=5;
  num_message_bits=24;
  fake_data=0;
  max_transmission_time=4; "30 us periods of RCK"
equations

"Pins"
declarations
A pin 3; "LVDS input"
B pin 10 istype 'com'; "LVDS output"
C=0; "Comparator Output"
LB pin 8 istype 'com'; "Loop Back"
!RESET pin 22;"Hardware Reset"			
ARCK pin 38; "Asynchronous 32.768 kHz reference clock input"
FCK pin 39; "Fast Clock 80 MHz."
!RW pin 59 istype 'com'; "RAM Write"
!RCE pin 66 istype 'reg'; "RAM Chip Enable"
!ROE pin 6 istype 'com'; "RAM Output Enable"
RA18..RA0 pin 85,80,79,78,16,17,19,31,30,53,
  54,55,56,58,67,69,70,71,72 istype 'com'; "RAM Address"
ram_addr = [RA18..RA0];
RD7..RD0 pin 9,11,14,15,60,61,64,65 istype 'com'; "RAM Data"
ram_data = [RD7..RD0];
RECEIVE pin 97 istype 'reg'; "Receive Indicator, through monostable"
UPLOAD pin 94 istype 'com'; "Upload Indicator, through monostable"
EMPTY pin 98 istype 'com'; "Empty Indicator, direct to LED"
TP1 pin 47 istype 'com'; "Test Point 1"
TP2 pin 48 istype 'com'; "Test Point 2"
SS1 pin 41 istype 'com'; "Serial Select ADC 1"
SCK1 pin 42 istype 'com'; "Serial Clock ADC 1"
SDI1 pin 43 istype 'com'; "Serial Data In ADC 1"
SDO1 pin 44; "Serial Data Out ADC 1"
SS2 pin 35 istype 'com'; "Serial Select ADC 2"
SCK2 pin 34 istype 'com'; "Serial Clock ADC 2"
SDI2 pin 36 istype 'com'; "Serial Data In ADC 2"
SDO2 pin 28; "Serial Data Out ADC 2"
SVR1 pin 84 istype 'reg'; "Select ADC 1 Voltage Reference"
SVA1 pin 50 istype 'reg'; "Select ADC 1 Voltage Analog"
SVL1 pin 49 istype 'reg'; "Select ADC 1 Voltage Logic"
SVR2 pin 86 istype 'reg'; "Select ADC 2 Voltage Reference"
SVA2 pin 87 istype 'reg'; "Select ADC 2 Voltage Analog"
SVL2 pin 93 istype 'reg'; "Select ADC 2 Voltage Logic"
ON pin 29 istype 'reg'; "WAKE, turns on fixed voltages"
SVB pin 92 istype 'reg'; "Select Voltage Bottom Reference"
SVT pin 81 istype 'reg'; "Select Voltage Top Reference"
equations


"Data Clock Generation"
"---------------------"

declarations
DCK node istype 'reg'; "Data Clock"
equations

"We divide the 80 MHz clock by two to create"
"the data clock."
DCK.clk=FCK;
DCK:=!DCK;

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

declarations
RCK node istype 'reg'; "Reference Clock"
equations

"We synchronise the incoming 32.768 kHz clock"
"to DCK to create RCK."
RCK.clk=DCK;
RCK:=ARCK;


"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"
ATR node istype 'com'; "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 rising 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 driver 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;


"Instruction Processor"
"---------------------"

declarations
IS node istype 'com'; "Instruction Strobe"
I7..I0 node istype 'com'; "Instruction"
instruction = [I7..I0];
opcode = [I7..I4];
opvalue = [I3..I0];
nop_instruction = 0;
start_instruction = 1;
reset_instruction = 2;
on_instruction = 3;
off_instruction = 4;
csel_op = 1;
sr_op = 2;
ns_op = 3;
equations

"When we receive a command with DC6 (called DRX in data"
"devices like this) set to 1, we execute DC16..DC9 (called"
"I7..I0 in the A2100) as an instruction. The IS (instruction"
"strobe) signal provokes execution. We use Q6 instead of DC6"
"in the strobe equation because Q6 is valid on the rising edge"
"of CS, but DC6 is clocked some time during the assertion of"
"CS."
IS = CS & Q6;

"The instruction bits are Q16 down to Q9. We don't use"
"the latched bits DC16 down to DC9 for the same reason"
"we don't use DC6 in IS."
[I7..I0] = [Q16..Q9];


"Fixed Voltages"
"--------------"

ON.ap = RESET;
ON.clk = IS;
when (instruction == on_instruction) then ON := 1;
else when (instruction == off_instruction) then ON := 0;
else when (instruction == reset_instruction) then ON := 1;
else ON := ON;


"Analog Multiplexer"
"------------------"


[SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVB,SVT].aclr = RESET;
[SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVB,SVT].clk = IS;

when (opcode == csel_op) then {
  SVB  := (opvalue == 0);
  SVT  := (opvalue == 1);
  SVR1 := (opvalue == 2);
  SVA1 := (opvalue == 3);
  SVL1 := (opvalue == 4);
  SVR2 := (opvalue == 5);
  SVA2 := (opvalue == 6);
  SVL2 := (opvalue >= 7);
} else {
  [SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVB,SVT] 
  :=
  [SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVB,SVT]
}


"Sample Session"
"--------------"

SS1 = RCK;
SS2 = RCK;


"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"
TB7..TB0 node istype 'reg'; "Transmission Bits"
ts=[TS4..TS0];"Transmission State"
tb=[TB7..TB0]; "Transmission Byte"
TBL node istype 'reg'; "Transmitter Byte Load"
TBO node istype 'com,keep'; "Transmitter Bit Out"
TBFD1,TBFD0 node istype 'reg'; "TB Fake Data Counter"
tbfd=[TBFD1,TBFD0];
equations

"We assert Transmit Byte Load, TBL, elsewhere in the code"
"when we want to clock ram_data.pin into the Transmit Byte."
TBL.clk = DCK;
TBL.aclr = RESET; 

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

"The Transmitter State, ts, controls serial transmission"
"to the LWDAQ driver of the Transmi 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;"TB7"
  state 5:goto 6;"TB7"
  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;"TB0"
  state 19:goto 20;"TB0"
  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)  & TB7
  # (ts==5)  & TB7
  # (ts==6)  & TB6
  # (ts==7)  & TB6
  # (ts==8)  & TB5
  # (ts==9)  & TB5
  # (ts==10) & TB4
  # (ts==11) & TB4
  # (ts==12) & TB3
  # (ts==13) & TB3
  # (ts==14) & TB2
  # (ts==15) & TB2
  # (ts==16) & TB1
  # (ts==17) & TB1
  # (ts==18) & TB0
  # (ts==19) & TB0
  # (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_data then {
  tb.clk = DCK;
  tb.aclr = RESET;
  when TBL then tb:=ram_data.pin;
  else tb:=tb;
}

"We can generate fake data to check for errors in the"
"upload to the LWDAQ driver, as opposed to errors in"
"RF reception. The Recorder instrument will interpret"
"the fake data as a time stamp."
tbfd.clk=DCK;
tbfd.aclr=RESET;
when fake_data then {
  TBL=1;
  when (ts==20) then tbfd:=tbfd+1
  else tbfd:=tbfd;
  when (tbfd==0) then tb:=^h05;
  when (tbfd==1) then tb:=^hAA;
  when (tbfd==2) then tb:=^hFF;
  when (tbfd==3) then tb:=^d0;
}

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

declarations
SA18..SA0 node istype 'reg'; "Data 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'; "Data Address Carry"
SAI node istype 'reg'; "Data Address Increment"
TX18..TX0 node istype 'reg'; "Data Address"
transmit_addr = [TX18..TX0];
txb0=[TX7..TX0]; "Transmit address byte zero"
txb1=[TX15..TX8]; "Transmit address byte one"
txb2=[TX18..TX16]; "Transmit address byte two"
TXC0,TXC1 node istype 'com,keep'; "Transmit Address Carry"
TXI node istype 'reg'; "Data 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);
SAI.clk = DCK;
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;
TXC0 = (txb0==^hFF);
TXC1 = (txb1==^hFF);
TXI.clk = DCK;
when TXI then {
  txb0 := txb0+1;
  when TXC0 then txb1 := txb1+1;
  else txb1 := txb1;
  when TXC1 & TXC0 then txb2 := txb2+1;
  else txb2 := txb2;
} else {
  transmit_addr := transmit_addr;
}

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


"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"
TSCC1..TSCC0 node istype 'reg'; "Time Stamp Clock Control"
tscc=[TSCC1..TSCC0];
RCREST node istype 'com'; "RAM Controller Rest"
TSS1..TSS0 node istype 'reg'; "Time Stamp State"
tss=[TSS1..TSS0];
CSTORED node istype 'com'; "Clock Stored"
equations

"We increment the timestamp only when the RAM controller"
"state is zero (at rest). Otherwise we might increment"
"the timestamp half way through storing it, or we might"
"increment the timestamp to zero while a non-clock message"
"is being stored. In that case, the message would have"
"timestamp zero, but the clock message marking the return"
"to timestamp zero has not yet 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 RCREST 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."
timestamp.clk = TSCC1;
timestamp.aclr = ATR;
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 immediately"
"request that the RAM controller store a timestamp."
"That's why we use !DCK to clock the timestamp state."
"When the timestamp becomes zero on the rising edge of"
"DCK, tss becomes 1 on the falling edge, so the RAM"
"controller receives tss==1 on the next rising edge"
"of DCK. If a non-clock message is waiting to be"
"stored, the RAM controller will ignore the non-clock"
"message until it has stored a new clock message."
tss.clk = !DCK;
tss.aclr = RESET;
state_diagram tss;
  state 0:if tsb0==0 then 1 else 0;
  state 1:if CSTORED then 2 else 1;
  state 2:if tsb0==0 then 2 else 0;
equations;


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

declarations
RDOE node istype 'com'; "RAM Data Output Enable (from this chip)"
RCS4..RCS0 node istype 'reg'; "Ram Controller State"
rcs=[RCS4..RCS0];
equations

"The RAM Controller responds to the timestamp state"
"in preference to the receiver state, and the receiver"
"state in preference to the LWDAQ transmitter state."
"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 (tss==1) then 9 
    else if (ts==1) & !AE then 7
    else 0;
  state 7:goto 8;   "load transmit byte"
  state 8:goto 0;   "increment transmit counter"
  state 9:goto 10;  "store clock ID"
  state 10:goto 11; "increment storage address"
  state 11:goto 12; "store high timestamp byte"
  state 12:goto 13; "increment storage address"
  state 13:goto 14; "store middle timestamp byte"
  state 14:goto 15; "increment storage address"
  state 15:goto 16; "store firmware version"
  state 16:goto 0;  "increment storage address"
  state 17:goto 18; "store low timestamp byte"
  state 18:goto 0; "increment storage address"
equations

"Tell the timestamp that we have stored the clock"
"message"
CSTORED = (rcs==9);

"Tell the timestamp clock that the RAM controller is"
"at rest."
RCREST = (rcs==0);

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

when (rcs==0) then {
  ram_addr = store_addr
  ram_data = 0;
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
} 
when (rcs==7) then {
  ram_addr = transmit_addr;
  ram_data = 0;
  RW = 0;
  ROE = 1;
  RCE := 1;
  SAI := 0;
  TXI := 0;
  TBL := 1;
  RDOE = 0;
}
when (rcs==8) then {
  ram_addr = transmit_addr;
  ram_data = 0;
  RW = 0;
  ROE = 1;
  RCE := 0;
  SAI := 0;
  TXI := 1;
  TBL := 0;
  RDOE = 0;
}
when (rcs==9) then {
  ram_addr = store_addr;
  ram_data = 0; "Clock Message ID"
  RW = 1;
  ROE = 0;
  RCE := 1;
  SAI := 1;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==10) then {
  ram_addr = store_addr;
  ram_data = 0; "Clock Message ID"
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==11) then {
  ram_addr = store_addr;
  ram_data = tsb2; "High Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 1;
  SAI := 1;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==12) then {
  ram_addr = store_addr;
  ram_data = tsb2; "High Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==13) then {
  ram_addr = store_addr;
  ram_data = tsb1; "Middle Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 1;
  SAI := 1;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==14) then {
  ram_addr = store_addr;
  ram_data = tsb1; "Middle Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==15) then {
  ram_addr = store_addr;
  ram_data = firmware_version; "firmware_version"
  RW = 1;
  ROE = 0;
  RCE := 1;
  SAI := 1;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==16) then {
  ram_addr = store_addr;
  ram_data = firmware_version; "firmware_version"
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==17) then {
  ram_addr = store_addr;
  ram_data = tsb0; "Low Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 1;
  SAI := 1;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}
when (rcs==18) then {
  ram_addr = store_addr;
  ram_data = tsb0; "Low Byte of Timestamp"
  RW = 1;
  ROE = 0;
  RCE := 0;
  SAI := 0;
  TXI := 0;
  TBL := 0;
  RDOE = 1;
}


"Indicators Lamps"
RECEIVE.clk = DCK;
RECEIVE := 0;
UPLOAD = DS;
EMPTY = AE;

"Test Points"
TP1 = CS;
TP2 = IS;
end