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

title 'LWDAQ Driver with VME Interface (A2037A)'

declarations

firmware_version_number=11;

"Version 11:"

"[09-JUL-08] Modify adc16_job so that when !CLEN, we run the"
"delay timer. This allows instruments like the Inclinometer to"
"do precisely-timed sampling with the sixteen-bit ADC. Increased"
"repeat counter from 16 bits to 23 bits, as it is in the A2037E."
"Made the TC255_device read_job more discriminating. Simplified"
"command bit logic by removing some device type conditions."

"[09-JUL]-08] Move pin numbers into source file. Change SCKOUT"
"to SCKP0 for consistency with P2037E."

"[09-JUL-08] Fix but in calculation of VW. The old version used"
"a combinatorial latch that failed in some devices. Now we make"
"VW a register."

"[09-JUL-08] Remove counter-timer 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."


"Version 10:"

"[14-OCT-05] EDP resets to 0."


"VME Bus"
VA1..VA31 pin 108,110,112,114,135,137,139,107,
  109,111,113,133,136,138,140,142,143,147,149,
  151,153,158,160,103..96; "vme address"
!DS0,!DS1 pin 163,165; "vme data strobes"
!AS pin 132; "vme address strobe"
!LWORD pin 164; "vme longword"
!IACK pin 146; "vme interrupt acknowledge"
VAM0..VAM5 pin 159,152,150,148,141,162; "vme address modifier"
!WRITE pin 161; "vme write"
VACK pin 169 istype 'reg'; "vme data acknowledge"
VD0..VD7 pin 184..181,176..173 istype 'com,pos'; "vme data"
!VDEN0..!VDEN1 pin 171,170 istype 'com,invert'; "vme data enable"
VDCK0..VDCK1 pin 189,172 istype 'com'; "vme data clock"
VDIR pin 188 istype 'com'; "vme direction"

"Switches"
BA19..BA31 pin 207..200,197..193; "board address"
LADDR pin 192; "long address"
TPC0..TPC1 pin 191,190; "test point configuration"
!MD0,!MD1 pin 49,48; "mode jumper field"
!HRST pin 168; "hardware reset"

"RAM"
RA0..RA18 pin 10..6,34..31,29..25,22,16..13 istype 'com'; "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';"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 'reg'; "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"
!BS node istype 'com,keep'; "board select (! reduces logic)"
BTS0..BTS4 node istype 'reg,keep'; "bit trasmitter state"
CD0..CD7 node istype 'com,keep,pos'; "control data"
CDS node istype 'com,keep'; "control data strobe"
CR1..CR16 node istype 'reg,keep'; "command register"
CSEL node istype 'com,keep'; "control select"
CVT8A node istype 'com,keep,pos'; "convert adc8 asynch"
CVT8S node istype 'reg,keep,pos'; "convert adc8 synch"
DA0..DA18 node istype 'reg,keep'; "data address"
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 'reg,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..DTR1 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"
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"
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,keep,pos'; "line end count"
LA0..LA1 node istype 'com,keep'; "lwdaq address"
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"
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,pos,keep'; "pixel end count"
RC0..RC23 node istype 'reg,keep'; "repeat counter"
RCSEL0..RCSEL2 node istype 'com,keep'; "repeat counter select"
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"
RDOE node istype 'com,keep'; "ram output enable"
RESET node istype 'com,keep'; "internal global RESET"
RPSEL node istype 'com,keep'; "ram portal select"
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"
SCKS node istype 'reg,keep'; "slow clock select"
SDS0,SDS1 node istype 'reg,keep'; "synchronized data strobes"
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"
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"
TXIS node istype 'reg,keep'; "TXI synchronized to SCK"
VA0 node istype 'reg,keep'; "vme address bit zero"
!VCA node istype 'reg,keep'; "vme cycle active"
VCCS0..VCCS4 node istype 'reg,keep'; "vme cycle controller state"
VDOE node istype 'keep'; "vme output enable"
VDS node istype 'reg,keep'; "vme data strobe" 
VDSD node istype 'reg,keep'; "VDS delayed" 
VVAC node istype 'com,keep'; "valid vme address code"
VVAM node istype 'com,keep'; "valid vme address modifier"
VW node istype 'reg,keep'; "vme data write"

"Sets"
control_addr=[VA5..VA0]; "local control address"
addr_modifier=[VAM5..VAM0]; "vme address modifiers"
vcc_state=[VCCS4..VCCS0]; "vme cycle controller state"
pixel_count=[PC9..PC0]; "for image retrieval"
line_count=[LC9..LC0]; "for image retrieval"
ram_data=[RD7..RD0]; "ram data bus"
ram_addr=[RA18..RA0]; "ram address bus"
control_data=[CD7..CD0]; "control data bus"
vme_data=[VD7..VD0]; "vme data bus"
vme_local_addr=[VA18..VA0]; "local VME address"
lwdaq_data=[AD7..AD0]; "lwdaq data bus"
lwdaq_addr=[LA1..LA0]; "lwdaq address 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=[DTR1..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=[DA7..DA0]; "data address byte zero"
dab1=[DA15..DA8]; "data address byte one"
dab2=[DA18..DA16]; "data address byte two"
data_addr=[DA18..DA0]; "data address from address counter"
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"
tpc=[TPC1..TPC0]; "test point configuration"
mode=[MD1..MD0]; "operating mode"


"Locations"
id_addr=0;"identifier location (byte)"
sr_addr=1;"status register 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 (four-byte)"
da_addr=24; "data address location (four-byte)"
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 (four-byte)"
ctcr_addr=39; "c-t config reg location (byte)"
cs_addr=40; "configuration switch location (byte, A2037E, A2037V)"
srst_addr=41; "software reset location (byte)"
dba_addr=42; "driver base address location (four-byte, A2037V)"
vam_addr=46; "vme address modifier location (byte, A2037V)"
ram_portal_addr=63; "ram portal location (byte)"

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

"Slow Clock Select (SCKS) is high before and after the rising"
"edge of SCK. We use it to select the rising edge of CK that"
"coincides with the rising edge of SCK."
SCKS.clk=FCK;
SCKS:=(mcs==9)#(mcs==0);

"The Slow Clock Phases (SCKP1..SCKP4) are the second to fifth"
"phases of 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);


"VME Cycle Controller"
"--------------------"

"The VME interface is data-strobe controlled, so we do not use"
"the address strobe (AS). Nevertheless, AS is connected to the"
"A2037 to support it's later use as a VME master."

declarations

vcc_rest   =^h00;
vcc_active =^h0F;
vcc_byte_01=^h01;
vcc_byte_02=^h02;
vcc_byte_03=^h03;
vcc_byte_04=^h04;
vcc_byte_05=^h05;
vcc_byte_06=^h06;
vcc_byte_11=^h11;
vcc_byte_12=^h12;
vcc_byte_13=^h13;
vcc_byte_14=^h14;
vcc_byte_15=^h15;
vcc_byte_16=^h16;
vcc_terminate=^h1F;

equations

VVAM = 
    (addr_modifier==^h09) & LADDR  "32-bit non-privileged access"
  # (addr_modifier==^h0D) & LADDR "32-bit supervisory access"
  # (addr_modifier==^h39) & !LADDR "24-bit non-privileged access"
  # (addr_modifier==^h3D) & !LADDR; "24-bit supervisory access"

VVAC = !LWORD & !IACK;

BS = 
    LADDR & ([VA31..VA19]==[BA31..BA19])
  #!LADDR & ([VA23..VA19]==[BA23..BA19]);

"We synchronize the data strobes with the internal clock."
[SDS0,SDS1].clk=!CK;
SDS0:=DS0;
SDS1:=DS1;

"We clock the state machine with CK, and clear it on RESET."
vcc_state.clk=CK;
vcc_state.aclr=RESET;

"We clock the vcc outputs on !CK, except VACK (see below)."
[VCA,VA0,VDS,VDSD].clk=!CK;
VACK.clk=CK;

"The setup time for our 7-ns ISP chip is 4 ns. The VME address setup"
"before data strobe is 10 ns. The synchronization delay of SDS0 and SDS1"
"is at least 12 ns. The address decoder has 10 + 12 - 4 = 18 ns to"
"decode the address. In vcc_rest we await DS0 or DS1. In vcc_active,"
"we give both data strobes time to settle. We also synchronize the data"
"exchange with the SCK clock using SCKS." 
state_diagram vcc_state;
  state vcc_rest:
    if  VVAM & VVAC & BS & (SDS0 # SDS1) then vcc_active;
    else vcc_rest;
  state vcc_active:
    if SCKS then 
    {
    if SDS0 then vcc_byte_01;
    if !SDS0 & SDS1 then vcc_byte_11;
    if !SDS0 & !SDS1 then vcc_terminate;
    }
    else vcc_active;
  state vcc_byte_01:goto vcc_byte_02;
  state vcc_byte_02:goto vcc_byte_03;
  state vcc_byte_03:goto vcc_byte_04;
  state vcc_byte_04:goto vcc_byte_05;
  state vcc_byte_05:goto vcc_byte_06;
  state vcc_byte_06:
    if SDS1 then vcc_byte_11;
    if !SDS1 then vcc_terminate;
  state vcc_byte_11:goto vcc_byte_12;
  state vcc_byte_12:goto vcc_byte_13;
  state vcc_byte_13:goto vcc_byte_14;
  state vcc_byte_14:goto vcc_byte_15;
  state vcc_byte_15:goto vcc_byte_16;
  state vcc_byte_16:goto vcc_terminate;
  state vcc_terminate:
    if !SDS0 & !SDS1 then vcc_rest;
    else vcc_terminate;
equations

"VME Cycle Active (VCA), declares that the VME bus is accessing"
"this board. We declare node !VCA so that the logic calculation"
"will be vcc_state==vcc_rest."
VCA:=(vcc_state!=vcc_rest);

"VACK drives DTACK* through a 74S38. We clock VACK on !CK"
"so that it will be delayed by 12 ns, ensuring that DTACK"
"will not be asserted before the VME data lines are valid,"
"nor released before the data lines are released."
VACK:=(vcc_state==vcc_terminate);

"VA0 completes the VME byte address, and also acts as an"
"indicator of the byte the VME Cycle Controller is currently"
"reading from or writing to. We use VA0 to complete our"
"control and ram addresses. Our internal data buses are only"
"eight bits wide."
VA0:=(vcc_state>=vcc_byte_01) & (vcc_state<=vcc_byte_06);
 
"The VME Address Decoder uses VDS (vme data strobe) to strobe"
"registers and memory."
VDS:=( (vcc_state>=vcc_byte_02) & (vcc_state<=vcc_byte_05) )
  # ( (vcc_state>=vcc_byte_12) & (vcc_state<=vcc_byte_15) );

"We use VDSD in conjunction with VDS to detect the end"
"of a VDS pulse."
VDSD:=VDS;

"VW is a latched version of the VME WRITE signal. VW holds"
"the value of WRITE set up at the beginning of a VME cycle"
"until the cycle ends."
VW.clk=VCA;
VW:=WRITE;

"VDCKx clocks data byte x into the output buffers as early as"
"possible during a VME cycle."
VDCK0 = CKOUT & VDS & VA0;
VDCK1 = CKOUT & VDS & !VA0;

"VDIR drives the DIR input of the data buffers."
VDIR=!VW;

"The VDENx signals enable the VME data buffers. On read cycles,"
"these buffers must drive the data lines even after the address lines"
"have started to change in anticipation of the next cycle. The VDCKx"
"signals clock the data into the buffers. The buffers are enabled on"
"read cycles while VCA is asserted, and on write cycles during the"
"appropriate byte read of the VME Cycle Controller's write cycle."
VDEN0 = (!VW & VCA) # (VW & VCA & VA0);
VDEN1 = (!VW & VCA) # (VW & VCA & !VA0);


"Address Decoder"
"---------------"

equations

"We select the control registers with vme addresses in the"
"range zero to num_control_bytes-1."
CSEL = VCA & (vme_local_addr20 ns on read cycles"
"and >30 ns on write cycles. On read cycles, the selected"
"control register must establish its data on the control"
"data bus within 70 ns of the falling edge of CDS." 
CDS = VDS & (vme_local_addr=num_control_bytes);

"We assert RPSEL when the VME interface reads or writes to"
"RAM indirectly through the ram portal."
RPSEL = !BUSY & VCA & (vme_local_addr==ram_portal_addr);

"The RAM address is equal to the data address when we assert"
"BUSY or when we are reading the ram portal. Otherwise it is"
"equal to the VME address."
when BUSY # RPSEL then ram_addr = data_addr
else ram_addr = vme_local_addr;



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

equations

"We write to the RAM on VME write cycles and when BUSY"
RWE = BUSY # (!BUSY & VW);

"We enable the RAM output on any VME read."
ROE = !BUSY & !VW;

"We drive the VME data lines on any VME read."
VDOE = !VW;
vme_data.oe = VDOE;

"We drive the RAM data lines on a VME write or during BUSY."
RDOE = VW # BUSY;
ram_data.oe = RDOE;

"When the VME interface addresses the control registers,"
"we set the VME data equal to the control data."
when CSEL & !RPSEL then vme_data = control_data;

"When the VME interface addresses the RAM, we set"
"the VME data equal to the RAM data, as seen on the"
"pins connected to the RAM chip."
when RSEL # RPSEL then vme_data = ram_data.pin;

"When the VME interface writes to the control registers,"
"we set the control data equal to the VME data, as seen"
"on the pins connected to the VME data buffers."
when VW then control_data = vme_data.pin;

"When we are not commandeering the RAM for data storage,"
"we set the internal RAM data equal to the VME data, as"
"seen on the pins connected to the VME data buffers."
when !BUSY then ram_data = vme_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
else RCE = VDS;

"We increment the data address whenever we read a byte through"
"the ram portal at ram_portal_addr."
when (RPSEL & VDSD & !VDS) then DAI:=1;

"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. Both ADR Synchronous (ADRS) and ADR"
"Asynchronous (ADRA) to choose from. We clock ADRS with"
"!CK."
ADRS.clk=!CK;


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

equations

"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 & VW & (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.fb+1;
  else dab1:=dab1.fb;
  when DAC1 & DAC0 then dab2:=dab2.fb+1;
  else dab2:=dab2.fb;
}

"We set the data address via the Control Register interface. 
"We use the DASEL nodes to reduce the data address fan-in."
DASEL0=CDS & VW & (control_addr==da_addr+3);
DASEL1=CDS & VW & (control_addr==da_addr+2);
DASEL2=CDS & VW & (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.fb;
  when DASEL1 then dab1:=[CD7..CD0];
  else dab1:=dab1.fb;
  when DASEL2 then dab2:=[CD2..CD0];
  else dab2:=dab2.fb;    
}


"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 & !VW & (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 & !VW & (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 & !VW & (control_addr==id_addr) then
  [CD7..CD0]=id_byte; "37 identifies the A2037"

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

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

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


"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 & VW & (control_addr==srst_addr)) then SRST:=1;
else SRST:=0;


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

"Enable Device Power (EDP) 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 EDP via the Control Register interface."
"After RESET, EDP is set to one."
EDP.clk=SCK;
EDP.aclr=RESET;
when (CDS & VW & (control_addr==edp_addr)) then EDP:=CD0;
else EDP:=EDP.fb;
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 & VW & (control_addr==clen_addr) then CLEN:=CD0;
else CLEN:=CLEN.fb;


"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 & VW & (control_addr==cr_addr+1) then [CR1..CR8]:=[CD0..CD7]
else [CR1..CR8]:=[CR1..CR8].fb;
when CDS & VW & (control_addr==cr_addr) then [CR9..CR16]:=[CD0..CD7]
else [CR9..CR16]:=[CR9..CR16].fb;


"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 & VW & (control_addr==dtr_addr) then dtr:=[CD1..CD0];
else dtr:=dtr.fb;


"Here we declare the device types supported by this version"
"of the firmware."
"A2031 incompatibility: A2037 does not support the A2029,"
"but instead treats device type zero as a null device."
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 & VW & (control_addr==der_addr) then der:=[CD2..CD0];
else der:=der.fb;


"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; "overrides 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 & VW & (control_addr==djr_addr) then djr:=[CD3..CD0];
  else djr:=djr.fb;
}

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

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 & VW & (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."
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: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!=loop_job) then dcs_bridge;

  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 dcs_bridge:goto px_1;

  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 pixel 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;
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);

"The drs states mirror the pixel states."
state_diagram drs;
  state 0:if !PXEC & (dcs==px_1) then 1 else 0;
  state 1:goto 2;
  state 2:if LOZ then 3 else 2;
  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;"synchronized with data"
  state 14:goto 15;"synchronized with data"
  state 15:goto 16;"synchronized with data"
  state 16:goto 17;"synchronized with data"
  state 17:goto 18;
  state 18:goto 19;
  state 19:goto 20;
  state 20:goto 21;
  state 21:goto 22;
  state 22:if PXEC then 0 else 3;
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].clk=!CK;

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

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

"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 TC255P images identical to"
"those captured by the A2004 and A2031."
when (dcs==dcs_bridge) then DAI:=SCKP1 # SCKP3;


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

[DC1..DC16].clk=!CK;

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" 
# (dtr==LED_device) & (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.fb+1;


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

line_count.clk=LCCK;
line_count.aclr=LCCL;
line_count:=line_count.fb+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 & VW & (control_addr==rc_addr+3);
RCSEL1=CDS & VW & (control_addr==rc_addr+2);
RCSEL2=CDS & VW & (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 & VW & (control_addr==dt_addr+3);
DTSEL1=CDS & VW & (control_addr==dt_addr+2);
DTSEL2=CDS & VW & (control_addr==dt_addr+1);

"We decrement the delay timer when DTEN is asserted and the counter"
"has not yet reached zero. Otherwise, we load the saved"
"delay time into the delay timer when the device controller has"
"finished executing a job, but the repeat counter is not yet zero."
"Otherwise, we can write to the delay timer, or let it sit."
when DTEN & !DTZ then
{
  dtb0:=dtb0-1;
  when DTZ0 then dtb1:=dtb1.fb-1;
  else dtb1:=dtb1.fb;
  when DTZ1 & DTZ0 then dtb2:=dtb2.fb-1;
  else dtb2:=dtb2.fb;
}
else 
{
  when DCJD & !RCZ & DTZ then delay_timer:=delay_timer_saved; 
  else
  {
    when DTSEL0 then dtb0:=[CD7..CD0];
    else dtb0:=dtb0.fb;
    when DTSEL1 then dtb1:=[CD7..CD0];
    else dtb1:=dtb1.fb;
    when DTSEL2 then dtb2:=[CD7..CD0];
    else dtb2:=dtb2.fb;    
  }
}


"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].fb;
  when DTSEL1 then [DTSV15..DTSV8]:=[CD7..CD0];
  else [DTSV15..DTSV8]:=[DTSV15..DTSV8].fb;
  when DTSEL2 then [DTSV23..DTSV16]:=[CD7..CD0];
  else [DTSV23..DTSV16]:=[DTSV23..DTSV16].fb;
}


"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.fb+1;
  else loop_time:=loop_time.fb;
}

"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.fb-1;
  else loop_offset:=loop_offset.fb;
}

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 conversion,"
"which we use to time the settling delay."
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 & VW & (control_addr==dar_addr) then dar:=[CD7..CD0];
else dar:=dar.fb;

"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 & VW & (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.fb;

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.fb, 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.fb)
  # ((bts==12) & SOUT.fb)  
  # ((bts==13) & SOUT.fb)  
  # ((bts==14) & SOUT.fb)  
  # ((bts==15) & SOUT.fb)  
  # ((bts==16) & SOUT.fb);

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


"Bread Board Area"
"----------------"

"K1..K4 are inputs in this firmware."


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

"The LEDs turn on when the test outputs are asserted. But note that"
"the TP outputs are active-low."

TP1=PCCK;
TP2=LCCK;
TP3=!DTZ;
TP4=CDS;
TP5=CVT8#CLAMP#CVT16;
TP6=(dcs==loop_5);
TP7=TDA;
TP8=TDC&!TDA;

end