"
module P2060

title 'P2060'

"(C) Kevan Hashemi 2012"

declarations

"Version 1"

"[12-JAN-12] First version. We select test points that allow us to"
"watch how effective the randomizer is, and also to trigger at the"
"beginning of each interval and pulse."

"Constants"
clocks_per_ms = 40000;

"Pins"
A pin 12;"LVDS input"
B pin 64 istype 'com';"LVDS output"
!RESET pin 37;"RESET"           
CK pin 38;"40 MHz clock input"
WAKE pin 66 istype 'com';"WAKE"
LB pin 65 istype 'com';"Loop Back, enables LVDS driver"
TP1..TP4 pin 69,70,71,72 istype 'com';"
LED16..LED1 pin 41..44,47..50,53..56,58..61 istype 'com';
DACIN pin 3 istype 'com'; "DAC Data In, IO1"
DACCK pin 4 istype 'com'; "DAC Serial Clock, IO2"
!DACCS pin 5 istype 'com'; "DAC Chip Select, IO3"
DACFS pin 6 istype 'com'; "DAC Frame Sync, IO4"
LAC pin 8 istype 'com'; "Lamp A Control, IO5"
IO6 pin 9 istype 'com'; "IO6"
LAO pin 10 istype 'com'; "Lamp A On, IO7"
IO8 pin 11 istype 'com'; "IO8"
PWA pin 14 istype 'com'; "Power and Activity, IO9"
LBC pin 15 istype 'com'; "Lamp B Control, IO10"

"Nodes"               
SA node istype 'reg';"Synchornized A."
DA node istype 'com';"Delayed SA"
DDA node istype 'com';"Delayed Delayed SA"
ACTIVE node istype 'reg';"transmission active"
D1..D9 node istype 'reg';"delay pipeline."
DRS0..DRS2 node istype 'reg';"Command Receiver State"
CS node istype 'com';"Command Strobe"
NCS node istype 'com';"New Command Strobe"
AS node istype 'com';"Address Strobe"
NAS node istype 'com';"New Address Strobe"
DS node istype 'com';"Data Strobe"
ER,Q1..Q16 node istype 'reg';"Receiver Bits"
DA0..DA15 node istype 'reg';"Device Address Bits"
DC1..DC16 node istype 'reg';"Device Command Bits"

"Sets"
drs=[DRS2..DRS0];"Command Receiver State"

equations


"Serial Input Decoding"
"---------------------"

"We synchronize the incoming LVDS logic signal to"
"our 40-MHz clock."
SA:=A;
SA.clk=CK;

"We put SA through a pipeline of registers clocked"
"with CK so that we can generate the delayed timing"
"pulses from the rising edge of SA."
[D1..D9]:= [SA,D1..D8];
[D1..D9].clk= CK;
[D1..D9].aclr=RESET;

"Delayed SA provides is asserted for one CK period 125 ns"
"after any rising edge of SA. We use DA and SA to obtain"
"the LWDAQ data bit. If SA is high with DA, the data bit"
"is one."
DA = D4 & !D5;

"Delayed Delayed SA is asserted for one CK period 250 ns"
"after any rising edge of SA. We use DDA and SA to obtain"
"the LWDAQ ACTIVE bit. If SA is low with DDA, ACTIVE is"
"true."
DDA = D8 & !D9;

"We assert ACTIVE whenever the driver is transmitting"
"a command data bit."
ACTIVE.clk=CK;
ACTIVE.aclr=RESET;
when !SA & DDA then ACTIVE:=1;
when SA & DDA then ACTIVE:=0;
when !DDA then ACTIVE:=ACTIVE;

"We clock the receiver shift register and the entry"
"register with CK, and we clear them on RESET."
[ER,Q1..Q16].clk=CK;
[ER,Q1..Q16].aclr=RESET;

"We shift the receiver bits whenever we have DA"
"asserted. We clock the current value of SA into"
"the entry register (ER), and shift all the other"
"bits over by one. At the beginning of a LWDAQ"
"transmission, ER contains a 1 if the transmission"
"is a command, and 0 if it is an address. At the"
"end of a transmission, ER contains a 1, and Q1"
"to Q16 contain the transmitted sixteen-bit word,"
"either address or command."
when DA then [ER,Q1..Q16]:=[SA,ER,Q1..Q15];
else [ER,Q1..Q16]:=[ER,Q1..Q16].fb;


"Data Receiver"
"-------------"

"Data Receiver states."
declarations

rest=0;
command_receive=1;
clock_command_register=2;
address_receive=3;
clock_address_register=4;
new_command_strobe=5;
new_address_strobe=6;

equations

drs.clk=CK;
drs.aclr=RESET;

state_diagram drs;
  "Stay in the rest state until we receive ACTIVE."
  "When ACTIVE, we proceed with command receive"
  "if the data bit in ER is one, otherwise an address"
  "receive."
  state rest:
    if ACTIVE then {
      if ER then command_receive
      else address_receive;
   } else rest;

  "We stay in command_receive until !ACTIVE."
  state command_receive:
    if !ACTIVE then clock_command_register
    else command_receive;

  "As we pass through clock_command_register we"
  "indicate that it is time to clock the receiver"
  "bits into the command register."
  state clock_command_register:goto new_command_strobe;

  "As we pass through new_command_strobe we start"
  "any action that should be taken when the new command"
  "arrives. The variable NCS is true when drs is in"
  "the new_command_strobe state."
  state new_command_strobe:goto rest;

  "We stay in address_receive until !ACTIVE."
  state address_receive:
    if !ACTIVE then clock_address_register;
    else address_receive ;

  "As we pass through clock_address_register we"
  "indicate that it is time to clock the receiver"
  "bits into the address register."    
  state clock_address_register:goto new_address_strobe;   

  "As we pass through new_address_strobe we start"
  "any action that should be taken when the new address"
  "arrives. The variable NAS is true when drs is in"
  "the new_address_strobe state."
  state new_address_strobe:goto rest;
equations


"Command Strobe is asserted for one CK period at the"
"end of a command transmission from the LWDAQ driver."
CS = (drs==clock_command_register);

"New Command Strobe follows CS when the new command"
"is already established in the DC registers."
NCS = (drs==new_command_strobe);

"Address Strobe is asserted for one CK period at the"
"end of an address transmission from the LWDAQ driver."
AS = (drs==clock_address_register);

"New Address Strobe follows AS when the new address"
"is already established in the DA registers."
NAS = (drs==new_address_strobe);

"Data Strobe is asserted for one CK period after a"
"solitary low pulse from the LWDAQ driver. The driver"
"uses solitary low pulses that endure for 125 ns and"
"are followed by a > 375 ns high pulse to initiate"
"serial transmission of data from LWDAQ devices of type"
"data_device, like this one."
DS = (SA & DDA & (drs==rest));

"We clock the receiver bits into the command register"
"on CS."
[DC1..DC16].clk=CK;
[DC1..DC16].aclr=RESET;
when CS then [DC1..DC16]:=[Q1..Q16]
else [DC1..DC16]:=[DC1..DC16];

"We clock the receiver bits into the address register"
"on AS."
[DA0..DA15].clk=CK;
[DA0..DA15].aclr=RESET;
when AS then [DA0..DA15]:=[Q1..Q16]
else [DA0..DA15]:=[DA0..DA15].fb;

"Wake the board with DC8."
WAKE = DC8;

"Loop back with DC7.."
LB = DC7;

"Loop back A to B for loopback job."
B=A;


"Operation Codes"
"---------------"

declarations
opcode=[DC4..DC1];"Operation Code"
clear_settings=0;
start_stimulus=1;
set_polarity=2;
set_brightness=3;
set_pulse_length_hi=4;
set_pulse_length_lo=5;
set_interval_length_hi=6;
set_interval_length_lo=7;
set_stimulus_length_hi=8;
set_stimulus_length_lo=9;
enable_randomizer=10;
RUN node istype 'reg,keep'; "Generate Stimulus"
SLCTR15..SLCTR0 node istype 'reg,keep'; "Stimulus Length Counter"
slctr=[SLCTR15..SLCTR0];
SLCTRZ node istype 'com,keep'; "Stimulus Length Counter Zero"
SLC15..SLC0 node istype 'reg,keep'; "Stimulus Length Code"
SLCZ node istype 'com,keep'; "Stimulus Length Code Zero"
slc=[SLC15..SLC0];
CLR node istype 'com,keep'; "Clear"
ICK0..ICK15 node istype 'reg,keep'; "Interval Clock Bits"
ick=[ICK15..ICK0];
ICKP node istype 'com,keep'; "Interval Clock Pulse"
ILC15..ILC0 node istype 'reg,keep'; "Interval Length Code"
ilc=[ILC15..ILC0];
RD14..RD0 node istype 'reg,keep'; "Random Delay Bits"
rdw=[RD14..RD0];
RWCS3..RWCS0 node istype 'reg,keep'; "Random Word Control State"
rwcs=[RWCS3..RWCS0];
ILT15..ILT0 node istype 'reg,keep'; "Interval Length Timer"
ilt=[ILT15..ILT0];
!LOP node istype 'com,keep'; "Lamp On Pulse"
!IEP node istype 'com,keep'; "Interval End Pulse"
PCK0..PCK15 node istype 'reg'; "Pulse Clock Bits"
pck=[PCK15..PCK0];
PCKP node istype 'com,keep'; "Pulse Clock Pulse"
PLT15..PLT0 node istype 'reg,keep'; "Pulse Length Timer"
plt=[PLT15..PLT0];
PLC15..PLC0 node istype 'reg,keep'; "Pulse Length Code "
plc=[PLC15..PLC0];
!LON node istype 'com,keep'; "Lamp On"
DACS0..DACS4 node istype 'reg,keep'; "DAC State Nodes"
DAP node istype 'reg,keep'; "DAC Preset"
CK0..CK2 node istype 'reg,keep'; "Clock Divider"
cks=[CK2..CK0];
dacs=[DACS4..DACS0];
APOL node istype 'reg,keep'; "Lamp A Polarity"
ENR node istype 'reg,keep'; "Enable Randomizer"
equations


"Stimulus Control"
"----------------"

CLR = NCS & (opcode==clear_settings) # RESET;
SLCZ = (slc==0);
SLCTRZ = (slctr==0);
RUN.clk=CK;
RUN.aclr=CLR;
when NCS & (opcode==start_stimulus) then {
  RUN:=DC9
} else {
  when SLCTRZ & !SLCZ then RUN:=0 else RUN:=RUN;
}

slc.clk=CK;
slc.aclr=CLR;
when NCS & (opcode==set_stimulus_length_hi) then {
  [SLC15..SLC8]:=[DC16..DC9]
} else {
  [SLC15..SLC8]:=[SLC15..SLC8];
}
when NCS & (opcode==set_stimulus_length_lo) then {
  [SLC7..SLC0]:=[DC16..DC9]
} else {
  [SLC7..SLC0]:=[SLC7..SLC0];
}

slctr.clk=CK;
slctr.aclr=CLR;
when !RUN then slctr:=slc;
when RUN & IEP then slctr:=slctr-1;
when RUN & !IEP then slctr:=slctr;


"Interval Clock"
"--------------"

"The interval clock produces a 25-ns pulse every ilc CK (40-MHz) periods,"
"starting with a pulse just after the assertion of RUN. When ilc is"
"zero, the interval is 65536 CK periods."

ilc.clk=CK;
ilc.aclr=CLR;
when NCS & (opcode==set_interval_length_hi) then {
  [ILC15..ILC8]:=[DC16..DC9]
} else {
  [ILC15..ILC8]:=[ILC15..ILC8];
}
when NCS & (opcode==set_interval_length_lo) then {
  [ILC7..ILC0]:=[DC16..DC9]
} else {
  [ILC7..ILC0]:=[ILC7..ILC0];
}

ick.clk=CK;
ick.aclr=CLR;
when !RUN then ick:=1;
when RUN & (ick==1) then ick:=ilc;
when RUN & (ick!=1) then ick:=ick-1;
ICKP = RUN & (ick==1);


"Random Delay Generator"
"----------------------"

"The random delay word changes from one interval to the next, providing"
"a new random delay from 1 to 32767."

ENR.clk=CK;
ENR.aclr=CLR;
when NCS & (opcode==enable_randomizer) then ENR:=DC9 else ENR:=ENR;

rwcs.clk=CK;
rwcs.aclr=CLR;
state_diagram rwcs
  state 0:if IEP then 1;
  state 1:goto 2;
  state 2:goto 3;
  state 3:goto 4;
  state 4:goto 5;
  state 5:goto 6;
  state 6:goto 7;
  state 7:goto 8;
  state 8:goto 9;
  state 9:goto 10;
  state 10:goto 11;
  state 11:goto 13;
  state 12:goto 13;
  state 13:goto 14;
  state 14:goto 0;
equations;


rdw.clk=CK;
rdw.ap=CLR;
when (rwcs==0) then rdw:=rdw else rdw:=[RD13..RD0,RD14 $ RD13];


"Interval Generator"
"------------------"

"The Interval Generator counts up to clocks_per_ms from 1, starting when"
"RUN is first asserted, and counts up again as long as RUN continues to"
"be asserted. It generates a pulse at some point during the count-up,"
"when the count is equal to the contents of the random delay word. This"
"pulse, Lamp On Pulse, starts the generation of a lamp pulse. Because we"
"have already divided the master clock by ilc, and we are now dividing"
"by clocks_per_ms, we see that each count-up takes ilc milliseconds, so that"
"the average time between pulses is ilc milliseconds, no matter what the"
"distribution of the rdw sequence. The LOP node declaration must be inverted"
"like !LOP so that the comparison of ilt with rdw can be performed efficiently"
"in generic logic blocks. The IEP node marks the end of an interval."

ilt.clk=CK;
ilt.aclr=CLR;
when !RUN then ilt:=1;
when RUN & ICKP & (ilt!=clocks_per_ms) then ilt:=ilt+1;
when RUN & ICKP & (ilt==clocks_per_ms) then ilt:=1;
when RUN & !ICKP then ilt:=ilt;
LOP = ENR & ICKP & (ilt==[0,RD14..RD0]) # !ENR & ICKP & (ilt==1);
IEP = ICKP & (ilt==clocks_per_ms);


"Pulse Clock"
"----------"

"The Pulse Clock produces a pulse 25 ns long on PCKP every 1 ms, starting"
"with a 25 ns pulse 1 ms after the LOP pulse."

pck.clk=CK;
pck.aclr=RESET;
when LOP then pck:=1;
when !LOP & (pck!=clocks_per_ms) then pck:=pck+1;
when !LOP & (pck==clocks_per_ms) then pck:=1;
PCKP = RUN & (pck==clocks_per_ms);


"Pulse Generator"
"---------------"

plc.clk=CK;
plc.aclr=CLR;
when NCS & (opcode==set_pulse_length_hi) then {
  [PLC15..PLC8]:=[DC16..DC9]
} else {
  [PLC15..PLC8]:=[PLC15..PLC8];
}
when NCS & (opcode==set_pulse_length_lo) then {
  [PLC7..PLC0]:=[DC16..DC9]
} else {
  [PLC7..PLC0]:=[PLC7..PLC0];
}

plt.clk=CK;
plt.aclr=CLR;
when LOP then plt:=plc;
when !LOP & PCKP & (plt!=0) then plt:=plt-1;
when !LOP & PCKP & (plt==0) then plt:=0;
when !LOP & !PCKP then plt:=plt;
LON = RUN & (plt!=0);


"Serial DAC Interface"
"--------------------"

cks.clk=CK;
cks:=cks+1;
DAP.clk=CK;
DAP:=NCS & (opcode==set_brightness);
dacs.clk=CK2;
dacs.aclr=CLR;
dacs.ap=DAP;
when (dacs==31) then dacs:=30;
when (dacs==30) then dacs:=0;
when (dacs<16) then dacs:=dacs+1;
when (dacs==16) then dacs:=16;


DACCS=1;
DACFS=(dacs==31) # (dacs==30);
DACCK=CK2;
DACIN =((dacs==4) & DC16)
  # ((dacs==5) & DC15)
  # ((dacs==6) & DC14)
  # ((dacs==7) & DC13)
  # ((dacs==8) & DC12)
  # ((dacs==9) & DC11)
  # ((dacs==10) & DC10)
  # ((dacs==11) & DC9);


"Lamp Control"
"------------"

APOL.clk=CK;
APOL.aclr=CLR;
when NCS & (opcode==set_polarity) then APOL:=DC9 else APOL:=APOL;

LAC = !LON & !APOL # LON & APOL;
LAO = LON;
LBC = !LON;


"Power and Activity Indicator"
"----------------------------"

PWA=1;


"Test Indicators"
"---------------"

TP1=RUN;
TP2=ILT15;
TP3=ENR;
TP4=LON;

end