"

" Copyright (C) 2004 Kevan Hashemi, Brandeis University

" This program is free software; you can redistribute it and/or modify
" it under the terms of the GNU General Public License as published by
" the Free Software Foundation; either version 2 of the License, or
" (at your option) any later version.

" This program is distributed in the hope that it will be useful,
" but WITHOUT ANY WARRANTY; without even the implied warranty of
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
" GNU General Public License for more details.

" You should have received a copy of the GNU General Public License
" along with this program; if not, write to the Free Software
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

module P2037E

title 'LWDAQ Driver with Ethernet Interface (A2037E)'

declarations

firmware_version_number=13;

"Version 13:"

"[09-JUL-08] Re-arrange code so as to separate RCM interface from the LWDAQ"
"interface. This allows us to copy and paste code from the P2037E into the"
"P2037A files."

"[09-JUL-08] Change TC255P to TC255. Remove lwdaq_addr and just set lwdaq_data"
"according to state. Remove the counter-timer functions and variables to make"
"space for modifications. Nobody ever used the counter-timer, so there seemed"
"no point in keeping it, despite all the hard work we put into designing it."
"Change name of counter-timer bits to SSR7..SSR0 for Serial Shift Register."
"Leave dummy responses to counter-time job and counter-timer configuration"
"register."

"[09-JUL-08] Fix bug whereby adc_16_job does not work for data_device. In the"
"previous code ADI=1 regardless of the job or controller state. Now we assert"
"ADI for data_device only when we are actually executing a read_job. We also"
"do the same for the TC255 read."

"Version 12:"

"[12-MAR-08] On adc_16_job, we now start the delay timer before we begin the"
"conversion when we see that CLEN is clear. In this way, the sample rate is not"
"dependent upon the asynchronous ADC conversion time. This allows a superior"
"implementation of the Inclinometer. The CLEN bit now serves two functions:"
"one for the 8-bit ADC, which is to enable or disable the video clamp, and"
"one for the 16-bit ADC, which is to enable or disable pre-conversion delay"
"count-down."

"Version 11:"

"Increased data_device read_job maximum transfer speed from 670 kBytes/s"
"to 1.3 MBytes/s."

"Version 10:"

"Modified 01-DEC-05: Synchorinze the incoming data from a data device"
"with FCK instead of CK. This makes sure that we get the correct serial"
"byte even when its bit transmission time is not exactly 50 ns. We can"
"now tolerate bit transmission times of 50+-2 ns on average, with stochastic"
"variation of 10 ns."

"Modified 17-NOV-05: Reduced the counter-timer to eight bits to free up"
"registers. By this means, we stopped the compiler from crashing. We"
"assume it was crashing because it could not handle the job of packing"
"all the existing logic into this chip. All that is left of the counter-"
"timer is the lower eight bits, which we use in the read_job for devices"
"of data_device type."

"Modified 17-NOV-05: The enable device power (EDP) output goes low"
"(power off) during RESET, and then goes high at the end of RESET. This"
"counter-acts the effects of power glitches upon device registers. A"
"power glitch will result in a power cycle of all devices, which resets"
"their registers to zero."

"Modified 17-NOV-05: The repeat counter is now three bytes, for a maximum"
"count of $FFFFFF instead of the previous $FFFF. This allows us to upload"
"2 MBytes consecutively with the read job on a device of type data_device."


"Rabbit Controller Module"
!LNK pin 126; "ethernet link"
ACT pin 131; "ethernet active"
CA0..CA5 pin 190,207,191,206,192,205; "control address"
!CW pin 193; "control write"
!DS pin 120; "data strobe, called K1 on the A203701 PCB"
D0..D7 pin 197,203,196,202,195,201,194,200; "module data"
control_addr=[CA5..CA0]; "local control address"

"Switches"
!MD0,!MD1 pin 49,48; "mode jumper field"
!HRST pin 168; "hardware reset"
!CSW pin 158; "configuration switch"

"RAM"
RA0..RA18 pin 10..6,34..31,29..25,22,16..13 istype 'reg'; "ram address"
RD0..RD7 pin 4,3,37,36,21..18 istype 'com,dc'; "ram data, bidirectional"
!RCE pin 5 istype 'com'; "ram chip enable"
!RWE pin 35 istype 'com'; "ram write enable"
!ROE pin 17 istype 'com'; "ram output enable"

"Clock Bus"
FCK pin 187; "fast clock (80 MHz) in from oscillator"
CKOUT pin 73 istype 'reg';"clock (40 MHz) out"
CK pin 74; "clock (40 MHz) in from CKOUT"
SCKP0 pin 84 istype 'reg,keep';"slow clock (8 MHz) out"
SCK pin 83; "slow clock (8 MHz) in from SCKP0"

"Test Pins"
!TP1..!TP8 pin 38,39,42..47 istype 'com,pos'; "test pins with LEDs"
K2..K4 pin 121..123; "breadboard area input"

"Devices"
!TXE0..!TXE8 pin 78,71,72,86,85,87,88,89,90 istype 'com'; "transceiver enable"
AD0..AD7 pin 61..54 istype 'com,pos'; "acquired data"
CLAMP pin 93 istype 'reg,pos'; "zero the input clamp"
CLEN pin 119 istype 'reg,pos'; "enable ADC8 clamp, delay ADC16 count-down"
CVT8 pin 68 istype 'com,pos'; "adc8 convert"
!ADC8 pin 69 istype 'reg,pos'; "adc8 output enable"
TAG pin 70; "adc8 input is out of range"
!CVT16 pin 66 istype 'reg,pos'; "adc16 convert"
!ADC16 pin 65 istype 'reg,pos'; "adc16 output enable"
HB16 pin 67 istype 'reg,pos'; "adc16 high byte select"
!BY16 pin 64; "adc16 busy"
!BUSY pin 125 istype 'reg'; "retrieval controller busy"
TXI pin 92; "transeiver input"
TXO pin 77 istype 'reg'; "transceiver output"

"Head Power Control"
MA0..MA3 pin 91,80,79,124 istype 'com'; "multiplexer address output"
EDP pin 117 istype 'com'; "enable device power"
IEDP pin 118 istype 'com'; "inverted EDP"

"Nodes"
ABT node istype 'reg,keep'; "activate bit transmitter"
ADRA node istype 'com,keep,pos'; "acquired data ready asynch"
ADRS node istype 'reg,keep,pos'; "acquired data ready synch"
ADI node istype 'com,keep,pos'; "acquired data internal"
ATA node istype 'reg,keep'; "address transmission active"
BTS0..BTS4 node istype 'reg,keep'; "bit trasmitter state"
CD0..CD7 node istype 'com,keep,pos'; "control data"
CDS node istype 'reg,keep'; "control data strobe"
CDSD node istype 'reg,keep'; "cds delayed"
CR1..CR16 node istype 'reg,keep'; "command register"
CVT8A node istype 'com,keep,pos'; "convert adc8 asynch"
CVT8S node istype 'reg,keep,pos'; "convert adc8 synch"
DAC0 node istype 'com,keep'; "data address carry from byte zero"
DAC1 node istype 'com,keep'; "data address carry from byte one"
DACL node istype 'com,keep'; "clear data address"
DAI node istype 'reg,keep,pos'; "data address increment"
DAR0..DAR7 node istype 'reg,keep'; "device address register"
DASEL0..DASEL2 node istype 'com,keep'; "data address select"
DC1..DC16 node istype 'com,keep'; "device command"
DCJD node istype 'reg,keep';"device controller job done"
DCS0..DCS5 node istype 'reg,keep'; "device controller state"
DCRST node istype 'com,keep'; "device controller reset"
DER0..DER2 node istype 'reg,keep'; "device element register"
DJR0..DJR3 node istype 'reg,keep'; "device job register"
DJSLP node istype 'com,keep'; "device job sleep"
DJCMD node istype 'com,keep'; "device job command"
DRS0..DRS4 node istype 'reg,keep'; "device receiver state"
DRSZ node istype 'reg,keep'; "device receiver state zero"
DT0..DT23 node istype 'reg,keep'; "delay timer"
DTEN node istype 'reg,keep'; "delay timer enable"
DTSV0..DTSV23 node istype 'reg,keep'; "delay timer saved"
DTR0..DTR2 node istype 'reg,keep'; "device type register"
DTS0..DTS4 node istype 'reg,keep'; "data transmitter state"
DTSEL0..DTSEL2 node istype 'com,keep'; "delay timer select"
DTR node istype 'com,keep,pos'; "delay timer restore"
DTZ node istype 'com,keep'; "delay timer zero"
DTZ0 node istype 'com,keep'; "delay timer zero in byte zero"
DTZ1 node istype 'com,keep'; "delay timer zero in byte one"
DTZ2 node istype 'com,keep'; "delay timer zero in byte two"
EDPR node istype 'reg,keep'; "enable device power register"
ESD node istype 'reg,keep'; "end settling delay"
FTOL node istype 'reg,keep,pos'; "force transceiver output low"
LC0..LC9 node istype 'reg,keep'; "line counter"
LCCK node istype 'reg,keep,pos'; "line counter clock"
LCCL node istype 'reg,keep,pos'; "line counter clear"
LNEC node istype 'com,neg,keep'; "line end count"
LO0..LO6 node istype 'reg,keep'; "loop offset"
LOEN node istype 'reg,keep,pos'; "loop offset enable"
LOLD node istype 'reg,keep,pos'; "loop offset load"
LOZ node istype 'reg,keep'; "loop offset zero"
LSB node istype 'reg,keep'; "last serial bit"
LT0..LT6 node istype 'reg,keep'; "loop timer"
LTCL node istype 'reg,keep,pos'; "loop timer clear"
LTEN node istype 'reg,keep,pos'; "loop timer enable"
LTR node istype 'reg,keep'; "loop timer runout"
MCS0..MCS3 node istype 'reg,keep'; "master clock state"
MRB0..MRB7 node istype 'reg,keep'; "most recent byte"
PC0..PC9 node istype 'reg,keep'; "pixel counter"
PCCK node istype 'reg,keep,pos'; "pixel counter clock"
PCCL node istype 'reg,keep,pos'; "pixel counter clear"
PXEC node istype 'com,neg,keep'; "pixel end count"
RC0..RC23 node istype 'reg,keep'; "repeat counter"
RCMOE node istype 'com,keep'; "rcm data output enable"
RCSEL0 node istype 'com,keep'; "repeat counter select byte zero"
RCSEL1 node istype 'com,keep'; "repeat counter select byte one"
RCSEL2 node istype 'com,keep'; "repeat counter select byte two"
RCZ node istype 'com,keep'; "repeat counter zero"
RCZ0 node istype 'com,keep'; "repeat counter zero in byte zero"
RCZ1 node istype 'com,keep'; "repeat counter zero in byte one"
RCZ2 node istype 'com,keep'; "repeat counter zero in byte two"
RESET node istype 'com,keep'; "internal global RESET"
RSD node istype 'reg,keep,pos'; "run settling delay"
RSDD node istype 'reg,keep,pos'; "RSD delayed"
RSEL node istype 'com,keep'; "ram select"
SB node istype 'com,keep'; "serial bit"
SCKP1..SCKP4 node istype 'reg,keep'; "slow clock phases"
SOUT node istype 'reg,keep'; "serial transmitter output"
SBY16 node istype 'reg,keep'; "synchronized BY16"
SPXEC node istype 'reg,keep'; "synchronized PXEC"
SLNEC node istype 'reg,keep'; "synchronized LNEC"
SRST node istype 'reg,keep'; "software reset"
SSR0..SSR7 node istype 'reg,keep'; "serial shift register"
SSSR node istype 'reg,keep,pos'; "shift serial shift register"
TBC node istype 'com,keep'; "transmit serial bit complete"
TDA node istype 'reg,keep'; "transmit device address"
TDAC node istype 'reg,keep'; "transmit device address complete"
TDC node istype 'reg,keep'; "transmit device command"
TDCC node istype 'reg,keep'; "transmit device command complete"
TXIC node istype 'reg,keep'; "TXI synchronized to CK"
TXIF node istype 'reg,keep'; "TXI synchronized to FCK"
TXIS node istype 'reg,keep'; "TXI synchronized to SCK"

"Sets"
pixel_count=[PC9..PC0]; "for image retrieval"
line_count=[LC9..LC0]; "for image retrieval"
ram_data=[RD7..RD0]; "ram data bus"
data_addr=[RA18..RA0]; "data address, or ram address bus"
control_data=[CD7..CD0]; "control data bus"
lwdaq_data=[AD7..AD0]; "lwdaq data bus"
dcs=[DCS5..DCS0]; "device controller state"
drs=[DRS4..DRS0]; "device receiver state"
dts=[DTS4..DTS0]; "data transmitter state"
bts=[BTS4..BTS0]; "bit transmitter state"
mcs=[MCS3..MCS0]; "master clock state"
dar=[DAR7..DAR0]; "device address register"
dtr=[DTR2..DTR0]; "device type register"
der=[DER2..DER0]; "device element register"
djr=[DJR3..DJR0]; "device job register"
loop_time=[LT6..LT0]; "measured loop time"
loop_offset=[LO6..LO0]; "loop time countdown for synchornization"
dtb0=[DT7..DT0]; "delay timer byte zero"
dtb1=[DT15..DT8]; "delay timer byte one"
dtb2=[DT23..DT16]; "delay timer byte two"
delay_timer=[DT23..DT0]; "delay timer"
delay_timer_saved=[DTSV23..DTSV0]; "saved delay timer"
dab0=[RA7..RA0]; "data address byte zero"
dab1=[RA15..RA8]; "data address byte one"
dab2=[RA18..RA16]; "data address byte two"
ssr=[SSR7..SSR0]; "serial shift register"
rcb0=[RC7..RC0]; "repeat counter byte zero"
rcb1=[RC15..RC8]; "repeat counter byte one"
rcb2=[RC23..RC16]; "repeat counter byte two"
repeat_counter=[RC23..RC0]; "repeat counter"
transceiver_select=[DAR7..DAR4]; "root socket number"
device_select=[DAR3..DAR0]; "branch socket number"
rcm_data=[D7..D0]; "rcm interface data"
mrb=[MRB7..MRB0];

"Constants"
id_addr=0;"identifying byte at 512K boundry"
sr_addr=1;"status register location (byte)"
mrb_addr=2; "most recent byte location (byte)"
djr_addr=3;"device job register location (byte)"
dar_addr=5; "device address register location (byte)"
do_addr=7; "digital outputs location (byte)"
di_addr=9; "digital inputs location (byte)"
daclr_addr=11; "data address clear location (byte)"
dtr_addr=13; "device type register location (byte)"
der_addr=15; "device element register location (byte)"
lt_addr=17; "loop timer location (byte)"
hv_addr=18; "hardware version number location (byte)"
fv_addr=19; "firmware version number location (byte)"
dt_addr=20; "delay timer location (longint)"
da_addr=24; "data address location (longint)"
edp_addr=29; "enable device power location (byte)"
clen_addr=31; "clamp enable location (byte)"
cr_addr=32; "command register location"
rc_addr=34; "repeat counter location (longint)"
ctcr_addr=39; "c-t config register location (byte)"
cs_addr=40; "configuration switch address (byte)"
srst_addr=41; "software reset address (byte)"
dba_addr=42; "VME driver base address (longint) (A2064)"
vam_addr=46; "VME address modifier (byte) (A2064)"
ram_portal_addr=63; "rcm interface ram portal location"
num_control_bytes=64; "bytes allocated to control registers"
max_loop_time=119; "120*25ns=6us, a 300-m cable"
id_byte=37;"identification byte"


"Master Clock Generator"
"----------------------"

equations

"The mcs machine rotates through ten states at the fast"
"clock rate (FCK)."
mcs.clk=FCK;
when (mcs<=8)&(mcs>=0) then mcs:=mcs+1;
else mcs:=0;

"CKOUT drives the CK global clock input."
CKOUT.clk=FCK;
CKOUT:=(mcs==0)#(mcs==2)#(mcs==4)#(mcs==6)#(mcs==8);

"SCKP0 drives the SCK global clock input. We can also use"
"it to select the falling edge of CK that follows immediately"
"after the rising edge of SCK."
SCKP0.clk=FCK;
SCKP0:=(mcs==0)#(mcs==1);

"The Slow Clock Phases (SCKP1..SCKP4) are the second to fifth"
"phases of SCK, following SCKP0."
[SCKP1..SCKP4].clk=FCK;
SCKP1:=(mcs==2)#(mcs==3);
SCKP2:=(mcs==4)#(mcs==5);
SCKP3:=(mcs==6)#(mcs==7);
SCKP4:=(mcs==8)#(mcs==9);


"Rabbit Control Module Interface"
"-------------------------------"

equations

"Control Data Strobe is the data strobe signal from the RCM"
"interface. The RCM module provides valid data during CDS"
"on read cycles, and expects valid data on the falling"
"edge of CDS."
CDS.clk=CK;
CDS:=DS;

"The RCM Interface selects RAM data by setting control_addr"
"equal to ram_portal_addr. If !RSEL, then we select a control"
"register."
RSEL = (control_addr==ram_portal_addr);

"We write to the RAM on Control Interface write cycles and"
"when BUSY"
RWE = BUSY # (CW & RSEL);

"We enable the RAM output on any read from RAM."
ROE = !BUSY & !CW & RSEL;

"We drive the RCM data lines on any Control Interface read"
"access."
RCMOE = !CW & CDS;
rcm_data.oe = RCMOE;

"We drive the RAM data lines on any write to RAM."
ram_data.oe = RWE;

"When the RCM interface addresses the control registers,"
"we set the RCM data equal to the control data. When it"
"addresses the RAM, we set RCM data equal to RAM data."
when !RSEL & !CW then rcm_data = control_data;
when RSEL & !CW then rcm_data = ram_data.pin;

"When the RCM interface writes to the control registers,"
"we set the control data equal to the RCM data, as seen"
"on the pins connected to the RCM2200."
when !RSEL & CW then control_data = rcm_data.pin;

"When we are not commandeering the RAM for data storage,"
"we set the internal RAM data equal to the RCM data, as"
"seen on the pins connected to the RCM2200."
when !BUSY & RSEL & CW then ram_data = rcm_data.pin;

"RAM Chip Enable (RCE) writes data to RAM on a write"
"cycle, and drives data onto [RD7..RD0] on a read cycle."
"We can assert RCE for as little as one CK period"
"and still ensure proper storage in RAM."
when BUSY then RCE = ADRA # ADRS;
when !BUSY then RCE = CDS & RSEL;

"We increment the data address whenever we read or write"
"a byte from or to the RAM through the RCM Interface."
"Consecutive reads or writes from the ram_portal_addr location"
"retrieve  or set consecutive bytes from the RAM. To perform the"
"increment we detect a rising edge on CDS. We increment"
"the data address by asserting DAI for one CK period."
[CDSD].clk=CK;
CDSD:=CDS;
when RSEL & CDSD & !CDS then DAI:=1;


"Most Recent Byte"
"----------------"

"The Most Recent Byte (mrb) register contains the most recent"
"byte stored to RAM. The RCM interface can read mrb even"
"when the RAM is busy. It can write to mrb when the RAM is not"
"busy, by writing a byte to the ram portal address."
mrb.clk=CK;
mrb.aclr=RESET;

when RWE & RCE then mrb := ram_data;
else mrb := mrb;


"DAQ Data Router"
"---------------"

equations

"When we commandeer the RAM for data storage, we set"
"ram_data equal to lwdaq_data as seen on the pins"
"connected to the board's data converters."
when BUSY then ram_data = lwdaq_data.pin;

"We drive the acquired data lines when the acquired data"
"comes from inside the ISP chip (Aquired Data Internal)."
"By default, ADI is false. Any state machine may assert ADI,"
"but no machine may unassert it."
lwdaq_data.oe = ADI;

"Aquired Data Ready (ADR) indicates that analog data"
"is ready to be stored in RAM. We may assert ADR for"
"as little as one FCK period and still ensure accurate"
"data storage. We have both ADR Synchronous (ADRS) and ADR"
"Asynchronous (ADRA) to choose from. We clock ADRS with"
"!CK."
ADRS.clk=!CK;


"Address Counter"
"---------------"

equations

"The data address is the same as the ram address."

"We clock the data address on the rising edge of CK."
[dab0,dab1,dab2].clk=CK;

"We clear the data address on a write to the daclr_addr"
"location or RESET. Alternatively, we can clear the"
"data address by writing a zero to the data address"
"location. We implement the data address clear location"
"for compatibility with the A2031."
DACL=(CDS & CW & (control_addr==daclr_addr)) # RESET;

"We clear the data address asynchronously with DACL."
[dab0,dab1,dab2].aclr=DACL;

"The data address carry outputs simplify the counter logic."
DAC0=(dab0==^hFF);
DAC1=(dab1==^hFF);

"Data Address Increment is clocked by !CK. Any state machine"
"may assert it, but no state machine may unassert it. The"
"variable is unasserted when its state is unspecified, hence"
"the 'pos' directive in its node declaration. We increment"
"the data address by one on each rising edge of CK for which"
"we assert DAI."
DAI.clk=!CK;
when DAI then
{
  dab0:=dab0+1;
  when DAC0 then dab1:=dab1+1;
  else dab1:=dab1;
  when DAC1 & DAC0 then dab2:=dab2+1;
  else dab2:=dab2;
}

"We set the data address via the Control register interface. 
"We use the DASEL nodes to reduce the data address fan-in."
DASEL0=CDS & CW & (control_addr==da_addr+3);
DASEL1=CDS & CW & (control_addr==da_addr+2);
DASEL2=CDS & CW & (control_addr==da_addr+1);

"We can write to the data address only when we are not"
"incrementing it."
when !DAI then
{
  when DASEL0 then dab0:=[CD7..CD0];
  else dab0:=dab0;
  when DASEL1 then dab1:=[CD7..CD0];
  else dab1:=dab1;
  when DASEL2 then dab2:=[CD2..CD0];
  else dab2:=dab2;    
}


"Readback registers"
"------------------"

"Readback from the control address space is all zeros except"
"as specified below. In some cases, the zeros act as the valid"
"upper byte or upper nibble of a readback register."

"Device Job register, partial readback."
when CDS & !CW & (control_addr==djr_addr) then 
  [CD3..CD0]=djr;


"Status register."
"A2031 Compatibility: bit three is the busy bit, and"
"when the device controller is idle, the status bits"
"are all zero."
when CDS & !CW & (control_addr==sr_addr) then
{
  CD7=DTEN;
  CD6=TDC;
  CD5=TDA;
  CD4=!RCZ; 
  CD3=BUSY;
  CD2=BY16;
  CD1=LTEN;
  CD0=RSD;
}

"A2037 identification byte."
when CDS & !CW & (control_addr==id_addr) then
  [CD7..CD0]=id_byte; "37 identifies the A2037"

"Firmware Version Number"
when CDS & !CW & (control_addr==fv_addr) then
  [CD7..CD0]=firmware_version_number;

"Hardware Version Number"
when CDS & !CW & (control_addr==hv_addr) then
  [CD1..CD0]=[MD1..MD0];

"We can read back the loop timer directly."
when CDS & !CW & (control_addr==lt_addr) then
  [CD6..CD0]=loop_time;

"We can read the configuration switch state. We"
"return the inverse of CSW for compatibility with"
"earlier firmware versions."
when CDS & !CW & (control_addr==cs_addr) then
  [CD0]=!CSW;

"We can read out the most recent byte stored to RAM"
"from the mrb register."
when CDS & !CW & (control_addr==mrb_addr) then
  control_data=mrb;


"Software and Hardware Reset"
"---------------------------"

RESET = SRST # HRST;

"SRST is a bit we can set through the control bus. When we"
"set SRST, RESET becomes true. SRST returns to zero after"
"one SCK cycle."
SRST.clk=SCK;
when (CDS & CW & (control_addr==srst_addr)) then SRST:=1;
else SRST:=0;


"Device Power Control"
"------------------"

"Enable Device Power Register (EDPR) turns on the power"
"supplies (+5V, +15V, and -15V) to the driver sockets, and to"
"the three power indicator LEDs. To turn off the power,"
"we write a zero to EDPR via the Control register interface."
"After RESET, EDPR is set to one. The actual EDP and IEDP"
"outputs are unasserted during reset, so that a reset causes"
"a temporary power shut down to all devices."
EDPR.clk=SCK;
EDPR.ap=RESET;
when (CDS & CW & (control_addr==edp_addr)) then EDPR:=CD0;
else EDPR:=EDPR;
EDP=EDPR & !RESET;
IEDP=!EDP;


"Clamp Control"
"-------------"

"We enable the adc8 input clamp with Clamp Enable (CLEN)."
"When the clamp is enabled, the adc8 analog input passes"
"through a capacitor, which we charge on CLAMP."
CLEN.clk=SCK;
CLEN.ap=RESET;
when CDS & CW & (control_addr==clen_addr) then CLEN:=CD0;
else CLEN:=CLEN;


"Command register"
"----------------"

"We use this register to control LWDAQ devices asynchronously."
"When we execute a command_job with the Device Controller, we"
"transmit the contents of the command register to the active"
"LWDAQ device."
[CR1..CR16].clk=SCK;
[CR1..CR16].aclr=RESET;
when CDS & CW & (control_addr==cr_addr+1) then [CR1..CR8]:=[CD0..CD7]
else [CR1..CR8]:=[CR1..CR8];
when CDS & CW & (control_addr==cr_addr) then [CR9..CR16]:=[CD0..CD7]
else [CR9..CR16]:=[CR9..CR16];


"Device Type register"
"--------------------"

"The Device Type register tells the Device Controller the LWDAQ"
"device identification number, which the Device Controller"
"needs to know when executing synchronous jobs."

dtr.clk=SCK;
dtr.aclr=RESET;
when CDS & CW & (control_addr==dtr_addr) then dtr:=[CD2..CD0];
else dtr:=dtr;

"Here we declare the device types supported by this version"
"of the firmware."
declarations

null_device=0;
LED_device=1;
TC255_device=2;
data_device=3;

equations


"Device Element register"
"-----------------------"

"The Device Element register tells the Device Controller"
"which internal part of a device it should select when"
"it executes a synchronous job."

equations

der.clk=SCK;
der.aclr=RESET;
when CDS & CW & (control_addr==der_addr) then der:=[CD2..CD0];
else der:=der;


"Device Job register"
"-------------------"

"The Device Job register is where the Control register Interface puts"
"commands for the Device Controller. The Device Controller starts executing"
"the command immediately, and when it finishes, it sits in its done state,"
"waiting for the control bus to write to the Device Job register."

declarations
null_job=0; 
wake_job=1; "also expose_job"
move_job=2; "also clear_job"
read_job=3;  
fast_toggle_job=4; "replaces alt_read_job" 
alt_move_job=5; "also transfer_job" 
flash_job=6;
sleep_job=7;
toggle_job=8; "also ab_expose_job"
loop_job=9;
command_job=10;
adc16_job=11;
adc8_job=12;
delay_job=13;
counter_timer_job=14;
fast_adc_job=15;

equations

djr.clk=SCK;
djr.aclr=RESET;
when DCJD & RCZ then djr:=0;
else
{
  when CDS & CW & (control_addr==djr_addr) then djr:=[CD3..CD0];
  else djr:=djr;
}

"DJSLP indicates a sleep job, and reduces logic complexity later."
DJSLP=(djr==sleep_job);

"DJCMD indicates a command job, and reduces logic complexity later."
DJCMD=(djr==command_job);

"BUSY indicates that the Device Controller is executing a job, and"
"that it is commandeering the RAM for uninterrupted data storage."
BUSY.clk=SCK;
BUSY:=(djr!=null_job);


"Device Controller and Device Receiver"
"-------------------------------------"

"The Device Controller sends commands to the devices connected to"
"the A2037. The Device Receiver receives data from the device."
"The controller and receiver are separate state machines"
"because the received data is delayed by the time it takes signals"
"to travel to and from the device. The Device Controller measures"
"the loop delay with the Loop Timer. The Device Receiver loads"
"its own Loop Offset from the Loop Timer and counts it down to"
"coordinate its reception with the device controllers transmission."

declarations

"Device Controller state names."
dcs_rest=^h00;
dcs_done=^hFF;

dcs_bridge=^h01;
dcs_pause=dcs_bridge+1;

loop_1=dcs_pause+1;
loop_2=loop_1+1;
loop_3=loop_2+1;
loop_4=loop_3+1;
loop_5=loop_4+1;

flash_1=loop_5+1;
flash_2=flash_1+1;
flash_3=flash_2+1;

command_1=flash_3+1;

adc16_1=command_1+1;
adc16_2=adc16_1+1;
adc16_3=adc16_2+1;
adc16_4=adc16_3+1;

adc8_1=adc16_4+1;

fast_adc_1=adc8_1+1;

delay_1=fast_adc_1+1;

fast_toggle_1=delay_1+1;

ct_1=fast_toggle_1+1;

toggle_1=ct_1+1;
toggle_2=toggle_1+1;

move_1=toggle_2+1;
move_2=move_1+1;

alt_move_1=move_2+1;
alt_move_2=alt_move_1+1;

px_1=alt_move_2+1;
px_2=px_1+1;
px_3=px_2+1;
px_4=px_3+1;

ln_1=px_4+1;
ln_2=ln_1+1;
ln_3=ln_2+1;
ln_4=ln_3+1;

rd_1=ln_4+1;
rd_2=rd_1+1;
rd_3=rd_2+1;

equations

"We use SCK to clock the Device Controller and thus reduce"
"the number of states (125-ns steps)."
dcs.clk=SCK;

"We reset the Device Controller asynchronously by writing"
"to the job register at any time, or with the external reset"
"line."
DCRST=RESET # (CDS & CW & (control_addr==djr_addr)); 
dcs.aclr=DCRST;

"The Device Controller sits in its rest state until it"
"detects djr!=null_job, whereupon it executes the job"
"specified by djr. If at any time during this execution,"
"we write again to djr, we will automatically reset the"
"Device Controller to its rest state. Assuming the"
"controller completes the job, it moves to its dcs_done"
"state, where it asserts DCJD. The DCJD signal decrements"
"the repeat counter. If the repeat counter, before DCJD"
"decrements it, is already zero, then DCJD and Repeat"
"Counter Zero (RCZ) will reset djr. When the Device Controller"
"returns to dcs_rest, either djr is zero, or it remains"
"unchanged, in which case the Device Controller repeats the"
"job, and continues to do so until RCZ or we write to djr."
"We assert DCJD when dcs=rd_3 also. 
state_diagram dcs;

  state dcs_rest: 
    case 
      djr==null_job:dcs_rest;
      djr==wake_job:command_1;
      djr==move_job:move_1;
      djr==alt_move_job:alt_move_1;
      djr==read_job:
        if (dtr==data_device) then rd_1
        else loop_1;
      djr==fast_toggle_job:fast_toggle_1;
      djr==flash_job:flash_1;
      djr==sleep_job:command_1;
      djr==toggle_job:toggle_1;
      djr==loop_job:loop_1;
      djr==command_job:command_1;
      djr==adc16_job:adc16_1;
      djr==adc8_job:adc8_1;
      djr==delay_job:delay_1;
      djr==counter_timer_job:ct_1;
      djr==fast_adc_job:fast_adc_1;
    endcase;

  state dcs_pause:if DTZ then dcs_done else dcs_pause;
  state dcs_done:goto dcs_rest;

  state flash_1:if !TDC then flash_2 else flash_1;
  state flash_2:if DTZ then flash_3 else flash_2;
  state flash_3:if !TDC then dcs_done else flash_3;

  state delay_1:if DTZ then dcs_done else delay_1;

  state fast_toggle_1:if DTZ then dcs_done else fast_toggle_1;

  state ct_1:goto dcs_done;

  state adc16_1:goto adc16_2;
  state adc16_2:if !SBY16 then adc16_3 else adc16_2;
  state adc16_3:goto adc16_4;
  state adc16_4:goto dcs_pause;

  state adc8_1:goto dcs_pause;

  state fast_adc_1:if DTZ then dcs_done else fast_adc_1;

  state command_1:if !TDC then dcs_done else command_1;

  state loop_1:if !TDC then loop_2 else loop_1;
  state loop_2:goto loop_3;
  state loop_3:if LTR then loop_4 else loop_3;
  state loop_4:goto loop_5; 
  state loop_5:
    if (TXIS & !LTR) then loop_5;
    if !(TXIS & !LTR)&(djr==loop_job) then dcs_done;
    if !(TXIS & !LTR)&(djr==read_job) then dcs_bridge;
    "All jobs that use loop_1 must be accounted for here."

  state dcs_bridge:goto px_1;

  state toggle_1:
    if TDC then toggle_1;
    else {if !DTZ then toggle_2 else dcs_done};
  state toggle_2:
    if !TDC then toggle_1 else toggle_2;

  state move_1:
    if TDC then move_1;
    else {if !SLNEC then move_2 else dcs_done};
  state move_2:
    if !TDC then move_1 else move_2;

  state alt_move_1:
    if TDC then alt_move_1;
    else {if !SLNEC then alt_move_2 else dcs_done};
  state alt_move_2:
    if !TDC then alt_move_1 else alt_move_2;

  state px_1:
    if !SPXEC then px_2;
    if SPXEC & !SLNEC then ln_1;
    if SPXEC & SLNEC & !DRSZ then px_1;
    if SPXEC & SLNEC & DRSZ then dcs_done;
  state px_2:goto px_3; 
  state px_3:goto px_4; "clock TC255_device here"
  state px_4:goto px_1;

  state ln_1:if !TDC then ln_2 else ln_1;
  state ln_2:if !TDC then ln_3 else ln_2;
  state ln_3:if !TDC then ln_4 else ln_3;
  state ln_4:if !TDC then px_1 else ln_4;

  state rd_1:goto rd_2;
  state rd_2:if DRSZ & !RCZ then rd_3;
    if DRSZ & RCZ then dcs_done;
    if !DRSZ then rd_2;
  state rd_3:goto rd_2;
equations

"We use !SCK to synchronize the following inputs to the Device"
"Controller."
[SBY16,SPXEC,SLNEC,LTR,DRSZ,TXIS].clk=!SCK;
SBY16:=BY16;
SPXEC:=PXEC;
SLNEC:=LNEC;
TXIS:=TXI;

"TDC and TDCC perform the handshake between the Device"
"Controller and the Data Transmitter. After the Device"
"Controller enters a state in which it wishes to transmit"
"a command to the device, TDC asserts itself, and remains"
"asserted until it receives TDCC from the Data Transmitter."
"TDC then returns to zero. Before TDC has a chance to"
"assert itself once again, the Device Controller must be"
"allowed to move on to its next state, which is why we"
"must clock TDC with !SCK." 
TDC.clk=!SCK;
TDC.aclr=RESET;
state_diagram TDC;
  state 0:if
    (dcs==toggle_1)
   #(dcs==toggle_2)
   #(dcs==move_1)
   #(dcs==move_2)
   #(dcs==alt_move_1)
   #(dcs==alt_move_2)
   #(dcs==loop_1)
   #(dcs==ln_1)
   #(dcs==ln_2)
   #(dcs==ln_3)
   #(dcs==ln_4)
   #(dcs==flash_1)
   #(dcs==flash_3)
   #(dcs==command_1)
     then 1 else 0;
  state 1:if TDCC then 0 else 1;
equations

"We use CK to clock the Device Receiver so as to increase"
"the resolution of its loop offset (25-ns steps). Unfortunately,"
"the 25-ns resolution requires more states when imitating."
"the the device controller."
drs.clk=CK;
drs.aclr=DCRST;

"When the Device Controller waits for the Device Receiver to"
"finish, it watches DRSZ."
DRSZ:=(drs==0);

"We synchronize TXI with CK, and create a delayed version"
"of TXIC with CK so we can detect edges in TXI in the device"
"receiver."
TXIC.clk=CK;
TXIC=TXI;

"The drs states mirror the pixel states for analog pixel readout,"
"and receives eight-bit serial data for data device readout."
state_diagram drs;
  state 0:
    if !PXEC & (dcs==px_1) then 1
    else if (dcs==rd_1) then 23
    else if (dcs==rd_3) then 23
    else 0;
  state 1:goto 2;
  state 2:if LOZ then 3 else 2;
  state 3:goto 4;
  state 4:goto 5;"data_device: D7 clock"
  state 5:goto 6;
  state 6:goto 7;"data_device: D6 clock"
  state 7:goto 8;
  state 8:goto 9;"data_device: D5"
  state 9:goto 10;
  state 10:goto 11;"data_device: D4 clock"
  state 11:goto 12;
  state 12:goto 13;"data_device: D3 clock"
  state 13:goto 14;"TC255_device: pixel clock"
  state 14:goto 15;"TC255_device: pixel clock, data_device: D2 clock"
  state 15:goto 16;"TC255_device: pixel clock"
  state 16:goto 17;"TC255_device: pixel clock, data_device:  D1 clock"
  state 17:goto 18;"TC255_device: store byte in RAM"
  state 18:goto 19;"data_device: D0 clock, TC255_device: increment data address"
  state 19:if CDS & (dcs==rd_2) then 19 else 20;"await !CDS for mrb store"
  state 20:goto 21;"data_device: store byte in RAM and mrb"
  state 21:goto 22;"data_device: increment data address"
  state 22:if (dcs==rd_2) then 0
    else if PXEC then 0 
    else 3;
  state 23:if (dcs==dcs_rest) then 0
    else if !TXIC then 3
    else 23; 
equations

"We clock most Device Receiver outputs and Device Controller outputs"
"with !CK."
[PCCK,LTEN,FTOL,HB16,CLAMP,ADC8,DCJD,CVT8S,
  PCCL,LCCK,LCCL,LTCL,DTEN,ADC16,CVT16,SSSR].clk=!CK;

"Detect Device Controller job done."
DCJD:=(dcs==dcs_done) # (dcs==rd_3);

"dcs_pause"
when (dcs==dcs_pause) then DTEN:=1;

"flash_job"
when (dcs==flash_2) then DTEN:=1;

"delay_job"
when (dcs==delay_1) then DTEN:=1;

"fast_toggle_job"
when (dcs==fast_toggle_1) then 
{
  FTOL:=RC0;
  DTEN:=1;
}

"loop_job"
when (dcs==loop_2) then LTCL:=SCKP0; "clear loop timer"
when (dcs==loop_3) then LTEN:=1; "run loop timer to max"
when (dcs==loop_4) then LTCL:=SCKP0; "clear again"
when (dcs==loop_5) then LTEN:=TXI; "run until receive low or max"
when (dcs==loop_5) then FTOL:=1; "send logic low"

"convert signal for adc8"
CVT8=CVT8A # CVT8S;

"adc8_job"
when (dcs==adc8_1) then
{
  CVT8S:=SCKP0; "initiate adc8 conversion"
  ADRS:=SCKP2; "store byte"
  DAI:=SCKP4; "increment data counter"
  ADC8:=1;"enable adc8 output"  
}

"fast_adc_job"
when (dcs==fast_adc_1) then
{
  DTEN:=!TAG; "wait for trigger then start delay timer"
  DAI:=!TAG; "increment data counter"
  ADC8:=1;"enable adc8 output"
  CVT8A=!CKOUT; "adc8 convert"
  ADRA=CKOUT; "store byte"
}

"adc16_job"
ADC16 := (dcs>=adc16_1) & (dcs<=adc16_4); "select adc16"
when ADC16 then DTEN:=!CLEN; "run the delay timer"
when (dcs==adc16_1) then CVT16:=1; "initiate 16-bit conversion"
when (dcs==adc16_2) then HB16:=1; "select high byte"
when (dcs==adc16_3) then HB16:=SCKP0; "select high byte"
when (dcs==adc16_3) then ADRS:=SCKP0; "store high byte"
when (dcs==adc16_3) then DAI:=SCKP2; "increment data address"
when (dcs==adc16_4) then ADRS:=SCKP2; "store low byte"
when (dcs==adc16_4) then DAI:=SCKP4; "increment data address"

"pixel and line counters"
when (dcs==dcs_rest) then PCCL:=1; 
when (dcs==dcs_rest) then LCCL:=1; 

"read_job for TC255_device"
when (dcs>=px_1) & (dcs<=ln_4) then {
  when (drs==1) then LOLD:=1;
  when (drs==2) then LOEN:=1;
  when (drs>=3)&(drs<=12) then PCCK:=1; 
  when (dcs==ln_2) then PCCL:=1; 
  when (dcs==ln_2) then LCCK:=1;
  when (dcs==px_3) then FTOL:=1; "send SRG clock directly"
  when !DRSZ then ADC8:=1; "select 8-bit ADC"
  when (drs>=3)&(drs<=8)&CLEN then CLAMP:=1; "charge clamp capacitor"
  when (drs==16) then CVT8S:=1; "convert 8-bit"
  when (drs==17) then ADRS:=1; "store byte"
  when (drs==18) then DAI:=1; "increment data address"
}

"read_job for data_device"
when (dcs>=rd_1) & (dcs<=rd_2) then {
  when (dcs==rd_1) then 
    FTOL:=1; "first device data strobe"
  when (dcs==rd_2) & (drs>=16) & (drs<=19) & !RCZ then 
    FTOL:=1; "subsequent device data strobes"
  when (drs==4) # (drs==6)  # (drs==8) # (drs==10) 
    # (drs==12) # (drs==14) # (drs==16) # (drs==18) then
    	SSSR:=1; "shift serial shift register"
  lwdaq_data=ssr;"store the data from serial shift register"
  ADI=1;"data from ssr is internal"
  when (drs==20) then ADRS:=1; "store byte"
  when (drs==21) then DAI:=1; "increment data address"
}

"move_job"
when (dcs==move_2) then LCCK:=1;

"alt_move_job"
when (dcs==alt_move_2) then LCCK:=1;

"toggle_job continues until the delay timer reaches zero."
when (dcs==toggle_1) then DTEN:=1;
when (dcs==toggle_2) then DTEN:=1;

"A2004 and A2031 Compatibility: We assert DAI twice to increment"
"the data address by two and make TC255 images identical to"
"those captured by the A2004 and A2031."
when (dcs==dcs_bridge) & (dtr==TC255_device) then 
  DAI:=SCKP1 # SCKP3;


"Device Command Bits"
"-------------------"


DC1=
  CR1 & DJCMD "CR1" 
# (dcs==ln_3) "DCEN, direct clock enable" 
# (dcs==ln_4) "DCEN, direct clock enable" 
# (dtr==LED_device) & (dcs==flash_1) & (der==0) "ON"
# (dtr==LED_device) & (dcs==flash_1) & (der==1); "ON1"

DC2=
  CR2 & DJCMD "CR2" 
# (dcs==ln_1) "!SRG, serial register gate" 
# (dcs==ln_4) "!SRG, serial register gate" 
# (dcs==move_2) "!SRG, serial register gate" 
# (dcs==alt_move_2) "!SRG, serial register gate" 
# (dtr==LED_device) & (dcs==flash_1) & (der==2); "ON2"

DC3=
  CR3 & DJCMD "CR3" 
# (dcs==ln_1) "SAG, storage area gate" 
# (dcs==ln_2) "SAG, storage area gate" 
# (dcs==move_2) "SAG, storage area gate" 
# (dcs==alt_move_2) "SAG, storage area gate" 
# (dcs==flash_1) & (der==3); "ON3"

DC4=
  CR4 & DJCMD "CR4" 
# (dcs==move_1) "IAGD, image area gate" 
# (dcs==alt_move_1) "IAGD, image area gate" 
# (dtr==LED_device) & (dcs==flash_1) & (der==4); "ON4"

DC5=
  CR5 & DJCMD "CR5" 
# (dcs==toggle_2); "ABGD, anti-blooming gate" 

DC6=
  CR6 & DJCMD "CR6" 
# (dcs==toggle_1) "ABEN, anti-blooming enable" 
# (dcs==toggle_2);"ABEN, anti-blooming enable" 

DC7=
  CR7 & DJCMD "CR7" 
# (dcs==loop_1); "LB" 

DC8=
  CR8 & DJCMD "CR8" 
# !DJSLP & !DJCMD; "WAKE on all devices" 

DC9=
  CR9 & DJCMD "CR9" 
# (dtr==TC255_device) & (der==1) & !DJCMD; "CCD2" 

DC10=
  CR10 & DJCMD "CR10" 
# (dtr==TC255_device) & (der==1) & (dcs==flash_1); "ON1" 

DC11=
  CR11 & DJCMD "CR11" 
# (dtr==TC255_device) & (der==2) & (dcs==flash_1); "ON2" 

DC12=
  CR12 & DJCMD "CR12" 
# (dtr==TC255_device) & (der==3) & (dcs==flash_1); "ON3" 

DC13=
  CR13 & DJCMD "CR13" 
# (dtr==TC255_device) & (der==4) & (dcs==flash_1); "ON4" 

DC14=
  CR14 & DJCMD; "CR14" 

DC15=
   CR15 & DJCMD; "CR15" 

DC16=
   CR16 & DJCMD; "CR16" 


"Pixel End Count"
"---------------"

when (dtr==TC255_device) then
{
  when (djr==read_job) then PXEC=(pixel_count==344);
}


"Line End Count"
"--------------"

when (dtr==TC255_device) then
{
  when (djr==read_job) then LNEC=(line_count==244);
  when (djr==move_job) then LNEC=(line_count==1000);
  when (djr==alt_move_job) then LNEC=(line_count==244);
}


"Pixel Counter"
"-------------"

pixel_count.clk=PCCK;
pixel_count.aclr=PCCL;
pixel_count:=pixel_count+1;


"Line Counter"
"------------"

line_count.clk=LCCK;
line_count.aclr=LCCL;
line_count:=line_count+1;


"Repeat Counter"
"--------------"

repeat_counter.clk=SCK;
repeat_counter.aclr=RESET;

RCZ0=(rcb0==0);
RCZ1=(rcb1==0);
RCZ2=(rcb2==0);
RCZ=RCZ0 & RCZ1 & RCZ2;

"We use the RCSEL nodes to reduce the repeat counter fan-in."
RCSEL0=CDS & CW & (control_addr==rc_addr+3);
RCSEL1=CDS & CW & (control_addr==rc_addr+2);
RCSEL2=CDS & CW & (control_addr==rc_addr+1);

"We decrement the repeat counter when DCJD and the counter."
"is not zero. Otherwise, we can write to the counter."
when DCJD & !RCZ then
{
  rcb0:=rcb0-1;
  when RCZ0 then rcb1:=rcb1-1;
  else rcb1:=rcb1;
  when RCZ0 & RCZ1 then rcb2:=rcb2-1;
  else rcb2:=rcb2;
}
else
{
  when RCSEL0 then rcb0:=[CD7..CD0];
  else rcb0:=rcb0;
  when RCSEL1 then rcb1:=[CD7..CD0];
  else rcb1:=rcb1;
  when RCSEL2 then rcb2:=[CD7..CD0];
  else rcb2:=rcb2;
}


"Delay Timer"
"-----------"

equations

delay_timer.clk=SCK;
delay_timer.aclr=RESET;

DTZ0=(dtb0==0);
DTZ1=(dtb1==0);
DTZ2=(dtb2==0);
DTZ=DTZ0 & DTZ1 & DTZ2;

"We use the DTSEL nodes to reduce the delay timer counter fan-in."
DTSEL0=CDS & CW & (control_addr==dt_addr+3);
DTSEL1=CDS & CW & (control_addr==dt_addr+2);
DTSEL2=CDS & CW & (control_addr==dt_addr+1);

"We restore the delay timer at the end of a job that will be repeated."
when DCJD & !RCZ then DTR=1;

"We decrement the delay timer when DTEN is asserted and the counter"
"has not yet reached zero. When DTR, we restore the delay timer to its"
"most recently written value."
when DTEN & !DTZ then
{
  dtb0:=dtb0-1;
  when DTZ0 then dtb1:=dtb1-1;
  else dtb1:=dtb1;
  when DTZ1 & DTZ0 then dtb2:=dtb2-1;
  else dtb2:=dtb2;
}
else 
{
  when DTR then delay_timer:=delay_timer_saved; 
  else
  {
    when DTSEL0 then dtb0:=[CD7..CD0];
    else dtb0:=dtb0;
    when DTSEL1 then dtb1:=[CD7..CD0];
    else dtb1:=dtb1;
    when DTSEL2 then dtb2:=[CD7..CD0];
    else dtb2:=dtb2;    
  }
}


"Delay Timer Saved"
"-----------------"

delay_timer_saved.clk=SCK;
delay_timer_saved.aclr=RESET;

"We clear the saved delay timer value when the device"
"controller has finished a job, and the repeat counter"
"is zero, meaning there will be no repeat executions."
"We write to the saved delay timer at the same time we"
"write to the delay timer itself."
when DCJD & RCZ & DTZ then delay_timer_saved:=0;
else
{
  when DTSEL0 then [DTSV7..DTSV0]:=[CD7..CD0];
  else [DTSV7..DTSV0]:=[DTSV7..DTSV0];
  when DTSEL1 then [DTSV15..DTSV8]:=[CD7..CD0];
  else [DTSV15..DTSV8]:=[DTSV15..DTSV8];
  when DTSEL2 then [DTSV23..DTSV16]:=[CD7..CD0];
  else [DTSV23..DTSV16]:=[DTSV23..DTSV16];
}


"Serial Shift Register"
"---------------------"

"We synchronise TXI with FCK for better resolution of incoming"
"data."
TXIF.clk=FCK;
TXIF:=TXI;

"We clock the counter-timer with CK and increment"
"it on CTI, which we clock with !CK."
ssr.clk=CK;
ssr.aclr=RESET;

when SSSR then {
  [SSR7..SSR0]:=[SSR6..SSR0,TXIF];
} else {
  [SSR7..SSR0]:=[SSR7..SSR0];
}

"Loop Timer"
"----------"

"The loop timer records the propagation delay between TXO"
"and TXI."
loop_time.clk=CK;
loop_time.aclr=RESET;

when LTCL then loop_time:=0;
else
{
  when LTEN then loop_time:=loop_time+1;
  else loop_time:=loop_time;
}

"Loop Timer Runout indicates the loop timer has reached"
"max_loop_time."
"A2031 incompatibility: the A2037 loop timer is only six"
"bit long, instead of seven, and the max_loop_time is"
"only 119 x 25 ns, corresponding to a 300-m cable instead"
"of a 600-m cable."
LTR:=(loop_time>=max_loop_time);
 

"Loop Offset"
"-----------"

"Loop Offset Enable and Loop Offset Load can be set by any"
"state machine using a 'when' statement. Otherwise they are"
"unasserted."
[LOEN,LOLD].clk=!CK;

loop_offset.clk=CK;
loop_offset.aclr=RESET;

when LOLD then loop_offset:=loop_time;
else 
{
  when LOEN then loop_offset:=loop_offset-1;
  else loop_offset:=loop_offset;
}

LOZ.clk=!CK;
LOZ:=(loop_offset==0)#(loop_offset>max_loop_time);


"Settling Delay Timer"
"--------------------"

"The settling delay timer runs when the device interface asserts"
"Run Settling Delay, and asserts End Settling Delay when it is"
"done. RSD may be asserted by any machine with a 'when' statement."
[RSD,RSDD,ESD].clk=SCK;

"We make a pulse out of an RSD rising edge using RSD Delayed"
"(RSDD), and we use this pulse to start an adc16 conversion,"
"which we use to time the settling delay. The A2037 adc16 takes"
"about 8 us for a conversion, so the settling delay is 8 us."
RSDD:=RSD;
when RSD & !RSDD then CVT16:=1;
when RSD then ADC16:=1;

"By the time both RSD and RSDD are high, the adc16 has asserted"
"BY16. When it unasserts BY16, we assert ESD."
ESD:=RSD & RSDD & !BY16;


"Multiplexer Controller"
"----------------------"

dar.clk=SCK;
dar.aclr=RESET;

when CDS & CW & (control_addr==dar_addr) then dar:=[CD7..CD0];
else dar:=dar;

"The Transmit Device Address state machine asserts TDA to tell"
"the Data Transmitter to transmit the new device address. It"
"waits for the Data Transmitter to reply with TDAC before it"
"unasserts TDA."
TDA.clk=CK;
state_diagram TDA;
  state 0:if CDS & CW & (control_addr==dar_addr) then 1 else 0;
  state 1:if TDAC then 0 else 1;
equations

"We enable one of the ten RJ45 ports on the A2037 based upon the"
"upper nibble of the device address register."
TXE0=(transceiver_select==0);
TXE1=(transceiver_select==1);
TXE2=(transceiver_select==2);
TXE3=(transceiver_select==3);
TXE4=(transceiver_select==4);
TXE5=(transceiver_select==5);
TXE6=(transceiver_select==6);
TXE7=(transceiver_select==7);
TXE8=(transceiver_select==8);

"We set the multiplex address outputs equal to the lower four bits"
"of the device address register."
[MA3..MA0]=[DAR3..DAR0];


"Data Transmitter"
"-----------------"

"The Data Transmitter works synchronously with the Bit Transmitter. It"
"activates the Bit Transmitter with ABT, and generates the next"
"bit when it receives TBC. We use ATA to mark each transmission as"
"an address or command."
ATA.aclr=RESET;
ATA.clk=!CK;
ATA:=(dts==0)&(TDA) # (dts!=0)&ATA;

dts.clk=CK;
dts.aclr=RESET;
state_diagram dts;
"Await TDA or TDC."
  state 0:if TDA # TDC then 1 else 0;

"If ATA then allow settling delay before transmission"
  state 1:if !ATA # ESD then 2 else 1;

"Transmit leading bit to indicate address or command."
  state 2:if TBC then 3 else 2;

"Transmit sixteen-bit serial data word"
  state 3:if TBC then 4 else 3;
  state 4:if TBC then 5 else 4;
  state 5:if TBC then 6 else 5;
  state 6:if TBC then 7 else 6;
  state 7:if TBC then 8 else 7;
  state 8:if TBC then 9 else 8;
  state 9:if TBC then 10 else 9;
  state 10:if TBC then 11 else 10;
  state 11:if TBC then 12 else 11;
  state 12:if TBC then 13 else 12;
  state 13:if TBC then 14 else 13;
  state 14:if TBC then 15 else 14;
  state 15:if TBC then 16 else 15;
  state 16:if TBC then 17 else 16;
  state 17:if TBC then 18 else 17;
  state 18:if TBC then 19 else 18;
 
"Transmit end bit."
  state 19:if TBC then 20 else 19;

"If ATA then allow settling delay before ending transmission."
  state 20:if ATA & !ESD then 20 else 21;

"Assert TDAC or TDCC and await negation of TDA or TDC."
  state 21:if ATA & !TDA # !ATA & !TDC then 0 else 21;
equations

"SB is the current serial bit. The final bit is always 1. The first bit of"
"a command transmission is 1, and of an address transmission is 0. We"
"transmit DC16 first. It will end up as the top bit in the device's control"
"register, while DC1 will be the bottom bit. When we transmit the value"
"of device_select, we do so with a single bit. At the end of the"
"transmission, all the bits in the multiplexer's address register will be"
"zero except the device_select'th bit, where the bottom bit is bit zero,"
"and the top bit is bit 15."
SB=(dts==2)&(!ATA) 
 # (dts==3)&(!ATA & DC16 # ATA & (device_select==15))  
 # (dts==4)&(!ATA & DC15 # ATA & (device_select==14))  
 # (dts==5)&(!ATA & DC14 # ATA & (device_select==13))  
 # (dts==6)&(!ATA & DC13 # ATA & (device_select==12))  
 # (dts==7)&(!ATA & DC12 # ATA & (device_select==11))  
 # (dts==8)&(!ATA & DC11 # ATA & (device_select==10))  
 # (dts==9)&(!ATA & DC10 # ATA & (device_select==9))  
 # (dts==10)&(!ATA & DC9 # ATA & (device_select==8))  
 # (dts==11)&(!ATA & DC8 # ATA & (device_select==7))  
 # (dts==12)&(!ATA & DC7 # ATA & (device_select==6))  
 # (dts==13)&(!ATA & DC6 # ATA & (device_select==5))  
 # (dts==14)&(!ATA & DC5 # ATA & (device_select==4))  
 # (dts==15)&(!ATA & DC4 # ATA & (device_select==3))  
 # (dts==16)&(!ATA & DC3 # ATA & (device_select==2))  
 # (dts==17)&(!ATA & DC2 # ATA & (device_select==1))  
 # (dts==18)&(!ATA & DC1 # ATA & (device_select==0))  
 # (dts==19);

"We clock the outputs of the data transmitter on the falling edge"
"of the state machine clock"
[LSB,ABT,TDCC,TDAC].clk=!CK;

"LSB marks the final serial bit."
LSB:=(dts==19);

"We assert ABT (activate bit transmitter) when we start transmitting"
"a command or address."
ABT:=(dts==2);

"We assert TDCC (transmit device command complete) when the"
"a data transmission has terminated."
TDCC:=!ATA & (dts==21);

"We assert TDAC (transmit device address complete) when the"
"an address transmission has terminated."
TDAC:=ATA & (dts==21);

"We assert RSD (run settling delay) before and after we transmit"
"the device address. The settling delay is several microseconds and"
"allows the newly-selected channel transmit lines to settle to lvds"
"voltage levels. After we transmit the address, we use the settling"
"delay once again to give the multiplexer outputs to settle as well."
when ATA & (dts==1) then RSD:=1;
when ATA & (dts==20) then RSD:=1;


"Bit Transmitter"
"---------------"

equations

bts.clk=CK;
bts.aclr=RESET;
SOUT.clk=!CK;

"The Bit Transmitter goes through the bit transmission cycle in"
"25-ns steps. It begins a serial data transmission with a 50-ns low"
"pulse. Then comes a 50-ns high pulse. Then it sends SB for 125 ns,"
"then it transmits LSB for 175 ns. The one-shot delay in the device"
"head can be anything between 88 ns and 175 ns, and the receiver"
"will still receive the incoming bit stream correctly. If LSB, and"
"therefor SOUT, is low, the Bit Transmitter goes back to the 50-ns"
"high pulse and starts transmitting the next bit. But if SOUT is"
"high, it knows it just transmitted the last bit, so it returns to"
"its rest state and waits for the next ABT."  
state_diagram bts;
  state 0:if ABT then 1 else 0;
  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 12;
  state 12:goto 13;
  state 13:goto 14;
  state 14:goto 15;
  state 15:goto 16;
  state 16:if SOUT then 0 else 3;
equations

"Here is SOUT in 25-ns steps, using SB (serial bit) and LSB (last"
"serial bit). We hold SOUT with feedback so the Data Transmitter"
"can change LSB after it receives TBC."
SOUT:= 
    (bts==0)
  # (bts==3) 
  # (bts==4)  
  # ((bts==5) & SB)
  # ((bts==6) & SB)
  # ((bts==7) & SB)
  # ((bts==8) & SB)
  # ((bts==9) & SB)
  # ((bts==10) & LSB)
  # ((bts==11) & SOUT)
  # ((bts==12) & SOUT)  
  # ((bts==13) & SOUT)  
  # ((bts==14) & SOUT)  
  # ((bts==15) & SOUT)  
  # ((bts==16) & SOUT);

"We assert TBC when when we have no further need for the current"
"value of STB. We assert TBC for one CK cycle only, and the"
"Data Transmitter moves on to the next bit."
TBC=(bts==9);


"Transceiver Output"
"------------------"

"The LVDS transmits SOUT unless FTOL is asserted, in which case it"
"sends out a zero. The Device Controller uses FTOL to override SOUT"
"and clock a signal in the device directly, once that signal has"
"been set up for direct clocking. SOUT is high between transmissions,"
"so FTOL forces low." 
TXO.clk=CK;
TXO:=SOUT & !FTOL;

"Test Pins"
"---------"

"The LEDs turn on when the test outputs are asserted. Note that"
"the TP outputs are active-low."
when 1 then {
  TP1=LNK $ CSW;
  TP2=ACT;
  TP3=PCCK;
  TP4=LCCK;
  TP5=!DTZ;
  TP6=!RCZ;
  TP7=TDA;
  TP8=TDC;
} else {


}

end