// status.v
// Status registers, including error latching
// $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 status
(
input host_clk, // interconnect
input host_re, // interconnect
input host_we, // interconnect
input [15:0] host_data, // interconnect
output [15:0] errors, // register ERRORS
output [15:0] status, // register STATUS
input error_en, // select ERRORS
input clk40, // interconnect
input trace_enable, // interconnect
input dkcm_busy, // interconnect
input pll_muxout_, // interconnect
input trigger_skipped, // interconnect
input rf_on_sync, // interconnect
input sync_error, // interconnect
input sync_missing, // interconnect
output reg clk40_missing_pulse, // interconnect
input daov_, // interconnect
input dbov_, // interconnect
input dcov_, // interconnect
input ddov_, // interconnect
input [1:0] lrc_slot, // interconnect
input il_stat_, // interconnect
output LED2 // pin f
);
reg error_clear_cmd;
reg pll_unlocked, trigger_skipped_latch;
reg sync_error_latch, sync_missing_latch;
reg handshake_token, handshake_error, self_test_latch;
wire self_test_set = host_we & error_en & host_data[10];
always @(posedge host_clk) begin
// Reading the error register (ERRORS) causes its bits to clear.
// This clear happens after the data is latched into the read pipeline.
// XXX There is about one cycle (40 ns) of dead time, where errors
// can happen and will never be visible to the software.
error_clear_cmd <= host_re & error_en;
// Latch PLL errors
if (~pll_muxout_ | error_clear_cmd) pll_unlocked <= ~pll_muxout_;
// Latch sync errors
if (sync_error | error_clear_cmd) sync_error_latch <= sync_error;
if (sync_missing | error_clear_cmd) sync_missing_latch <= sync_missing;
// The software is expected to write to the error register (0x000c)
// (the data is ignored) at the beginning of its xfer_from_fpga
// routine, which is triggered by the interrupt. This puts the
// handshake logic into "armed" mode, where handshake_token=1.
// If an RF pulse comes along in this mode, the handshake_error
// bit is set. The xfer_from_fpga routine will read from error
// reg as the last thing it does, which both finds out if
// it acted fast enough to not get corrupted data, and sets
// handshake_token back to 0, so the handshake logic won't
// complain when the next RF pulse hits.
if ((host_we | host_re) & error_en)
handshake_token <= host_we;
if ((trace_enable & handshake_token) | error_clear_cmd)
handshake_error <= trace_enable & handshake_token;
// ext_trigger_skipped comes from rf_timer module as a 100 ns pulse,
// and is a simple register output (glitchless), so
// it is guaranteed to `stick' if we sample it at 25 MHz.
if (trigger_skipped | error_clear_cmd)
trigger_skipped_latch <= trigger_skipped;
if (self_test_set | error_clear_cmd)
self_test_latch <= self_test_set;
end
reg daov_latch, dbov_latch, dcov_latch, ddov_latch;
always @(posedge clk40) begin
if (trace_enable & daov_ | error_clear_cmd) daov_latch <= trace_enable & daov_;
if (trace_enable & dbov_ | error_clear_cmd) dbov_latch <= trace_enable & dbov_;
if (trace_enable & dcov_ | error_clear_cmd) dcov_latch <= trace_enable & dcov_;
if (trace_enable & ddov_ | error_clear_cmd) ddov_latch <= trace_enable & ddov_;
end
// these two processes provide a "clock detect" feature.
// If the 40 MHz goes away, or is even erratic, an error bit is raised.
// If the 25 MHz CPU clock goes away, there's nobody to tell :-(
// Strategy for crossing the clock domain: use a 2-bit Gray code
// counter clocked at 40 MHz, which can be sampled at 25 MHz.
// The counter will always have advanced one or two 25 ns cycles
// between 40 ns clocks.
reg [1:0] gray40, gray_sample, gray_previous;
reg clk40_missing, test2, test4;
`ifdef SIMULATE
initial gray40 = 2'b0;
`endif
always @(posedge clk40) gray40 <= {gray40[0], ~gray40[1]};
always @(posedge host_clk) begin
gray_sample <= gray40; // cross clock domains *here*
gray_previous <= gray_sample;
clk40_missing_pulse <= (gray_previous == gray_sample);
test2 <= ~test2;
test4 <= clk40_missing_pulse;
if(clk40_missing_pulse | error_clear_cmd)
clk40_missing <= clk40_missing_pulse;
end
flasher flasher(host_clk, clk40_missing_pulse, LED2);
assign errors = {5'b00000, self_test_latch, pll_unlocked, handshake_error,
sync_error_latch, sync_missing_latch,
trigger_skipped_latch, clk40_missing,
daov_latch, dbov_latch, dcov_latch, ddov_latch};
assign status = { 10'b0, lrc_slot, pll_muxout_, il_stat_, rf_on_sync, dkcm_busy };
endmodule