summaryrefslogtreecommitdiff
path: root/tests/openmsp430/rtl/omsp_watchdog.v
diff options
context:
space:
mode:
Diffstat (limited to 'tests/openmsp430/rtl/omsp_watchdog.v')
-rw-r--r--tests/openmsp430/rtl/omsp_watchdog.v556
1 files changed, 556 insertions, 0 deletions
diff --git a/tests/openmsp430/rtl/omsp_watchdog.v b/tests/openmsp430/rtl/omsp_watchdog.v
new file mode 100644
index 00000000..f7cedda0
--- /dev/null
+++ b/tests/openmsp430/rtl/omsp_watchdog.v
@@ -0,0 +1,556 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2009 , Olivier Girard
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the authors nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE
+//
+//----------------------------------------------------------------------------
+//
+// *File Name: omsp_watchdog.v
+//
+// *Module Description:
+// Watchdog Timer
+//
+// *Author(s):
+// - Olivier Girard, olgirard@gmail.com
+//
+//----------------------------------------------------------------------------
+// $Rev: 134 $
+// $LastChangedBy: olivier.girard $
+// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
+//----------------------------------------------------------------------------
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_defines.v"
+`endif
+
+module omsp_watchdog (
+
+// OUTPUTs
+ per_dout, // Peripheral data output
+ wdt_irq, // Watchdog-timer interrupt
+ wdt_reset, // Watchdog-timer reset
+ wdt_wkup, // Watchdog Wakeup
+ wdtifg, // Watchdog-timer interrupt flag
+ wdtnmies, // Watchdog-timer NMI edge selection
+
+// INPUTs
+ aclk, // ACLK
+ aclk_en, // ACLK enable
+ dbg_freeze, // Freeze Watchdog counter
+ mclk, // Main system clock
+ per_addr, // Peripheral address
+ per_din, // Peripheral data input
+ per_en, // Peripheral enable (high active)
+ per_we, // Peripheral write enable (high active)
+ por, // Power-on reset
+ puc_rst, // Main system reset
+ scan_enable, // Scan enable (active during scan shifting)
+ scan_mode, // Scan mode
+ smclk, // SMCLK
+ smclk_en, // SMCLK enable
+ wdtie, // Watchdog timer interrupt enable
+ wdtifg_irq_clr, // Watchdog-timer interrupt flag irq accepted clear
+ wdtifg_sw_clr, // Watchdog-timer interrupt flag software clear
+ wdtifg_sw_set // Watchdog-timer interrupt flag software set
+);
+
+// OUTPUTs
+//=========
+output [15:0] per_dout; // Peripheral data output
+output wdt_irq; // Watchdog-timer interrupt
+output wdt_reset; // Watchdog-timer reset
+output wdt_wkup; // Watchdog Wakeup
+output wdtifg; // Watchdog-timer interrupt flag
+output wdtnmies; // Watchdog-timer NMI edge selection
+
+// INPUTs
+//=========
+input aclk; // ACLK
+input aclk_en; // ACLK enable
+input dbg_freeze; // Freeze Watchdog counter
+input mclk; // Main system clock
+input [13:0] per_addr; // Peripheral address
+input [15:0] per_din; // Peripheral data input
+input per_en; // Peripheral enable (high active)
+input [1:0] per_we; // Peripheral write enable (high active)
+input por; // Power-on reset
+input puc_rst; // Main system reset
+input scan_enable; // Scan enable (active during scan shifting)
+input scan_mode; // Scan mode
+input smclk; // SMCLK
+input smclk_en; // SMCLK enable
+input wdtie; // Watchdog timer interrupt enable
+input wdtifg_irq_clr; // Clear Watchdog-timer interrupt flag
+input wdtifg_sw_clr; // Watchdog-timer interrupt flag software clear
+input wdtifg_sw_set; // Watchdog-timer interrupt flag software set
+
+
+//=============================================================================
+// 1) PARAMETER DECLARATION
+//=============================================================================
+
+// Register base address (must be aligned to decoder bit width)
+parameter [14:0] BASE_ADDR = 15'h0120;
+
+// Decoder bit width (defines how many bits are considered for address decoding)
+parameter DEC_WD = 2;
+
+// Register addresses offset
+parameter [DEC_WD-1:0] WDTCTL = 'h0;
+
+// Register one-hot decoder utilities
+parameter DEC_SZ = (1 << DEC_WD);
+parameter [DEC_SZ-1:0] BASE_REG = {{DEC_SZ-1{1'b0}}, 1'b1};
+
+// Register one-hot decoder
+parameter [DEC_SZ-1:0] WDTCTL_D = (BASE_REG << WDTCTL);
+
+
+//============================================================================
+// 2) REGISTER DECODER
+//============================================================================
+
+// Local register selection
+wire reg_sel = per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
+
+// Register local address
+wire [DEC_WD-1:0] reg_addr = {per_addr[DEC_WD-2:0], 1'b0};
+
+// Register address decode
+wire [DEC_SZ-1:0] reg_dec = (WDTCTL_D & {DEC_SZ{(reg_addr==WDTCTL)}});
+
+// Read/Write probes
+wire reg_write = |per_we & reg_sel;
+wire reg_read = ~|per_we & reg_sel;
+
+// Read/Write vectors
+wire [DEC_SZ-1:0] reg_wr = reg_dec & {DEC_SZ{reg_write}};
+wire [DEC_SZ-1:0] reg_rd = reg_dec & {DEC_SZ{reg_read}};
+
+
+//============================================================================
+// 3) REGISTERS
+//============================================================================
+
+// WDTCTL Register
+//-----------------
+// WDTNMI is not implemented and therefore masked
+
+reg [7:0] wdtctl;
+
+wire wdtctl_wr = reg_wr[WDTCTL];
+
+`ifdef CLOCK_GATING
+wire mclk_wdtctl;
+omsp_clock_gate clock_gate_wdtctl (.gclk(mclk_wdtctl),
+ .clk (mclk), .enable(wdtctl_wr), .scan_enable(scan_enable));
+`else
+wire mclk_wdtctl = mclk;
+`endif
+
+`ifdef NMI
+parameter [7:0] WDTNMIES_MASK = 8'h40;
+`else
+parameter [7:0] WDTNMIES_MASK = 8'h00;
+`endif
+
+`ifdef ASIC
+ `ifdef WATCHDOG_MUX
+parameter [7:0] WDTSSEL_MASK = 8'h04;
+ `else
+parameter [7:0] WDTSSEL_MASK = 8'h00;
+ `endif
+`else
+parameter [7:0] WDTSSEL_MASK = 8'h04;
+`endif
+
+parameter [7:0] WDTCTL_MASK = (8'b1001_0011 | WDTSSEL_MASK | WDTNMIES_MASK);
+
+always @ (posedge mclk_wdtctl or posedge puc_rst)
+ if (puc_rst) wdtctl <= 8'h00;
+`ifdef CLOCK_GATING
+ else wdtctl <= per_din[7:0] & WDTCTL_MASK;
+`else
+ else if (wdtctl_wr) wdtctl <= per_din[7:0] & WDTCTL_MASK;
+`endif
+
+wire wdtpw_error = wdtctl_wr & (per_din[15:8]!=8'h5a);
+wire wdttmsel = wdtctl[4];
+wire wdtnmies = wdtctl[6];
+
+
+//============================================================================
+// 4) DATA OUTPUT GENERATION
+//============================================================================
+
+`ifdef NMI
+parameter [7:0] WDTNMI_RD_MASK = 8'h20;
+`else
+parameter [7:0] WDTNMI_RD_MASK = 8'h00;
+`endif
+`ifdef WATCHDOG_MUX
+parameter [7:0] WDTSSEL_RD_MASK = 8'h00;
+`else
+ `ifdef WATCHDOG_NOMUX_ACLK
+parameter [7:0] WDTSSEL_RD_MASK = 8'h04;
+ `else
+parameter [7:0] WDTSSEL_RD_MASK = 8'h00;
+ `endif
+`endif
+parameter [7:0] WDTCTL_RD_MASK = WDTNMI_RD_MASK | WDTSSEL_RD_MASK;
+
+// Data output mux
+wire [15:0] wdtctl_rd = {8'h69, wdtctl | WDTCTL_RD_MASK} & {16{reg_rd[WDTCTL]}};
+wire [15:0] per_dout = wdtctl_rd;
+
+
+//=============================================================================
+// 5) WATCHDOG TIMER (ASIC IMPLEMENTATION)
+//=============================================================================
+`ifdef ASIC
+
+// Watchdog clock source selection
+//---------------------------------
+wire wdt_clk;
+
+`ifdef WATCHDOG_MUX
+omsp_clock_mux clock_mux_watchdog (
+ .clk_out (wdt_clk),
+ .clk_in0 (smclk),
+ .clk_in1 (aclk),
+ .reset (puc_rst),
+ .scan_mode (scan_mode),
+ .select (wdtctl[2])
+);
+`else
+ `ifdef WATCHDOG_NOMUX_ACLK
+ assign wdt_clk = aclk;
+ `else
+ assign wdt_clk = smclk;
+ `endif
+`endif
+
+// Reset synchronizer for the watchdog local clock domain
+//--------------------------------------------------------
+
+wire wdt_rst_noscan;
+wire wdt_rst;
+
+// Reset Synchronizer
+omsp_sync_reset sync_reset_por (
+ .rst_s (wdt_rst_noscan),
+ .clk (wdt_clk),
+ .rst_a (puc_rst)
+);
+
+// Scan Reset Mux
+omsp_scan_mux scan_mux_wdt_rst (
+ .scan_mode (scan_mode),
+ .data_in_scan (puc_rst),
+ .data_in_func (wdt_rst_noscan),
+ .data_out (wdt_rst)
+);
+
+
+// Watchog counter clear (synchronization)
+//-----------------------------------------
+
+// Toggle bit whenever the watchog needs to be cleared
+reg wdtcnt_clr_toggle;
+wire wdtcnt_clr_detect = (wdtctl_wr & per_din[3]);
+always @ (posedge mclk or posedge puc_rst)
+ if (puc_rst) wdtcnt_clr_toggle <= 1'b0;
+ else if (wdtcnt_clr_detect) wdtcnt_clr_toggle <= ~wdtcnt_clr_toggle;
+
+// Synchronization
+wire wdtcnt_clr_sync;
+omsp_sync_cell sync_cell_wdtcnt_clr (
+ .data_out (wdtcnt_clr_sync),
+ .data_in (wdtcnt_clr_toggle),
+ .clk (wdt_clk),
+ .rst (wdt_rst)
+);
+
+// Edge detection
+reg wdtcnt_clr_sync_dly;
+always @ (posedge wdt_clk or posedge wdt_rst)
+ if (wdt_rst) wdtcnt_clr_sync_dly <= 1'b0;
+ else wdtcnt_clr_sync_dly <= wdtcnt_clr_sync;
+
+wire wdtqn_edge;
+wire wdtcnt_clr = (wdtcnt_clr_sync ^ wdtcnt_clr_sync_dly) | wdtqn_edge;
+
+
+// Watchog counter increment (synchronization)
+//----------------------------------------------
+wire wdtcnt_incr;
+
+omsp_sync_cell sync_cell_wdtcnt_incr (
+ .data_out (wdtcnt_incr),
+ .data_in (~wdtctl[7] & ~dbg_freeze),
+ .clk (wdt_clk),
+ .rst (wdt_rst)
+);
+
+
+// Watchdog 16 bit counter
+//--------------------------
+reg [15:0] wdtcnt;
+
+wire [15:0] wdtcnt_nxt = wdtcnt+16'h0001;
+
+`ifdef CLOCK_GATING
+wire wdtcnt_en = wdtcnt_clr | wdtcnt_incr;
+wire wdt_clk_cnt;
+omsp_clock_gate clock_gate_wdtcnt (.gclk(wdt_clk_cnt),
+ .clk (wdt_clk), .enable(wdtcnt_en), .scan_enable(scan_enable));
+`else
+wire wdt_clk_cnt = wdt_clk;
+`endif
+
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+ if (wdt_rst) wdtcnt <= 16'h0000;
+ else if (wdtcnt_clr) wdtcnt <= 16'h0000;
+`ifdef CLOCK_GATING
+ else wdtcnt <= wdtcnt_nxt;
+`else
+ else if (wdtcnt_incr) wdtcnt <= wdtcnt_nxt;
+`endif
+
+
+// Local synchronizer for the wdtctl.WDTISx
+// configuration (note that we can live with
+// a full bus synchronizer as it won't hurt
+// if we get a wrong WDTISx value for a
+// single clock cycle)
+//--------------------------------------------
+reg [1:0] wdtisx_s;
+reg [1:0] wdtisx_ss;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+ if (wdt_rst)
+ begin
+ wdtisx_s <= 2'h0;
+ wdtisx_ss <= 2'h0;
+ end
+ else
+ begin
+ wdtisx_s <= wdtctl[1:0];
+ wdtisx_ss <= wdtisx_s;
+ end
+
+
+// Interval selection mux
+//--------------------------
+reg wdtqn;
+
+always @(wdtisx_ss or wdtcnt_nxt)
+ case(wdtisx_ss)
+ 2'b00 : wdtqn = wdtcnt_nxt[15];
+ 2'b01 : wdtqn = wdtcnt_nxt[13];
+ 2'b10 : wdtqn = wdtcnt_nxt[9];
+ default: wdtqn = wdtcnt_nxt[6];
+ endcase
+
+
+// Watchdog event detection
+//-----------------------------
+
+// Interval end detection
+assign wdtqn_edge = (wdtqn & wdtcnt_incr);
+
+// Toggle bit for the transmition to the MCLK domain
+reg wdt_evt_toggle;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+ if (wdt_rst) wdt_evt_toggle <= 1'b0;
+ else if (wdtqn_edge) wdt_evt_toggle <= ~wdt_evt_toggle;
+
+// Synchronize in the MCLK domain
+wire wdt_evt_toggle_sync;
+omsp_sync_cell sync_cell_wdt_evt (
+ .data_out (wdt_evt_toggle_sync),
+ .data_in (wdt_evt_toggle),
+ .clk (mclk),
+ .rst (puc_rst)
+);
+
+// Delay for edge detection of the toggle bit
+reg wdt_evt_toggle_sync_dly;
+always @ (posedge mclk or posedge puc_rst)
+ if (puc_rst) wdt_evt_toggle_sync_dly <= 1'b0;
+ else wdt_evt_toggle_sync_dly <= wdt_evt_toggle_sync;
+
+wire wdtifg_evt = (wdt_evt_toggle_sync_dly ^ wdt_evt_toggle_sync) | wdtpw_error;
+
+
+// Watchdog wakeup generation
+//-------------------------------------------------------------
+
+// Clear wakeup when the watchdog flag is cleared (glitch free)
+reg wdtifg_clr_reg;
+wire wdtifg_clr;
+always @ (posedge mclk or posedge puc_rst)
+ if (puc_rst) wdtifg_clr_reg <= 1'b1;
+ else wdtifg_clr_reg <= wdtifg_clr;
+
+// Set wakeup when the watchdog event is detected (glitch free)
+reg wdtqn_edge_reg;
+always @ (posedge wdt_clk_cnt or posedge wdt_rst)
+ if (wdt_rst) wdtqn_edge_reg <= 1'b0;
+ else wdtqn_edge_reg <= wdtqn_edge;
+
+// Watchdog wakeup cell
+wire wdt_wkup_pre;
+omsp_wakeup_cell wakeup_cell_wdog (
+ .wkup_out (wdt_wkup_pre), // Wakup signal (asynchronous)
+ .scan_clk (mclk), // Scan clock
+ .scan_mode (scan_mode), // Scan mode
+ .scan_rst (puc_rst), // Scan reset
+ .wkup_clear (wdtifg_clr_reg), // Glitch free wakeup event clear
+ .wkup_event (wdtqn_edge_reg) // Glitch free asynchronous wakeup event
+);
+
+// When not in HOLD, the watchdog can generate a wakeup when:
+// - in interval mode (if interrupts are enabled)
+// - in reset mode (always)
+reg wdt_wkup_en;
+always @ (posedge mclk or posedge puc_rst)
+ if (puc_rst) wdt_wkup_en <= 1'b0;
+ else wdt_wkup_en <= ~wdtctl[7] & (~wdttmsel | (wdttmsel & wdtie));
+
+// Make wakeup when not enabled
+wire wdt_wkup;
+omsp_and_gate and_wdt_wkup (.y(wdt_wkup), .a(wdt_wkup_pre), .b(wdt_wkup_en));
+
+
+// Watchdog interrupt flag
+//------------------------------
+reg wdtifg;
+
+wire wdtifg_set = wdtifg_evt | wdtifg_sw_set;
+assign wdtifg_clr = (wdtifg_irq_clr & wdttmsel) | wdtifg_sw_clr;
+
+always @ (posedge mclk or posedge por)
+ if (por) wdtifg <= 1'b0;
+ else if (wdtifg_set) wdtifg <= 1'b1;
+ else if (wdtifg_clr) wdtifg <= 1'b0;
+
+
+// Watchdog interrupt generation
+//---------------------------------
+wire wdt_irq = wdttmsel & wdtifg & wdtie;
+
+
+// Watchdog reset generation
+//-----------------------------
+reg wdt_reset;
+
+always @ (posedge mclk or posedge por)
+ if (por) wdt_reset <= 1'b0;
+ else wdt_reset <= wdtpw_error | (wdtifg_set & ~wdttmsel);
+
+
+
+//=============================================================================
+// 6) WATCHDOG TIMER (FPGA IMPLEMENTATION)
+//=============================================================================
+`else
+
+// Watchdog clock source selection
+//---------------------------------
+wire clk_src_en = wdtctl[2] ? aclk_en : smclk_en;
+
+
+// Watchdog 16 bit counter
+//--------------------------
+reg [15:0] wdtcnt;
+
+wire wdtifg_evt;
+wire wdtcnt_clr = (wdtctl_wr & per_din[3]) | wdtifg_evt;
+wire wdtcnt_incr = ~wdtctl[7] & clk_src_en & ~dbg_freeze;
+
+wire [15:0] wdtcnt_nxt = wdtcnt+16'h0001;
+
+always @ (posedge mclk or posedge puc_rst)
+ if (puc_rst) wdtcnt <= 16'h0000;
+ else if (wdtcnt_clr) wdtcnt <= 16'h0000;
+ else if (wdtcnt_incr) wdtcnt <= wdtcnt_nxt;
+
+
+// Interval selection mux
+//--------------------------
+reg wdtqn;
+
+always @(wdtctl or wdtcnt_nxt)
+ case(wdtctl[1:0])
+ 2'b00 : wdtqn = wdtcnt_nxt[15];
+ 2'b01 : wdtqn = wdtcnt_nxt[13];
+ 2'b10 : wdtqn = wdtcnt_nxt[9];
+ default: wdtqn = wdtcnt_nxt[6];
+ endcase
+
+
+// Watchdog event detection
+//-----------------------------
+
+assign wdtifg_evt = (wdtqn & wdtcnt_incr) | wdtpw_error;
+
+
+// Watchdog interrupt flag
+//------------------------------
+reg wdtifg;
+
+wire wdtifg_set = wdtifg_evt | wdtifg_sw_set;
+wire wdtifg_clr = (wdtifg_irq_clr & wdttmsel) | wdtifg_sw_clr;
+
+always @ (posedge mclk or posedge por)
+ if (por) wdtifg <= 1'b0;
+ else if (wdtifg_set) wdtifg <= 1'b1;
+ else if (wdtifg_clr) wdtifg <= 1'b0;
+
+
+// Watchdog interrupt generation
+//---------------------------------
+wire wdt_irq = wdttmsel & wdtifg & wdtie;
+wire wdt_wkup = 1'b0;
+
+
+// Watchdog reset generation
+//-----------------------------
+reg wdt_reset;
+
+always @ (posedge mclk or posedge por)
+ if (por) wdt_reset <= 1'b0;
+ else wdt_reset <= wdtpw_error | (wdtifg_set & ~wdttmsel);
+
+
+`endif
+
+
+endmodule // omsp_watchdog
+
+`ifdef OMSP_NO_INCLUDE
+`else
+`include "openMSP430_undefines.v"
+`endif