"
module P3023A

title 'P3023A'


"Version 2"

"[05-DEC-12] Transfer the A2060L code into this file so as to make"
"the A3023A look like a Lamp Controller. Instead of basing the timing"
"on a 40-MHz clock, we use the 32.768 kHz reference clock. We use SRUN"
"for the lamp controller RUN variable. We ignore APOL, the polarity of"
"the lamp control."


declarations

"Constants"
da_delay = 11; "CK periods to DA"
dda_delay = 22; "CK periods to DDA"
run_time = dda_delay+3; "CK periods to run"
clocks_per_ms = 33; "we have rounded 32.768 to 33"


"Inputs"
A pin 3; "LVDS Input"
!RST pin 28;"Power-Up Reset"
RCK pin 27; "Reference Clock, 32.768 kHz"

"Outputs"
B pin 11 istype 'com'; "Loop-Back Output"
LB pin 6 istype 'com'; "Loop-Back Enable"
LED1..LED4 pin 29,30,31,34 istype 'com'; "Indicator Lamps and Test Pins"
X1 pin 100 istype 'com'; "Select Input X1"
X2 pin 99 istype 'com'; "Select Input X2"
Y1 pin 61 istype 'com'; "Select Input Y1"
Y2 pin 58 istype 'com'; "Select Input Y2"
P pin 65 istype 'com'; "Apply Power to RF Amplifier"

"Command Receiver Nodes"
SA node istype 'reg'; "Synchronized A"
DSA node istype 'reg'; "Delayed SA"
DA node istype 'reg'; "Delayed A Rising Edge"
DDA node istype 'reg'; "Delayed DA"
AA node istype 'reg'; "Address Active"
CA node istype 'reg'; "Command Active"
ER,Q1..Q16 node istype 'reg'; "Receiver Bits"
LT5..LT0 node istype 'reg'; "LWDAQ Timer"
lt = [LT5..LT0];
DS node istype 'com'; "Data Strobe"
DC1..DC16 node istype 'reg';"Device Command Bits"
DA0..DA15 node istype 'reg';"Device Address Bits"

"Ring Oscillator Notes"
RO1,RO2 node istype 'com,keep'; "Ring Oscillator"
CK node istype 'reg,keep'; "Clock"
RUN node istype 'reg,keep';
equations 


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

"The RUN flag controls the ring oscillator. When the ring"
"oscillator runs, it causes lt to increment. When lt reaches"
"a threshold, we clear the RUN flag."
RUN.aclr = (lt == run_time) # RST;
RUN := 1;
RUN.clk = A;

"Here we generate our clock with a ring oscillator."
"The ring oscillator consists of two combinatorial gates."
RO1 = RO2;
RO2 = !RO1 & RUN;
CK.clk = RO1;
CK:=!CK;


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


"We synchronize A with DCK, and provide a delayed"
"version of A that allows us to detect edges."
[SA,DSA].clk = CK;
[SA,DSA].aclr = RST;
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 = CK;
lt.aclr = !RUN;
lt := lt+1;
DA.clk = !CK;
DA.aclr = RST;
DA := (lt==da_delay);
DDA.clk = !CK;
DDA.aclr = RST;
DDA := (lt==dda_delay);

"The command or address bits enter a sixteen-bit shift register."
[ER,Q1..Q16].clk = DA;
[ER,Q1..Q16].aclr = RST;
[ER,Q1..Q16] := [SA,ER,Q1..Q15];

"Address Active, or AA, provides a pulse that begins with DDA"
"on the start bit of an address transmission, and ends with DDA"
"on the stop bit of an address transmission. We clock the receiver"
"bits into the address register on a rising edge of AS."
AA.clk = DDA;
AA := (!AA & !CA & !SA & !ER) # (AA & !SA);
[DA0..DA15].clk = !AA;
[DA0..DA15].aclr = RST;
[DA0..DA15] := [Q1..Q16];

"Command Active, or CA, provides a pulse that begins with DDA"
"on the start bit of a command transmission, and ends with DDA"
"on the stop bit of a command transmission. We clock the receiver"
"bits into the command register on a rising edge of CS."
CA.clk = DDA;
CA := (!AA & !CA & !SA & ER) # (CA & !SA);
[DC1..DC16].clk = !CA;
[DC1..DC16].aclr = RST;
[DC1..DC16] := [Q1..Q16];

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

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

"The loop-back value is always equal to the incoming logic."
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;
SRUN 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];
ILT7..ILT0 node istype 'reg,keep'; "Interval Length Timer"
ilt=[ILT7..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"
APOL node istype 'reg,keep'; "Lamp A Polarity"
ENR node istype 'reg,keep'; "Enable Randomizer"
NCS0,NCS1 node istype 'reg'; "New Command Strobe States"
NCS node istype 'com'; "New Command Strobe"
equations


"Interface With Command Receiver"
"-------------------------------"

"New Command Strobe indicates a new command has just arrived."
[NCS0,NCS1].clk = RCK;
[NCS0,NCS1].aclr = CA;

state_diagram [NCS1,NCS0]
  state 0:if !CA then 1 else 0;
  state 1:goto 2;
  state 2:goto 2;
equations

NCS = [NCS1,NCS0] == 1;


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

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

slc.clk=RCK;
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=RCK;
slctr.aclr=CLR;
when !SRUN then slctr:=slc;
when SRUN & IEP then slctr:=slctr-1;
when SRUN & !IEP then slctr:=slctr;


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

"The interval clock produces an RCK pulse every ilc x RCK periods,"
"starting with a pulse just after the assertion of SRUN. When ilc is"
"zero, the interval is 65536 RCK periods."

ilc.clk=RCK;
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=RCK;
ick.aclr=CLR;
when !SRUN then ick:=1;
when SRUN & (ick==1) then ick:=ilc;
when SRUN & (ick!=1) then ick:=ick-1;
ICKP = SRUN & (ick==1);


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

"The random delay word changes from one interval to the next."

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

rdw.clk=RCK;
when RST then rdw:=[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
else when IEP then rdw:=[RD13..RD0,RD14 $ RD13] 
else rdw:=rdw;


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

"The Interval Generator counts up to clocks_per_ms from 1, starting when"
"SRUN is first asserted, and counts up again as long as SRUN 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=RCK;
ilt.aclr=CLR;
when !SRUN then ilt:=1;
when SRUN & ICKP & (ilt!=clocks_per_ms) then ilt:=ilt+1;
when SRUN & ICKP & (ilt==clocks_per_ms) then ilt:=1;
when SRUN & !ICKP then ilt:=ilt;
LOP = ENR & ICKP & (ilt==[0,0,0,RD4..RD0]) 
  # ENR & ICKP & ((ilt==[0,0,1,0,0,0,0,0]) & ([RD4..RD0] == 0))
  # (!ENR & ICKP & (ilt==1));
IEP = ICKP & (ilt==clocks_per_ms);


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

"The Pulse Clock produces an RCK pulse on PCKP every 1 ms, starting"
"with a pulse 1 ms after the LOP pulse."

pck.clk=RCK;
pck.aclr=RST;
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 = SRUN & (pck==clocks_per_ms);


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

plc.clk=RCK;
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=RCK;
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 = SRUN & (plt!=0);


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

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

X1 = LON;
X2 = !LON;
Y1 = LON;
Y2 = !LON;



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

LED1=IEP;
LED2=SRUN;
LED3=1;
LED4=LON;

end