"
" Copyright (C) 2011-2015 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 P2071 title 'LWDAQ Driver' declarations "Firmware and hardware versions." firmware_version_number=9; controller_hardware_id=71; "Version 9:" "[05-APR-18] Add source device type 9, multisource_device, for generic LWDAQ devices" "that require a flash job." "Version 8:" "[10-JUL-17] Add the !VME input that we pull down in the VME version of the hardware" "and leave floating in the Ethernet version. This flag we use to modify the firmware" "behavior dynamically depending upon the hardware. With VME asserted, the head power" "resets to OFF. With VME unasserted, head power resets to ON. With VME asserted, the" "hardware version number is 16 plus the two-bit number in the hardware version bits." "Version 7:" "[14-SEP-15] Correct a problem with flash job for IXC424Q type, where we did not hold" "V2 and V3 HI." "NOTE: After we clear the ICX424, we drive V1 LO and V2 and V3 HI. We do the same" "during a flash job. If not, we will usually obtain good images anyway, but some sensors" "exhibit a bright rectangle in the center of dark current, the origin of which we do not" "understand, other than that it disappears if we driver the vertical clock lines correctly." "We make sure to leave V2 HI during a loop job, while V1 and V3 are LO. The loop job follows" "a read pulse, and preceeds a read_job. After the read pulse, our image capture software" "uses a command job to set V2 HI, which keeps the image charge under the V2 clock line." "The read_job uses a loop_job to measure loop time, and during this loop_job we transmit" "a command to the ICX device. This command must have V2 HI so that the image will be" "held intact during the loop time measurement." "Version 6:" "[01-APR-15] Add support for image sensors 3 and 4 and light sources 7-10 for CCD devices." "For these device elements, we set DC14 and DC15, which are VDS0 and VDS1 respectively in" "the device firmware, for Virtual Device Select." "Version 5:" "[22-DEC-14] Add support for the KAF-0261C, device type 8." "Version 4:" "[12-FEB-13] Add support for up to fourteeen light sources in LED devices. We don't have" "to assert V3 during flashes, so we now hold only V2 high during flashes of ICX424 and" "ICX424Q." "Version 3:" "[16-NOV-12] Add support for up to six light sources in CCD devices. Make sure that the" "IXC424's V2 and V3 lines are held high during flashes of its own light" "sources." "Version 2:" "[09-MAR-12] Add support for device elements 5 and 6 in device type LED." "Sort out and debug the ICX424 image sensor readout. In particular, we make sure" "that V2 is asserted during the loop-back job that preceeds readout. Otherwise the" "image charge starts spreading about the place." "Eliminate DCEN for ICX424 and use DC1 for RDP instead. Add ICX424Q device type," "which obtains a quarter-sized image by binning rows using the vertical phases" "controlled by the driver, and directs the device to bin columns. We use DC16 to" "select the column binning in the device. We increase the number of columns and" "rows in the ICX424 image so as to get all the image pixels. The ICX424Q image is" "half the number of rows and columns." "Version 1:" "[09-DEC-11] Start with P2037E15 prototype version. Add four RAM address lines and various" "other inputs and outputs of the A2071E that differ from the A2037E. Speed up the" "interface with the relay so as to support RCM6700 with 15 wait states. Change" "to CK gated by SCKP0 in delay timer and repeat counter." "Interface with RCM6700 Relay" !LNK pin 85; "ethernet link and activity, from RCM6700" CA0..CA5 pin 124, 121, 125, 122, 120, 123; "control address, from RCM6700" !CW pin 86; "control write, from RCM6700" !DS pin 87; "data strobe, from RCM6700" D0..D7 pin 111, 115, 112, 116, 113, 117, 114, 118; "control data, from RCM6700" "Switches and Jumpers" HV0,HV1 pin 16, 17; "hardware version" !HRST pin 5; "hardware reset" !CSW pin 82; "configuration switch" !VME pin 60; "VME circuit flag" "Ethernet Socket Lights" EGRN pin 83 istype 'com'; "green lamp" EYLW pin 84 istype 'com'; "yellow lamp" "RAM" RA0..RA20 pin 161, 162, 163, 164, 165, 159, 160, 158, 141, 142, 140, 139, 138, 137, 136, 135, 146, 147, 148, 149, 145 istype 'reg'; "ram address" RD0..RD7 pin 168, 169, 173, 172, 174, 175, 171, 170 istype 'com,dc'; "ram data, bidirectional" !RE1..!RE4 pin 126, 127, 152, 150 istype 'com'; "ram enable" !RW pin 151 istype 'com'; "ram write" "Clock Bus" FCK pin 66; "fast clock (80 MHz) in from oscillator" CKOUT pin 37 istype 'reg';"clock (40 MHz) out" CK pin 154; "clock (40 MHz) in from CKOUT" SCKP0 pin 70 istype 'reg,keep';"slow clock (8 MHz) out" SCK pin 68; "slow clock (8 MHz) in from SCKP0" "Test Pins" TP1..TP8 pin 7, 8, 9, 10, 11, 12, 14, 15 istype 'com,pos'; "test pins with LEDs" "Devices" !TXE0..!TXE8 pin 32, 18, 19, 20, 21, 23, 24, 25, 26 istype 'com'; "transceiver enable" AD0..AD7 pin 100, 99, 98, 97, 96, 95, 94, 93 istype 'com,pos'; "acquired data" CLAMP pin 106 istype 'reg,pos'; "zero the input clamp" CLEN pin 107 istype 'reg,pos'; "enable ADC8 clamp, delay ADC16 count-down" CVT8 pin 108 istype 'com,pos'; "adc8 convert" !ADC8 pin 109 istype 'reg,pos'; "adc8 output enable" !CVT16 pin 103 istype 'reg,pos'; "adc16 convert" !ADC16 pin 104 istype 'reg,pos'; "adc16 output enable" HB16 pin 102 istype 'reg,pos'; "adc16 high byte select" !BY16 pin 105; "adc16 busy" BUSY pin 6 istype 'reg'; "controller busy" TXI pin 35; "transeiver input" TXO pin 34 istype 'reg'; "transceiver output" "Head Power Control" MA0..MA3 pin 30, 29, 28, 33 istype 'com'; "multiplexer address output" ENH pin 27 istype 'com'; "enable head power" "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" CCDD node istype 'com,keep'; "CCD Device" 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..DER3 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" DJRD node istype 'com,keep'; "device job read" 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..DTR3 node istype 'reg,keep'; "device type register" DTRS node istype 'com,keep'; "delay timer restore" 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" 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" PXBN node istype 'com,neg,keep'; "pixel binning" RC0..RC23 node istype 'reg,keep'; "repeat counter" RA21..RA22 node istype 'reg,keep'; "upper ram address bits" 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" RSEL node istype 'com,keep'; "ram select" SB node istype 'com,keep'; "serial bit" SCKP1..SCKP4 node istype 'reg,keep'; "slow clock phases" SDT0..SDT5 node istype 'reg,keep'; "Settling Delay Timer" 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" TC255 node istype 'com,keep'; "TC255 device type bit" 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" TWPH node istype 'com,keep'; "two-phase ccd" 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=[RA22..RA0]; "data address" dab0=[RA7..RA0]; "data address byte zero" dab1=[RA15..RA8]; "data address byte one" dab2=[RA22..RA16]; "data address byte two" control_data=[CD7..CD0]; "control data bus" control_addr=[CA5..CA0]; "local control address" 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=[DTR3..DTR0]; "device type register" der=[DER3..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" 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]; "most recent byte" sdt=[SDT5..SDT0]; "settling delay timer" "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)" 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" "Master Clock Generator" "----------------------" equations "Here we use the fast clock (FCK), which is 80 MHz, to generate" "the global CK clock, which si 40 MHz, and the global slow clock," "which is 8 MHz." "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 write cycles, and expects valid data on the falling" "edge of CDS on read cycles." 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" RW = 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 = RW; "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; "RE1..4 enable RAM chips 1 through 4, each of which provides" "2 MBytes of memory. On write cycles, asserting RE writes data" "into RAM, and on read cycles, RE enables the RAM output buffer." "We can assert RE for as little as one FCK period and ensure" "storage in RAM. We use Acquired Data Ready (ADR), both the" "synchronous and asynchronous versions, to generate RE We select" "the RAM chip using the upper two bits of the data address." when BUSY then { RE1 = (ADRA # ADRS) & !RA22 & !RA21; RE2 = (ADRA # ADRS) & !RA22 & RA21; RE3 = (ADRA # ADRS) & RA22 & !RA21; RE4 = (ADRA # ADRS) & RA22 & RA21; } else { RE1 = CDS & RSEL & !RA22 & !RA21; RE2 = CDS & RSEL & !RA22 & RA21; RE3 = CDS & RSEL & RA22 & !RA21; RE4 = CDS & RSEL & RA22 & RA21; } "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 RW & BUSY & (RE1 # RE2 # RE3 # RE4) 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. We have both ADR Synchronous" "(ADRS) and ADR Asynchronous (ADRA) to choose from. Here" "we clock ADRS with !CK. The ADRS signal is generated" "elsewhere, but is unasserted by default." ADRS.clk=!CK; "Data Address" "------------" 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; [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:=[CD6..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." when CDS & !CW & (control_addr==sr_addr) then { CD7=DTEN; CD6=TDC; CD5=TDA; CD4=!RCZ; CD3=BUSY; CD2=BY16; CD1=LTEN; CD0=RSD; } "Identification Byte." when CDS & !CW & (control_addr==id_addr) then [CD7..CD0]=controller_hardware_id; "Firmware Version Number" when CDS & !CW & (control_addr==fv_addr) then [CD7..CD0]=firmware_version_number; "Hardware Version Number. When the VME flag is asserted," "the hardware version is 16 + the two hardware version bits." "Otherwise the version is just the two bits." when CDS & !CW & (control_addr==hv_addr) then { when VME then { [CD7..CD0]=[0,0,0,0,1,0,HV1,HV0]; } else { [CD7..CD0]=[0,0,0,0,0,0,HV1,HV0]; } } "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 CK cycle." SRST.clk=CK; 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 ENH output turns on and" "off the device power. On RESET, we turn off the device power" "and then turn it on again when RESET is released." EDPR.clk=CK; when VME then { EDPR.aclr=RESET; } else { EDPR.ap=RESET; } when (CDS & CW & (control_addr==edp_addr)) then EDPR:=CD0; else EDPR:=EDPR; ENH=EDPR & !RESET; "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=CK; 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=CK; [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=CK; dtr.aclr=RESET; when CDS & CW & (control_addr==dtr_addr) then dtr:=[CD3..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; KAF0400_device=4; TC237_device=5; ICX424_device=6; ICX424Q_device=7; KAF0261_device=8; multisource_device=9; equations "The CCDD bit is set whenever the target device is an image" "sensor whose image we are going to read out and digitize" "on the driver. This one bit saves us from bringing the four" "device type bits into the device command bit calculations" "later on, and so allows us to pack more logic into this" "chip." CCDD = (dtr == TC255_device) # (dtr == TC237_device) # (dtr == KAF0400_device) # (dtr == ICX424_device) # (dtr == ICX424Q_device) # (dtr == KAF0261_device); "The TC255 bit is set when we select a TC255 device, which" "is unusual in the complexity of its anti-blooming control." TC255 = (dtr == TC255_device); "The Two-Phase CCD (TWPH) bit is set when the target sensor" "is a single or two-phase device, in which the vertical" "clocks are each the negative of the other." TWPH = (dtr == TC255_device) # (dtr == TC237_device) # (dtr == KAF0400_device) # (dtr == KAF0261_device); "Pixel Binning (PXBN) instructs the device controller to" "double-clock the lines, and to instruct the device to double-" "clock the columns by setting DC16." PXBN = (dtr == ICX424Q_device); "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." der.clk=CK; der.aclr=RESET; when CDS & CW & (control_addr==der_addr) then der:=[CD3..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; unused_job=14; fast_adc_job=15; equations djr.clk=CK; 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); "DJRD indicates a read job, and reduces logic complexity later." DJRD=(djr==read_job); "BUSY indicates that the Device Controller is executing a job, and" "that it is commandeering the RAM for uninterrupted data storage." BUSY.clk=CK; 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; toggle_1=fast_toggle_1+1; toggle_2=toggle_1+1; move_1=toggle_2+1; move_2=move_1+1; move_3=move_2+1; move_4=move_3+1; move_5=move_4+1; move_6=move_5+1; move_done=move_6+1; alt_move_1=move_done+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; ln_5=ln_4+1; ln_6=ln_5+1; ln_7=ln_6+1; ln_8=ln_7+1; ln_9=ln_8+1; ln_10=ln_9+1; ln_11=ln_10+1; ln_12=ln_11+1; rd_1=ln_12+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 if CCDD then loop_1; else dcs_done; 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==unused_job:dcs_done; djr==fast_adc_job:fast_adc_1; endcase; "The pause state is where we are waiting for the delay time" "to count down to zero before completing the job." state dcs_pause:if DTZ then dcs_done else dcs_pause; "In the done state, we assert DCJD (device controller job done)," "which decrements the repeat counter." state dcs_done:goto dcs_rest; "The flash job sends a type-dependent switch-on command to" "the target device, waits for the delay time, and sends a" "a switch-off command that leaves the device awake but the" "source turned off." 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; "The delay job simply holds up the device controller for a" "fixed length of time." state delay_1:if DTZ then dcs_done else delay_1; "The fast toggle job transmits a logic HI on TXO when the" "repeat counter is even and a LO on TXO when the repeat counter" "is odd. The job lasts for the delay time, and the idea is that" "we repeat the job to sustain a square wave at the device for" "an exact length of time and an exact number of cycles." state fast_toggle_1:if DTZ then dcs_done else fast_toggle_1; "The adc16 job initiates a conversion in the sixteen-bit" "ADC and stores the upper and lower bytes in RAM." 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; "The adc8 job initiates a conversion in the eight-bit ADC" "and stores the result in RAM." state adc8_1:goto dcs_pause; "The fast adc8 job digitizes the eight-bit ADC input repeatedly" "at 40 MHz, storing each result in RAM, until the delay time" "has expired." state fast_adc_1:if DTZ then dcs_done else fast_adc_1; "The command job sends a command to the target device." state command_1:if !TDC then dcs_done else command_1; "The loop job sends a loop command to the target device, asserts" "a logic LO on TXO and waits for this LO to return on TXI. While" "waiting, we run the loop timer to get the loop time." 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: "All jobs that use loop_1 must be accounted for here." if (TXIS & !LTR) then loop_5; if !(TXIS & !LTR)&(djr==loop_job) then dcs_done; if !(TXIS & !LTR)&(djr==read_job) then dcs_bridge; "The bridge state allows us to increment the data address before" "CCD read jobs, so that the first data pixel is at the correct location" "in RAM. The various LWDAQ Driver circuits use eight-bit ADCs with" "different internal pipeline lengths, so for backward copatibility we" "must adjust the first pixel location for newer circuits." state dcs_bridge:goto px_1; "The toggle job transmits two alternating type-dependent commands to" "the target. Each command endures in the device for around 4 us, which" "is the command transmission time. We continue performing this alternation" "until the delay time expires." 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; "The move job clears a CCD of charge by transmitting a sequence of commands" "to clock lines down and out of the image area. We transmit this sequence" "a number of times that is a function of the device type, rather than dictated" "by the repeat counter or delay timer." state move_1: if !TDC then {if !SLNEC then move_2 else move_done} else move_1; state move_2: if !TDC then {if TWPH then move_1 else move_3} else move_2; state move_3: if !TDC then move_4 else move_3; state move_4: if !TDC then move_5 else move_4; state move_5: if !TDC then move_6 else move_5; state move_6: if !TDC then move_1 else move_6; state move_done: if !TDC then dcs_done else move_done; "The alt move job is for moving charge out of the image area of a CCD into" "its frame store area, if such exists. It is type-dependent and transmits the" "line-shifting commands exactly the right number of times to move the image" "fully into the frame store." 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; "The px and ln states together constitute the image read job, which clocks" "consecutive CCD lines into a serial output register, clocks all the pixels" "out of the seriral register, and digitizes all of them with double-correlated" "double-sampling in the eight-bit ADC. All pixels are stored in RAM. The pixel" "states are shadowed by the the device receiver state machine so as to synchronize" "digitization with the arrival of analog data down a long cable." 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 value here" state px_4:goto px_1; "Whereas the clocking of pixels out of a serial output register is much the same" "for various CCDs, the clocking of lines varies according to how many clock phases" "the CCD requires. The TC255 has a single vertical clock phase. The KAF0400 has" "two. The ICX424 and other Sony CCDs have three." 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 {if TWPH then px_1 else ln_5} else ln_4; state ln_5:if !TDC then ln_6 else ln_5; state ln_6:if !TDC then {if PXBN then ln_7 else px_1} else ln_6; state ln_7:if !TDC then ln_8 else ln_7; state ln_8:if !TDC then ln_9 else ln_8; state ln_9:if !TDC then ln_10 else ln_9; state ln_10:if !TDC then ln_11 else ln_10; state ln_11:if !TDC then ln_12 else ln_11; state ln_12:if !TDC then px_1 else ln_12; "The read job is for data devices. It sends out a LO pulse on TXO and waits for" "a LO pulse to return. When it sees the falling edge on TXO it starts the serial" "bit receiver to get an eight-bit serial byte from the target." 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==move_3) #(dcs==move_4) #(dcs==move_5) #(dcs==move_6) #(dcs==move_done) #(dcs==alt_move_1) #(dcs==alt_move_2) #(dcs==loop_1) #(dcs==ln_1) #(dcs==ln_2) #(dcs==ln_3) #(dcs==ln_4) #(dcs==ln_5) #(dcs==ln_6) #(dcs==ln_7) #(dcs==ln_8) #(dcs==ln_9) #(dcs==ln_10) #(dcs==ln_11) #(dcs==ln_12) #(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;"CCD: pixel clock" state 14:goto 15;"CCD: pixel clock, data_device: D2 clock" state 15:goto 16;"CCD: pixel clock" state 16:goto 17;"CCD: pixel clock, data_device: D1 clock" state 17:goto 18;"CCD: store byte in RAM" state 18:goto 19;"data_device: D0 clock, CCD: 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:=1; "start the delay timer" DAI:=1; "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 CCD devices" when (dcs>=px_1) & (dcs<=ln_6) 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 horizontal 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==14) 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 devices" 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; "Backward Image Compatibility. We assert DAI once to increment the" "data address by one and make TC255 images identical to those captured" "by the A2004, A2031, and A2037 drivers. The A2004 was a pre-LWDAQ CCD" "driver, which used two AD775 eight-bit ADCs each with with a three-stage" " pipeline. The result was a combined pipeline of six stages. The A2031" "and A2037 LWDAQ Drivers used TLV5580 eight-bit ADC with a four-stage pipeline." "In order to make TC255P images captured with the A2031 identical to those" "captured with the A2004, the A2031 and A2037 incremented the address counter" "by two before they recorded an image. The A2071 uses the ADS828, with a" "five-stage pipeline, so we increment the data address by one." when (dcs==dcs_bridge) & CCDD then DAI:=SCKP1; "Device Command Bits" "-------------------" DC1= CR1 & DJCMD "CR1" # (dtr==TC255_device) & (dcs==ln_4) "DCEN, direct clock enable" # (dtr==TC237_device) & (dcs==ln_4) "DCEN, direct clock enable" # (dtr==KAF0400_device) & (dcs==ln_4) "DCEN, direct clock enable" # (dtr==KAF0261_device) & (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 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR1; "DC1 for multisources" DC2= CR2 & DJCMD "CR2" # (dtr==TC255_device) & (dcs==ln_1) "!SRG, serial register gate" # (dtr==TC255_device) & (dcs==ln_4) "!SRG, serial register gate" # (dtr==TC255_device) & (dcs==move_2) "!SRG, serial register gate" # (dtr==TC255_device) & (dcs==move_done) "!SRG, serial register gate" # (dtr==TC255_device) & (dcs==alt_move_2) "!SRG, serial register gate" # (dtr==TC237_device) & (dcs==ln_1) "!SRG, serial register gate" # (dtr==TC237_device) & (dcs==ln_4) "!SRG, serial register gate" # (dtr==TC237_device) & (dcs==move_2) "!SRG, serial register gate" # (dtr==TC237_device) & (dcs==move_done) "!SRG, serial register gate" # (dtr==TC237_device) & (dcs==alt_move_2) "!SRG, serial register gate" # (dtr==KAF0400_device) & (dcs==ln_1) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==ln_2) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==ln_3) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==ln_4) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==move_1) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==move_2) "H, horizontal clock" # (dtr==KAF0400_device) & (dcs==move_3) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==ln_1) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==ln_2) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==ln_3) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==ln_4) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==move_1) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==move_2) "H, horizontal clock" # (dtr==KAF0261_device) & (dcs==move_3) "H, horizontal clock" # (dtr==ICX424_device) & (dcs==ln_6) "H, horizontal clock" # (dtr==ICX424Q_device) & (dcs==ln_12) "H, horizontal clock" # (dtr==LED_device) & (dcs==flash_1) & (der==2) "ON2 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR2; "DC2 for multisources" DC3= CR3 & DJCMD "CR3" # (dtr==TC255_device) & (dcs==ln_1) "SAG, storage area gate" # (dtr==TC255_device) & (dcs==ln_2) "SAG, storage area gate" # (dtr==TC255_device) & (dcs==move_2) "SAG, storage area gate" # (dtr==TC255_device) & (dcs==move_done) "SAG, storage area gate" # (dtr==TC255_device) & (dcs==alt_move_2) "SAG, storage area gate" # (dtr==TC237_device) & (dcs==ln_1) "SAG, storage area gate" # (dtr==TC237_device) & (dcs==ln_2) "SAG, storage area gate" # (dtr==TC237_device) & (dcs==move_2) "SAG, storage area gate" # (dtr==TC237_device) & (dcs==move_done) "SAG, storage area gate" # (dtr==TC237_device) & (dcs==alt_move_2) "SAG, storage area gate" # (dtr==KAF0400_device) & (dcs==ln_1) "V1 vertical clock" # (dtr==KAF0400_device) & (dcs==ln_3) "V1 vertical clock" # (dtr==KAF0400_device) & (dcs==move_1) "V1 vertical clock" # (dtr==KAF0400_device) & (dcs==alt_move_1) "V1 vertical clock" # (dtr==KAF0261_device) & (dcs==ln_1) "V1 vertical clock" # (dtr==KAF0261_device) & (dcs==ln_3) "V1 vertical clock" # (dtr==KAF0261_device) & (dcs==move_1) "V1 vertical clock" # (dtr==KAF0261_device) & (dcs==alt_move_1) "V1 vertical clock" # (dtr==ICX424_device) & (dcs==move_1) "V1, vertical clock" # (dtr==ICX424_device) & (dcs==move_2) "V1, vertical clock" # (dtr==ICX424_device) & (dcs==move_3) "V1, vertical clock" # (dtr==ICX424_device) & (dcs==ln_1) "V1, vertical clock" # (dtr==ICX424_device) & (dcs==ln_2) "V1, vertical clock" # (dtr==ICX424_device) & (dcs==ln_3) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_1) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_2) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_3) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_1) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_2) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_3) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_7) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_8) "V1, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_9) "V1, vertical clock" # (dtr==LED_device) & (dcs==flash_1) & (der==3) "ON3 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR3; "DC3 for multisources" DC4= CR4 & DJCMD "CR4" # (dtr==TC255_device) & (dcs==move_1) "IAGD, image area gate" # (dtr==TC255_device) & (dcs==alt_move_1) "IAGD, image area gate" # (dtr==TC237_device) & (dcs==move_1) "IAGD, image area gate" # (dtr==TC237_device) & (dcs==alt_move_1) "IAGD, image area gate" # (dtr==KAF0400_device) & (dcs==ln_2) "V2 vertical clock" # (dtr==KAF0400_device) & (dcs==move_2) "V2 vertical clock" # (dtr==KAF0400_device) & (dcs==alt_move_2) "V2 vertical clock" # (dtr==KAF0261_device) & (dcs==ln_2) "V2 vertical clock" # (dtr==KAF0261_device) & (dcs==move_2) "V2 vertical clock" # (dtr==KAF0261_device) & (dcs==alt_move_2) "V2 vertical clock" # (dtr==ICX424_device) & (dcs==loop_1) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==flash_1) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==flash_3) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==move_1) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==move_5) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==move_6) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==ln_1) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==ln_5) "V2, vertical clock" # (dtr==ICX424_device) & (dcs==ln_6) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==loop_1) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==flash_1) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==flash_3) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_1) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_5) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_6) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_1) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_5) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_6) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_7) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_11) "V2, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_12) "V2, vertical clock" # (dtr==LED_device) & (dcs==flash_1) & (der==4) "ON4 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR4; "DC4 for multisources" DC5= CR5 & DJCMD "CR5" # (dtr==ICX424_device) & (dcs==flash_1) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==flash_3) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==move_3) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==move_4) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==move_5) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==ln_3) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==ln_4) "V3, vertical clock" # (dtr==ICX424_device) & (dcs==ln_5) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==flash_1) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==flash_3) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_3) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_4) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==move_5) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_3) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_4) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_5) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_9) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_10) "V3, vertical clock" # (dtr==ICX424Q_device) & (dcs==ln_11) "V3, vertical clock" # TC255 & (dcs==toggle_2) "ABGD, anti-blooming gate" # (dtr==LED_device) & (dcs==flash_1) & (der==5) "ON5 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR5; "DC5 for multisources" DC6= CR6 & DJCMD "CR6" # TC255 & (dcs==toggle_1) "ABEN, anti-blooming enable" # TC255 & (dcs==toggle_2) "ABEN, anti-blooming enable" # (dtr==LED_device) & (dcs==flash_1) & (der==6) "ON6 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR6; "DC6 for multisources" DC7= CR7 & DJCMD "CR7" # (dcs==loop_1); "LB" DC8= CR8 & DJCMD "CR8" # !DJSLP & !DJCMD; "WAKE on all devices" DC9= CR9 & DJCMD "CR9" # CCDD & (der==1) & !DJCMD "CCD1, selects first of first pair of CCDs." # CCDD & (der==3) & !DJCMD "CCD3, selects first of second pair CCDs." # (dtr==LED_device) & (dcs==flash_1) & (der==7) "ON7 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR9; "DC9 for multisources" DC10= CR10 & DJCMD "CR10" # CCDD & (der==1) & (dcs==flash_1) "ON1 for CCD devices" # CCDD & (der==7) & (dcs==flash_1) "ON7 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==8) "ON8 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR10; "DC10 for multisources" DC11= CR11 & DJCMD "CR11" # CCDD & (der==2) & (dcs==flash_1) "ON2 for CCD devices" # CCDD & (der==8) & (dcs==flash_1) "ON8 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==9) "ON9 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR11; "DC11 for multisources" DC12= CR12 & DJCMD "CR12" # CCDD & (der==3) & (dcs==flash_1) "ON3 for CCD devices" # CCDD & (der==9) & (dcs==flash_1) "ON9 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==10) "ON10 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR12; "DC12 for multisources" DC13= CR13 & DJCMD "CR13" # CCDD & (der==4) & (dcs==flash_1) "ON4 for CCD devices" # CCDD & (der==10) & (dcs==flash_1) "ON10 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==11) "ON11 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR13; "DC13 for multisources" DC14= CR14 & DJCMD "CR14" # CCDD & (der==5) & (dcs==flash_1) "ON5 for CCD devices" # CCDD & (der>=7) & (der<=10) & (dcs==flash_1) "VDS0 for CCD devices" # CCDD & (der>=3) & (der<=4) & DJRD "VDS0 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==12) "ON12 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR14; "DC14 for multisources" DC15= CR15 & DJCMD "CR15" # CCDD & (der==6) & (dcs==flash_1) "ON6 for CCD devices" # CCDD & (der>=7) & (der<=10) & (dcs==flash_1) "VDS1 for CCD devices" # CCDD & (der>=3) & (der<=4) & DJRD "VDS1 for CCD devices" # (dtr==LED_device) & (dcs==flash_1) & (der==13) "ON13 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR15; "DC15 for multisources" DC16= CR16 & DJCMD "CR16" # (dtr==ICX424Q_device) & (dcs==ln_12) "PXBN" # (dtr==LED_device) & (dcs==flash_1) & (der==14) "ON14 for LED devices" # (dtr==multisource_device) & (dcs==flash_1) & CR16; "DC16 for multisources" "Pixel End Count" "---------------" when (dtr==TC255_device) then { when (djr==read_job) then PXEC=(pixel_count==344); } when (dtr==TC237_device) then { when (djr==read_job) then PXEC=(pixel_count==690); } when (dtr==ICX424_device) then { when (djr==read_job) then PXEC=(pixel_count==700); } when (dtr==ICX424Q_device) then { when (djr==read_job) then PXEC=(pixel_count==350); } when (dtr==KAF0400_device) then { when (djr==read_job) then PXEC=(pixel_count==800); } when (dtr==KAF0261_device) then { when (djr==read_job) then PXEC=(pixel_count==520); } "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==1023); when (djr==alt_move_job) then LNEC=(line_count==244); } when (dtr==TC237_device) then { when (djr==read_job) then LNEC=(line_count==500); when (djr==move_job) then LNEC=(line_count==1023); when (djr==alt_move_job) then LNEC=(line_count==500); } when (dtr==ICX424_device) then { when (djr==read_job) then LNEC=(line_count==520); when (djr==move_job) then LNEC=(line_count==1023); when (djr==alt_move_job) then LNEC=(line_count==520); } when (dtr==ICX424Q_device) then { when (djr==read_job) then LNEC=(line_count==260); when (djr==move_job) then LNEC=(line_count==1023); when (djr==alt_move_job) then LNEC=(line_count==520); } when (dtr==KAF0400_device) then { when (djr==read_job) then LNEC=(line_count==520); when (djr==move_job) then LNEC=(line_count==1023); when (djr==alt_move_job) then LNEC=(line_count==520); } when (dtr==KAF0261_device) then { when (djr==read_job) then LNEC=(line_count==520); when (djr==move_job) then LNEC=(line_count==1023); when (djr==alt_move_job) then LNEC=(line_count==520); } "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=CK; 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. We want to do this once only in each SCK period," "so we use SCKP0 to select only one CK clock during a SCK" "period for the decrement. At other times, we can write to the" "counter through the control interface." when DCJD & !RCZ then { when SCKP0 then { rcb0:=rcb0-1; when RCZ0 then rcb1:=rcb1-1; else rcb1:=rcb1; when RCZ0 & RCZ1 then rcb2:=rcb2-1; else rcb2:=rcb2; } else { rcb0:=rcb0; rcb1:=rcb1; 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=CK; 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 use the Delay Timer Restore node to set the delay timer to its" "saved value. This node reduces the number of inputs required by the" "delay timer, and speeds up fitting." DTRS = DCJD & !RCZ & SCKP0; "We decrement the delay timer when DTEN is asserted and the counter" "has not yet reached zero. We decrement at 8 MHz, which is why we" "permit the decrement only on SCK0. When the device controller job." "is done, but the repeat counter is non-zero, we set the delay timer" "to its saved value." when DTEN & !DTZ then { when SCKP0 then { dtb0:=dtb0-1; when DTZ0 then dtb1:=dtb1-1; else dtb1:=dtb1; when DTZ1 & DTZ0 then dtb2:=dtb2-1; else dtb2:=dtb2; } else { dtb0:=dtb0; dtb1:=dtb1; dtb2:=dtb2; } } else { when DTRS 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=CK; 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" "---------------------" "The Serial Shift Register receives serial bytes from data" "devices. The data device transmits bits at a rate of 20 MBPS," "so that each bit takes 50 ns. We assert SSSR to instruct the" "Serial Shift Register to shift in the latest value of TXI." "We synchronise TXI with FCK for better resolution of incoming" "data." TXIF.clk=FCK; TXIF:=TXI; "We clock the serial shift register with CK. The SSSR strobe we" "clock elsewhere 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." 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,ESD].clk=SCK; "We want a delay of roughly 8 us, so we count SCK up to" "sixty-three." sdt.clk=SCK; sdt.aclr=!RSD; when (sdt>=0) & (sdt<63) then sdt:=sdt+1; when (sdt==63) then sdt:=63; "We end the settling delay when sdt=63." ESD:=(sdt==63); "Multiplexer Controller" "----------------------" dar.clk=CK; 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 1 else 2; "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 and Scratch Code" "--------------------------" "The LEDs turn on when the test outputs are HI." declarations test_firmware=0; equations when (test_firmware==0) then { TP1=CSW; TP2=LNK; TP3=PCCK; TP4=LCCK; TP5=!DTZ; TP6=!RCZ; TP7=TDA; TP8=TDC; EGRN=1; EYLW=LNK; } else { TP1=DAI; TP2=CA4; TP3=CDSD; TP4=!CDS; TP5=CDS; TP6=!CDS & CDSD & RSEL; TP7=RA0; TP8=RSEL; EGRN=1; EYLW=LNK; } end