// stopwatch.v
// 32-bit precision event timer, used to measure pulse period
// $Id$
// Larry Doolittle, LBNL
// llc-suite Copyright (c) 2004, The Regents of the University of
// California, through Lawrence Berkeley National Laboratory (subject
// to receipt of any required approvals from the U.S. Dept. of Energy).
// All rights reserved.
// Your use of this software is pursuant to a "BSD-style" open
// source license agreement, the text of which is in license.txt
// (md5sum a1e0e81c78f6eba050b0e96996f49fd5) that should accompany
// this file. If the license agreement is not there, or if you
// have questions about the license, please contact Berkeley Lab's
// Technology Transfer Department at TTD@lbl.gov referring to
// "llc-suite (LBNL Ref CR-1988)"
`timescale 1ns / 1ns
module stopwatch
(
input host_clk, // interconnect
input host_we, // interconnect
input control_sel, // select STOPWATCH
input [15:0] host_data, // interconnect
input [13:0] host_addr, // interconnect
output [15:0] readout, // register STOPWATCH
input clk40, // interconnect
input rf_on_sync // interconnect
);
wire trigger = rf_on_sync;
reg armed, busy; // in the 40 MHz domain
// host_clk domain:
wire host_arm = host_we & control_sel & host_data[1];
reg host_trigger, busy_sync;
reg host_gray;
`ifdef SIMULATE
initial begin host_gray=0; host_trigger=0; end
`endif
always @(posedge host_clk) begin
if (host_arm) host_gray <= ~host_gray;
if (host_we & control_sel) host_trigger <= host_data[2];
busy_sync <= busy;
end
// 40 MHz domain:
reg trigger_sync, trigger_prev, pre_save, saving;
reg [2:0] count_low, latch_low;
reg gray, gray_prev;
reg carry; reg [3:0] count_hi;
wire tick = (count_low==0);
wire fire = armed & (host_trigger | trigger_sync & ~trigger_prev);
wire [3:0] counter_out, host_nibble;
`ifdef SIMULATE
initial begin carry=0; count_hi=0; count_low=0; armed=0;
saving=0; pre_save=0; end
`endif
always @(posedge clk40) begin
trigger_sync <= trigger; // potentially async input
trigger_prev <= trigger_sync;
gray <= host_gray; // cross clock domains
gray_prev <= gray;
if ((gray_prev != gray) | fire) armed <= ~fire;
if (fire) latch_low <= count_low;
if (fire | tick) pre_save <= fire;
if (tick) saving <= pre_save;
count_low <= count_low + 1;
busy <= armed | pre_save | saving;
{carry, count_hi} <= {1'b0,counter_out} + (tick?1'b1:carry);
end
// configure shift register as 7 long
srl16x4e counter(.Q(counter_out), .A0(1'b0), .A1(1'b1), .A2(1'b1), .A3(1'b0),
.CE(1'b1), .CLK(clk40), .D(count_hi));
srl16x4e memory(.Q(host_nibble), .A0(host_addr[0]), .A1(host_addr[1]),
.A2(host_addr[2]), .A3(host_addr[3]),
.CE(saving), .CLK(clk40), .D(count_hi));
assign readout={7'b0, busy_sync, 1'b0, latch_low, host_nibble};
endmodule