module P3007A title 'P3007A' "Verion 4, Last modified 12-DEC-05" "Adds time stamp with checksum from a virtual transmitter" "with ID zero." "Pins" declarations A pin 3; "LVDS input" B pin 10 istype 'com'; "LVDS output" C pin 43; "Comparator Output" LB pin 8 istype 'com'; "Loop Back" !RESET pin 22;"RESET" RCK pin 20; "32 kHz reference clock input" FCK pin 38; "Fast Clock on Global CLK1" FCKO pin 37 istype 'com,keep'; "Source of FCK" !RW pin 59 istype 'com'; "RAM Write" !RCE pin 66 istype 'reg'; "RAM Chip Enable" !ROE pin 6 istype 'com'; "RAM Output Enable" RA18..RA0 pin 85,80,79,78,16,17,19,31,30,53, 54,55,56,58,67,69,70,71,72 istype 'com'; "RAM Address" ram_addr = [RA18..RA0]; RD7..RD0 pin 9,11,14,15,60,61,64,65 istype 'com'; "RAM Data" ram_data = [RD7..RD0]; equations "Nodes" declarations FCS12..FCS0 node istype 'reg'; "Fast Clock Speed" FCSC node istype 'com,keep'; "Fast Clock Speed Carry" AS node istype 'reg'; "Address Strobe" CS node istype 'reg'; "Command Strobe" DS node istype 'reg'; "Data Strobe" DC1..DC16 node istype 'reg';"Device Command Bits" WAKE node istype 'com'; "Wake" DTX node istype 'com'; "Device Transmit" TBO node istype 'com'; "Transmitter Bit Out" DCK node istype 'reg'; "Data Clock" RVCK node istype 'reg'; "Receiver Clock" RVRN node istype 'reg'; "Receiver Run" RVD7..RVD0 node istype 'reg'; "Receiver Data" rvd=[RVD7..RVD0]; equations "Fast Clock Generation" "---------------------" "Here we generate the fast clock using a ring oscillator. Becauase" "the fast clock period is only four propagation delays, we must be" "careful using it to clock complicated state machines. If the compiler" "splits one of the state variable bits, the state machine could" "require more than four propagation delays between clock edges. So" "we try to advance our state machines with FCK and another pulsed" "clock, such as RVCK or DCK, whose frequency is slower." declarations R1 node istype 'com,keep'; "Ring Oscillator" equations [FCKO,R1]=[R1,!FCKO & !RESET]; "Fast Clock Calibration" "----------------------" declarations MS1..MS0 node istype 'reg'; "Master State" SC15..SC0 node istype 'reg'; "Startup Counter Low Byte Zero" SCZ0 node istype 'com,keep'; "Startup Counter Low Byte Zero" SCZ1 node istype 'com,keep'; "Startup Counter Top Byte Zero" ms=[MS1..MS0]; "Calibration State" fcs = [FCS12..FCS0]; "Fast Clock Speed" fcs_1 = [FCS12..FCS8]; "Fast Clock Speed, Top Byte" fcs_0 = [FCS7..FCS0]; "Fast Clock Speed, Low Byte" sc_1 = [SC15..SC8]; "Startup Counter Top Byte" sc_0 = [SC7..SC0]; "Startup Counter Low Byte" equations SCZ0 = (sc_0 == 0); SCZ1 = (sc_1 == 0); sc_0.clk = RCK; sc_0.ap = RESET; sc_0:=sc_0-1; sc_1.clk = RCK; sc_1.ap = RESET; when SCZ0 then sc_1:=sc_1-1 else sc_1:=sc_1; ms.clk=RCK; ms.aclr=RESET; state_diagram ms; state 0: if SCZ0 & SCZ1 then 1 else 0; "wait two seconds" state 1: goto 2; "clear speed counter" state 2: goto 3; "count ring periods in one RCK period" state 3: goto 3; "run" equations fcs_0.clk = FCK; fcs_0.aclr = RESET; when (ms==2) then fcs_0:=fcs_0+1; else fcs_0:=fcs_0; FCSC = (fcs_0 == ^hFF); fcs_1.clk = FCK; fcs_1.aclr = RESET; when (ms==2) & FCSC then fcs_1:=fcs_1+1; else fcs_1:=fcs_1; "Data Clock Generation" "---------------------" "Generates 40 MHz clock with code we hope can be transported "to other circuits. What's new in this generator is the division "of the fast clock speed by the desired data clock speed to produce" "a binary number with both integer and fractional parts. The data" "clock generator counts down the integer part to zero each" "time it creates a data clock period, and adds the fractional" "part to a cumulative sum. Whenever this sum generates a" "carry, the clock generator waits one DCE fast clock period" "before generating its data clock pulse. In this way, the" "average period of the data clock is accurate to a fraction" "of a fast clock period. You can increase the fractional" "accuracy by increasing the size of the fractional sum" "register. In this case we provide four bits of fractional" "sum, for data clock period accuracy +- 1/32 of a fast clock" "period. With fast clock period 6 ns (as it is in the first" "application of this code) and data clock period 25 ns (that's" "40 MHz), we have 25 ns +- 0.2 ns, which is plenty good enough" "for 8-bit serial transmission at 20 MBPS. We assume a thirteen-" "bit fast clock speed counter named FCS12..FCS0. If you use more" "bits, the addition equations for 'DCC' become enormous, and" "you should perform the addition with separate carry bits, as" "we do for our fractional sum bits, by way of illustration." declarations DCI3..DCI0 node istype 'reg';"Data Clock Integer" DCC7..DCC0 node istype 'com,keep';"Data Clock Count" DCF3..DCF0 node istype 'reg';"Data Clock Fraction" DCE node istype 'reg'; "Data Clock Extra Step" DCFS3..DCFS0 node istype 'com,keep'; "Data Clock Fraction Sum" DCFC3..DCFC0 node istype 'com,keep'; "Data Clock Fraction Carry" dcf=[DCF3..DCF0];"Data Clock Fraction" dci=[DCI3..DCI0];"Data Clock Integer" dcc=[DCC7..DCC0];"Data Clock Count" equations "Here we set dcc to the fast clock speed divided by twice the" "number of 40 MHz periods in one reference clock period." "We use the top four bits of dcc to represent the integer" "part of the result, and the lower four bits to represent" "the fractional part. We subtract 1.000 (binary) from the" "result to account for the fact that we'll be counting down" "to zero when we use this number to create the 25 ns period." dcc = [0,FCS12..FCS6] +[0,0,FCS12..FCS7] +[0,0,0,0,FCS12..FCS9] +[0,0,0,0,0,0,FCS12..FCS11] +[0,0,0,0,0,0,0,FCS12] -[0,0,0,1,0,0,0,0]; DCFS0 = DCF0 $ DCC0; DCFC0 = DCF0&DCC0; DCFS1 = DCF1 $ DCC1 $ DCFC0; DCFC1 = DCF1&DCC1 # DCF1&DCFC0 # DCC1&DCFC0; DCFS2 = DCF2 $ DCC2 $ DCFC1; DCFC2 = DCF2&DCC2 # DCF2&DCFC1 # DCC2&DCFC1; DCFS3 = DCF3 $ DCC3 $ DCFC2; DCFC3 = DCF3&DCC3 # DCF3&DCFC2 # DCC3&DCFC2; DCE.aclr = RESET; DCE.clk = FCK; DCK.aclr = RESET; DCK.clk = FCK; dci.aclr = RESET; dci.clk = FCK; dcf.aclr = RESET; dcf.clk = FCK; when (dci>0) then { dci := dci-1; dcf := dcf; DCE := DCE; DCK := 0; } when (dci==0) then { when DCE then { dci := 0; dcf := dcf; DCE := 0; DCK := 0; } else { dci := [DCC7..DCC4]; dcf := [DCFS3..DCFS0]; DCE := DCFC3; DCK := 1; } } "LWDAQ Command and Address Decoding" "----------------------------------" declarations SA node istype 'reg'; "Synchronized A" DSA node istype 'reg'; "Delayed SA" ARISE node istype 'reg'; "Rising Edge on A" DA node istype 'reg'; "Delayed A Rising Edge" DDA node istype 'reg'; "Delayed DA" AA node istype 'reg'; "Address Active" DAA node istype 'reg'; "Delayed AA" CA node istype 'reg'; "Command Active" DCA node istype 'reg'; "Delayed CA" ER,Q1..Q16 node istype 'reg';"Receiver Bits" PC12..PC7 node istype 'reg'; "Pulse Counter" pc=[PC12..PC7]; "Pulse Counter" equations [SA,DSA,DA,DDA,ARISE].clk = FCK; [SA,DSA,DA,DDA,ARISE].aclr = RESET; SA := A; DSA := SA; pc.clk = FCK; pc.aclr = RESET; when !ARISE then { ARISE := SA&!DSA; DA := 0; DDA := 0; pc := [FCS12..FCS7]; } when ARISE then { ARISE := !DDA; pc := pc-1; DA := (pc==[0,FCS12..FCS8]); DDA := (pc==0); } "We clock the receiver shift register and the entry" "register with DA, and we clear them on RESET." [ER,Q1..Q16].clk = DA; [ER,Q1..Q16].aclr = RESET; [ER,Q1..Q16] := [SA,ER,Q1..Q15]; "Address Active provides a pulse that begins with DDA" "on the start bit of an address transmission, and ends" "with the stop bit of an address transmission." AA.clk = DDA; AA.aclr = RESET; AA:=(!AA & !SA & !ER) # (AA & !SA); "Delayed AA allows us to create AS." DAA.clk=FCK; DAA:=AA; "Address Strobe provides a pulse at the end of an address" "transmission." AS.clk = FCK; AS := DAA & !AA; "Command Active provides a pulse that begins with DDA" "on the start bit of a command transmission, and ends" "with the stop bit of a command transmission." CA.clk = DDA; CA.aclr = RESET; CA:=(!CA & !SA & ER) # (CA & !SA); "Delayed CA allows us to create CS." DCA.clk=FCK; DCA:=CA; "Command Strobe provides a pulse at the end of a command" "transmission." CS.clk = FCK; CS := DCA & !CA; "Data Strobe identifies a solitary low pulse on A. We synchronize" "the strobe with the data clock so that we can use it to start" "the bit transmitter. We set DS with its asynchronous preset, and" "clear it on the next rising edge of DCK." DS.clk = DCK; DS.ap = (DDA & SA); DS := 0; "We clock the receiver bits into the command register" "on a falling edge of CS." [DC1..DC16].clk = CS; [DC1..DC16].aclr = RESET; [DC1..DC16] := [Q1..Q16]; "WAKE bit." WAKE = DC8; "Device Transmit Bit" DTX = DC5; "We enable the return LVDS driver when DC7 is set." LB = DC7; "We loop back A to the driver so long as DTX is not set." "Otherwise we send back the output of the data transmitter" "(Transmitter Bit Out). TBO should be HI by default," "and goes low after DS and DTX." when !DTX then B = A; else B = TBO; "Data Transmitter" "----------------" "The transmitter sends bytes back to the driver. It waits for" "DS combined with DTX (DC5). When it receives DS and DTX, it" "waits for Transmission Byte Load (TBL). The transmitter uses" "DCK to time its serial transmission to the driver. It transmits" "a leading zero followed by the eight bits of the transmission" "byte (tb)." declarations TS3..TS0 node istype 'reg'; "Transmit State" TB7..TB0 node istype 'reg'; "Transmission Bits" ts=[TS3..TS0];"Transmission State" tb=[TB7..TB0]; "Transmission Byte" TBL node istype 'reg'; "Transmitter Byte Load" equations TBL.clk = DCK; TBL.aclr = RESET; ts.clk = DCK; ts.aclr = RESET; state_diagram ts; state 0:if DS & DC5 then 1 else 0; state 1: if !DC5 then 0; if DC5 & TBL then 2; if DC5 & !TBL then 1; state 2:goto 3;"start bit 0" state 3:goto 4;"TB7" 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;"TB0" state 11:goto 0;"stop bit 1" equations; "TBO is the output of the transmitter. It passes through" "the LVDS return and so along the cables to the driver." TBO = ( (ts==0) # (ts==1) # (ts==3) & TB7 # (ts==4) & TB6 # (ts==5) & TB5 # (ts==6) & TB4 # (ts==7) & TB3 # (ts==8) & TB2 # (ts==9) & TB1 # (ts==10) & TB0 # (ts==11) ); "We load the transmitter byte from the RAM data bus. When" "some other part of the firmware asserts TBL." tb.clk = DCK; tb.aclr = RESET; when TBL then tb:=ram_data.pin; else tb:=tb; "Receive Clock Generation" "------------------------" "Generate a 4.194 MHz clock signal for use in the 4.194 MBPS" "serial receiver we apply to the incoming C signal." declarations RVCI5..RVCI0 node istype 'reg';"Receiver Clock Integer" RVCC7..RVCC0 node istype 'com,keep';"Receiver Clock Count" RVCF1..RVCF0 node istype 'reg';"Receiver Clock Fraction" RVCE node istype 'reg'; "Receiver Clock Extra Step" RVCFS1..RVCFS0 node istype 'com,keep'; "Receiver Clock Fraction Sum" RVCFC1..RVCFC0 node istype 'com,keep'; "Receiver Clock Fraction Carry" rvcf=[RVCF1..RVCF0];"Receiver Clock Fraction" rvci=[RVCI5..RVCI0];"Receiver Clock Integer" rvcc=[RVCC7..RVCC0];"Receiver Clock Count" equations "Here we set rvcc to the fast clock speed divided by twice the" "number of 4.194 MHz periods in one reference clock period." "This number is 128, which simplified the transmitter logic." "We use the top six bits of dcc to represent the integer" "part of the result, and the lower two bits to represent" "the fractional part. We subtract 1.00 (binary) from the" "result to account for the fact that we'll be counting down" "to zero when we use this number to create the 238.4-ns period." "The first time we count down rvcc, however, we want to generate" "a 119.2-ns half-period, so we set it to half the value required" "for the subsequent 238.4-ns period." when !RVRN then { rvcc = [0,FCS12..FCS6] -[0,0,0,0,0,1,0,0]; } else { rvcc = [FCS12..FCS5] -[0,0,0,0,0,1,0,0]; } RVCFS0 = RVCF0 $ RVCC0; RVCFC0 = RVCF0&RVCC0; RVCFS1 = RVCF1 $ RVCC1 $ RVCFC0; RVCFC1 = RVCF1&RVCC1 # RVCF1&RVCFC0 # RVCC1&RVCFC0; RVCE.aclr = RESET; RVCE.clk = FCK; RVCK.aclr = RESET; RVCK.clk = FCK; rvci.aclr = RESET; rvci.clk = FCK; rvcf.aclr = RESET; rvcf.clk = FCK; when RVRN then { when (rvci>0) then { rvci := rvci-1; rvcf := rvcf; RVCE := RVCE; RVCK := 0; } when (rvci==0) then { when RVCE then { rvci := 0; rvcf := rvcf; RVCE := 0; RVCK := 0; } else { rvci := [RVCC7..RVCC2]; rvcf := [RVCFS1..RVCFS0]; RVCE := RVCFC1; RVCK := 1; } } } else { rvci := [RVCC7..RVCC2]; rvcf := [RVCC1..RVCC0]; RVCE := 0; RVCK := 0; } "Receiver" "--------" declarations SC node istype 'reg'; "Synchronized C" DSC node istype 'reg'; "Delayed SC" RVS4..RVS0 node istype 'reg'; "Receiver State" rvs=[RVS4..RVS0]; equations SC.clk = FCK; SC := C; DSC.clk = FCK; DSC := SC; rvs.clk = FCK; rvs.aclr = RESET; state_diagram rvs; state 0:if !SC & DSC then 1 else 0; state 1:if RVCK then 2 else 1; state 2:if RVCK then 3 else 2; state 3:if RVCK then 4 else 3; state 4:if RVCK then 5 else 4; state 5:if RVCK then 6 else 5; state 6:if RVCK then 7 else 6; state 7:if RVCK then 8 else 7; state 8:if RVCK then 9 else 8; state 9:if RVCK then 10 else 9; state 10:if DCK then 11 else 10; state 11:if DCK then 12 else 11; state 12:if RVCK then {if DSC then 13 else 0} else 12; state 13:if !DSC then 1 else 13; equations RVRN.clk = FCK; RVRN.aclr = RESET; RVRN := (rvs>=1) & (rvs<=12); rvd.clk = FCK; rvd.aclr = RESET; when RVCK & (rvs>=2) & (rvs<=9) then rvd:=[RVD6..RVD0,DSC]; else rvd:=rvd; "Address Counters" "----------------" declarations SA18..SA0 node istype 'reg'; "Data Address" store_addr = [SA18..SA0]; sab0=[SA7..SA0]; "Store Address byte zero" sab1=[SA15..SA8]; "Store address byte one" sab2=[SA18..SA16]; "Store address byte two" SAC0,SAC1 node istype 'com'; "Data Address Carry" SAI node istype 'reg'; "Data Address Increment" TX18..TX0 node istype 'reg'; "Data Address" transmit_addr = [TX18..TX0]; txb0=[TX7..TX0]; "Transmit address byte zero" txb1=[TX15..TX8]; "Transmit address byte one" txb2=[TX18..TX16]; "Transmit address byte two" TXC0,TXC1 node istype 'com'; "Transmit Address Carry" TXI node istype 'reg'; "Data Address Increment" !AE0 node istype 'com,keep'; "Addresses Equal Byte 0" !AE1 node istype 'com,keep'; "Addresses Equal Byte 1" !AE2 node istype 'com,keep'; "Addresses Equal Byte 2" AE node istype 'com'; "Addresses Equal" equations "The store address is the RAM address at which we store" "data." store_addr.clk = DCK; store_addr.aclr = RESET; SAC0 = (sab0==^hFF); SAC1 = (sab1==^hFF); SAI.clk = DCK; when SAI then { sab0 := sab0+1; when SAC0 then sab1 := sab1+1; else sab1 := sab1; when SAC1 & SAC0 then sab2 := sab2+1; else sab2 := sab2; } else { store_addr := store_addr; } "The transmit address is the RAM address from which" "we read data to transmit." transmit_addr.clk = DCK; transmit_addr.aclr = RESET; TXC0 = (txb0==^hFF); TXC1 = (txb1==^hFF); TXI.clk = DCK; when TXI then { txb0 := txb0+1; when TXC0 then txb1 := txb1+1; else txb1 := txb1; when TXC1 & TXC0 then txb2 := txb2+1; else txb2 := txb2; } else { transmit_addr := transmit_addr; } "Address Equal is true when the store address equals the" "transmit address." AE0 = (sab0 == txb0); AE1 = (sab1 == txb1); AE2 = (sab2 == txb2); AE = AE0 & AE1 & AE2; "Time Stamp" "----------" declarations STAMP13..STAMP0 node istype 'reg'; "Time Stamp" timestamp=[STAMP13..STAMP0]; DV5..DV0 node istype 'reg'; "RCK Divider" divider=[DV5..DV0]; CHKSM1..CHKSM0 node istype 'reg'; "Checksum" checksum=[CHKSM1..CHKSM0]; TSRY node istype 'reg'; "Time Stamp Ready" SRCK node istype 'reg'; "Synchronized Reference Clock" DSRCK node istype 'reg'; "Delayed SRCK" equations SRCK.clk = DCK; SRCK := RCK; DSRCK.clk = DCK; DSRCK := SRCK; divider.clk = SRCK; divider.aclr = RESET; divider := divider+1; timestamp.clk = SRCK; timestamp.aclr = RESET; when (divider==0) then timestamp := timestamp+1; else timestamp:=timestamp; checksum.clk = SRCK; checksum.aclr = RESET; when (divider==0) then checksum := 3; when (divider==1) then checksum := checksum + [0,STAMP0]; when (divider==2) then checksum := checksum + [0,STAMP1]; when (divider==3) then checksum := checksum + [0,STAMP2]; when (divider==4) then checksum := checksum + [0,STAMP3]; when (divider==5) then checksum := checksum + [0,STAMP4]; when (divider==6) then checksum := checksum + [0,STAMP5]; when (divider==7) then checksum := checksum + [0,STAMP6]; when (divider==8) then checksum := checksum + [0,STAMP7]; when (divider==9) then checksum := checksum + [0,STAMP8]; when (divider==10) then checksum := checksum + [0,STAMP9]; when (divider==11) then checksum := checksum + [0,STAMP10]; when (divider==12) then checksum := checksum + [0,STAMP11]; when (divider==13) then checksum := checksum + [0,STAMP12]; when (divider==14) then checksum := checksum + [0,STAMP13]; when (divider>14) then checksum := checksum; "RAM Interface" "-------------" declarations RCS3..RCS0 node istype 'reg'; "Ram Controller State" rcs=[RCS3..RCS0]; RDOE node istype 'com'; "RAM Data Output Enable (from this chip)" equations rcs.clk = DCK; rcs.aclr = RESET; state_diagram rcs; state 0:if (rvs>=4) then { if (rvs==11) then 1 else 0; } else { if TSRY then 5 else { if (ts==1) & !AE then 3 else 0; } }; state 1:goto 2; state 2:goto 0; state 3:goto 4; state 4:goto 0; state 5:goto 6; state 6:goto 7; state 7:goto 8; state 8:goto 9; state 9:goto 10; state 10:goto 0; equations "TSRY goes true when the time stamp and its checksum are" "ready. It returns to false when the ram controller starts" "to store the time stamp in memory." TSRY.clk = DCK; TSRY.aclr = RESET; TSRY := ((divider==15) & SRCK & !DSRCK) # (TSRY & (rcs != 5)); ram_data.oe = RDOE; RCE.clk = DCK; when (rcs==0) then { ram_addr = store_addr; ram_data = 0; RW = 1; ROE = 0; RCE := 0; SAI := 0; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==1) then { ram_addr = store_addr; ram_data = rvd; RW = 1; ROE = 0; RCE := 1; SAI := 0; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==2) then { ram_addr = store_addr; ram_data = rvd; RW = 1; ROE = 0; RCE := 0; SAI := 1; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==3) then { ram_addr = transmit_addr; ram_data = 0; RW = 0; ROE = 1; RCE := 1; SAI := 0; TXI := 0; TBL := 1; RDOE = 0; } when (rcs==4) then { ram_addr = transmit_addr; ram_data = 0; RW = 0; ROE = 1; RCE := 0; SAI := 0; TXI := 1; TBL := 0; RDOE = 0; } when (rcs==5) then { ram_addr = store_addr; ram_data = ^b00100000; RW = 1; ROE = 0; RCE := 1; SAI := 1; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==6) then { ram_addr = store_addr; ram_data = ^b00100000; RW = 1; ROE = 0; RCE := 0; SAI := 0; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==7) then { ram_addr = store_addr; ram_data = [STAMP13..STAMP6]; RW = 1; ROE = 0; RCE := 1; SAI := 1; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==8) then { ram_addr = store_addr; ram_data = [STAMP13..STAMP6]; RW = 1; ROE = 0; RCE := 0; SAI := 0; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==9) then { ram_addr = store_addr; ram_data = [STAMP5..STAMP0,CHKSM1..CHKSM0]; RW = 1; ROE = 0; RCE := 1; SAI := 1; TXI := 0; TBL := 0; RDOE = 1; } when (rcs==10) then { ram_addr = store_addr; ram_data = [STAMP5..STAMP0,CHKSM1..CHKSM0]; RW = 1; ROE = 0; RCE := 0; SAI := 0; TXI := 0; TBL := 0; RDOE = 1; } end