Attention

This documentation is a work in progress. Expect to see errors and unfinished things.

timestamp Source File

  1// High-speed cycle counter
  2
  3// This module attaches to the slow readout bus used in many
  4// LBNL DAQ builds. It provides a 59-bit cycle counter (since chip boot),
  5// and an optional timestamp capture register.
  6
  7// The 8-bit-wide shift-register-style output is ready to be merged
  8// in a "slow" DSP data stream, LSB-first.  Sorry about the byte-order,
  9// but it's intrinsic to the mechanism used.
 10
 11// Synthesizes to 54 LUTs and 31 Flip flops at 150 MHz in XC3S1000-5 with XST 12.1 (aux_reg=0)
 12// Synthesizes to 101 LUTs and 65 Flip flops at 150 MHz in XC3S1000-5 with XST 12.1 (aux_reg=1)
 13// 59-bit counter will wrap every 182 years if clocked at 100 MHz.
 14`timescale 1ns / 1ns
 15module timestamp(
 16     input clk,  // timespec 6.6 ns
 17     // aux_ ports are only useful if parameter aux_reg is 1
 18     input aux_trig,
 19     output aux_skip,
 20     input slow_op,
 21     input slow_snap,
 22     input [7:0] shift_in,
 23     output [7:0] shift_out
 24);
 25
 26// Re-use some ideas from SNS
 27
 28// Data bus width, used to make the testing process shorter and more believable.
 29parameter dw=8;
 30parameter aux_reg=0;
 31
 32reg [2:0] fast=0;
 33reg [dw-1:0] count_loop=0;
 34reg c_out=0;
 35wire [dw-1:0] count_out;
 36wire c_in = (fast==0) ? 1 : c_out;
 37always @(posedge clk) begin
 38     fast <= fast+1;
 39     {c_out,count_loop} <= count_out + c_in;
 40end
 41
 42reg_delay #(.dw(dw), .len(7))
 43     count(.clk(clk), .reset(1'b0), .gate(1'b1), .din(count_loop), .dout(count_out));
 44
 45// Can snapshot fast anytime.  Have to wait for the next cycle of
 46// fast sequencing from 0 through 7 before the rest of the counter
 47// state can be read out
 48reg pending=0, sending=0, grab_fast=0;
 49always @(posedge clk) begin
 50     grab_fast <= slow_op & slow_snap;
 51     if (fast==7) pending <= 0;
 52     if (slow_op & slow_snap) pending <= 1;
 53     if (fast==7) sending <= pending;
 54     if (fast==6) sending <= 0;
 55end
 56wire [dw-1:0] fast_pad={fast,{dw-3{1'b0}}};
 57wire [dw-1:0] shift_in2;  // output of aux subsystem
 58wire [dw-1:0] snap_in = grab_fast ? fast_pad : (slow_op&~slow_snap) ? shift_in2 : count_out;
 59wire snap_shift=grab_fast|(slow_op&~slow_snap)|sending;
 60wire [dw-1:0] snap_out;
 61reg_delay #(.dw(dw), .len(8))
 62     s1(.clk(clk), .reset(1'b0), .gate(snap_shift), .din(snap_in), .dout(snap_out));
 63
 64// Second snapshot register
 65// If aux_reg is a constant 0 at compile-time, this will get optimized away
 66reg abusy=0, axmit=0, astored=0;
 67reg apending=0, asending=0, agrab_fast=0;
 68always @(posedge clk) begin
 69     agrab_fast <= aux_trig & ~abusy;
 70     if (aux_trig) abusy <= 1;
 71     if (fast==7) apending <= 0;
 72     if (aux_trig & ~abusy) apending <= 1;
 73     if (fast==7) asending <= apending;
 74     if (fast==6) asending <= 0;
 75     if ((fast==6)&asending) astored<=1;
 76     if (astored&slow_op&slow_snap) begin astored<=0; axmit<=1; end
 77     if (axmit&slow_op&slow_snap) begin axmit<=0; abusy<=0; end
 78end
 79wire [dw-1:0] ashiftd;  // hold shift register data in parallel with aux slot
 80reg_delay #(.dw(dw), .len(8))
 81     aslow(.clk(clk), .reset(1'b0), .gate(slow_op), .din(shift_in[dw-1:0]), .dout(ashiftd));
 82wire [dw-1:0] asnap_in = agrab_fast ? fast_pad : count_out;
 83wire asnap_shift=agrab_fast|asending|(axmit&slow_op&~slow_snap);
 84wire [dw-1:0] asnap_out;  // shift register fills with time info
 85reg_delay #(.dw(dw), .len(8))
 86     a1(.clk(clk), .reset(1'b0), .gate(asnap_shift), .din(asnap_in), .dout(asnap_out));
 87// Keep track of the first 8 shift commands
 88reg [2:0] ascnt=0;
 89reg apost8=0;
 90always @(posedge clk) begin
 91     if (slow_op&slow_snap) begin ascnt<=0; apost8<=0; end
 92     if (slow_op&~slow_snap&~apost8) ascnt<=ascnt+1;
 93     if (slow_op&~slow_snap&(ascnt==7)) apost8<=1;
 94end
 95// Note dependence on aux_reg
 96// Always skips in the non-aux_reg case
 97assign aux_skip = aux_reg ? (aux_trig & abusy) : aux_trig;
 98assign shift_in2 = aux_reg ? (apost8 ? ashiftd : axmit ? asnap_out : 0) : shift_in;
 99
100// Output of this module is simply the output of the above shift register
101// Making an explicit copy like this avoids a warning when dw != 8
102assign shift_out=snap_out;
103
104// More-or-less equivalent to adding
105//   { time1, time2, time3, time4, atime1, atime2, atime3, atime4 }
106// to slow_sr_data, but uses far fewer resources
107
108endmodule