From 7764d0ba1dcf064ae487ee985c43083a0909e7f4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 5 Jan 2013 11:13:26 +0100 Subject: initial import --- tests/openmsp430/rtl/omsp_alu.v | 258 +++++++ tests/openmsp430/rtl/omsp_and_gate.v | 89 +++ tests/openmsp430/rtl/omsp_clock_gate.v | 86 +++ tests/openmsp430/rtl/omsp_clock_module.v | 1058 +++++++++++++++++++++++++++ tests/openmsp430/rtl/omsp_clock_mux.v | 192 +++++ tests/openmsp430/rtl/omsp_dbg.v | 827 +++++++++++++++++++++ tests/openmsp430/rtl/omsp_dbg_hwbrk.v | 282 +++++++ tests/openmsp430/rtl/omsp_dbg_uart.v | 298 ++++++++ tests/openmsp430/rtl/omsp_execution_unit.v | 420 +++++++++++ tests/openmsp430/rtl/omsp_frontend.v | 966 ++++++++++++++++++++++++ tests/openmsp430/rtl/omsp_mem_backbone.v | 275 +++++++ tests/openmsp430/rtl/omsp_multiplier.v | 420 +++++++++++ tests/openmsp430/rtl/omsp_register_file.v | 618 ++++++++++++++++ tests/openmsp430/rtl/omsp_scan_mux.v | 75 ++ tests/openmsp430/rtl/omsp_sfr.v | 353 +++++++++ tests/openmsp430/rtl/omsp_sync_cell.v | 80 ++ tests/openmsp430/rtl/omsp_sync_reset.v | 78 ++ tests/openmsp430/rtl/omsp_wakeup_cell.v | 108 +++ tests/openmsp430/rtl/omsp_watchdog.v | 556 ++++++++++++++ tests/openmsp430/rtl/openMSP430.v | 584 +++++++++++++++ tests/openmsp430/rtl/openMSP430_defines.v | 843 +++++++++++++++++++++ tests/openmsp430/rtl/openMSP430_undefines.v | 732 ++++++++++++++++++ 22 files changed, 9198 insertions(+) create mode 100644 tests/openmsp430/rtl/omsp_alu.v create mode 100644 tests/openmsp430/rtl/omsp_and_gate.v create mode 100644 tests/openmsp430/rtl/omsp_clock_gate.v create mode 100644 tests/openmsp430/rtl/omsp_clock_module.v create mode 100644 tests/openmsp430/rtl/omsp_clock_mux.v create mode 100644 tests/openmsp430/rtl/omsp_dbg.v create mode 100644 tests/openmsp430/rtl/omsp_dbg_hwbrk.v create mode 100644 tests/openmsp430/rtl/omsp_dbg_uart.v create mode 100644 tests/openmsp430/rtl/omsp_execution_unit.v create mode 100644 tests/openmsp430/rtl/omsp_frontend.v create mode 100644 tests/openmsp430/rtl/omsp_mem_backbone.v create mode 100644 tests/openmsp430/rtl/omsp_multiplier.v create mode 100644 tests/openmsp430/rtl/omsp_register_file.v create mode 100644 tests/openmsp430/rtl/omsp_scan_mux.v create mode 100644 tests/openmsp430/rtl/omsp_sfr.v create mode 100644 tests/openmsp430/rtl/omsp_sync_cell.v create mode 100644 tests/openmsp430/rtl/omsp_sync_reset.v create mode 100644 tests/openmsp430/rtl/omsp_wakeup_cell.v create mode 100644 tests/openmsp430/rtl/omsp_watchdog.v create mode 100644 tests/openmsp430/rtl/openMSP430.v create mode 100644 tests/openmsp430/rtl/openMSP430_defines.v create mode 100644 tests/openmsp430/rtl/openMSP430_undefines.v (limited to 'tests/openmsp430/rtl') diff --git a/tests/openmsp430/rtl/omsp_alu.v b/tests/openmsp430/rtl/omsp_alu.v new file mode 100644 index 00000000..d1069973 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_alu.v @@ -0,0 +1,258 @@ +//---------------------------------------------------------------------------- +// 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_alu.v +// +// *Module Description: +// openMSP430 ALU +// +// *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_alu ( + +// OUTPUTs + alu_out, // ALU output value + alu_out_add, // ALU adder output value + alu_stat, // ALU Status {V,N,Z,C} + alu_stat_wr, // ALU Status write {V,N,Z,C} + +// INPUTs + dbg_halt_st, // Halt/Run status from CPU + exec_cycle, // Instruction execution cycle + inst_alu, // ALU control signals + inst_bw, // Decoded Inst: byte width + inst_jmp, // Decoded Inst: Conditional jump + inst_so, // Single-operand arithmetic + op_dst, // Destination operand + op_src, // Source operand + status // R2 Status {V,N,Z,C} +); + +// OUTPUTs +//========= +output [15:0] alu_out; // ALU output value +output [15:0] alu_out_add; // ALU adder output value +output [3:0] alu_stat; // ALU Status {V,N,Z,C} +output [3:0] alu_stat_wr; // ALU Status write {V,N,Z,C} + +// INPUTs +//========= +input dbg_halt_st; // Halt/Run status from CPU +input exec_cycle; // Instruction execution cycle +input [11:0] inst_alu; // ALU control signals +input inst_bw; // Decoded Inst: byte width +input [7:0] inst_jmp; // Decoded Inst: Conditional jump +input [7:0] inst_so; // Single-operand arithmetic +input [15:0] op_dst; // Destination operand +input [15:0] op_src; // Source operand +input [3:0] status; // R2 Status {V,N,Z,C} + + +//============================================================================= +// 1) FUNCTIONS +//============================================================================= + +function [4:0] bcd_add; + + input [3:0] X; + input [3:0] Y; + input C_; + + reg [4:0] Z_; + begin + Z_ = {1'b0,X}+{1'b0,Y}+{4'b0,C_}; + if (Z_<5'd10) bcd_add = Z_; + else bcd_add = Z_+5'd6; + end + +endfunction + + +//============================================================================= +// 2) INSTRUCTION FETCH/DECODE CONTROL STATE MACHINE +//============================================================================= +// SINGLE-OPERAND ARITHMETIC: +//----------------------------------------------------------------------------- +// Mnemonic S-Reg, Operation Status bits +// D-Reg, V N Z C +// +// RRC dst C->MSB->...LSB->C * * * * +// RRA dst MSB->MSB->...LSB->C 0 * * * +// SWPB dst Swap bytes - - - - +// SXT dst Bit7->Bit8...Bit15 0 * * * +// PUSH src SP-2->SP, src->@SP - - - - +// CALL dst SP-2->SP, PC+2->@SP, dst->PC - - - - +// RETI TOS->SR, SP+2->SP, TOS->PC, SP+2->SP * * * * +// +//----------------------------------------------------------------------------- +// TWO-OPERAND ARITHMETIC: +//----------------------------------------------------------------------------- +// Mnemonic S-Reg, Operation Status bits +// D-Reg, V N Z C +// +// MOV src,dst src -> dst - - - - +// ADD src,dst src + dst -> dst * * * * +// ADDC src,dst src + dst + C -> dst * * * * +// SUB src,dst dst + ~src + 1 -> dst * * * * +// SUBC src,dst dst + ~src + C -> dst * * * * +// CMP src,dst dst + ~src + 1 * * * * +// DADD src,dst src + dst + C -> dst (decimaly) * * * * +// BIT src,dst src & dst 0 * * * +// BIC src,dst ~src & dst -> dst - - - - +// BIS src,dst src | dst -> dst - - - - +// XOR src,dst src ^ dst -> dst * * * * +// AND src,dst src & dst -> dst 0 * * * +// +//----------------------------------------------------------------------------- +// * the status bit is affected +// - the status bit is not affected +// 0 the status bit is cleared +// 1 the status bit is set +//----------------------------------------------------------------------------- + +// Invert source for substract and compare instructions. +wire op_src_inv_cmd = exec_cycle & (inst_alu[`ALU_SRC_INV]); +wire [15:0] op_src_inv = {16{op_src_inv_cmd}} ^ op_src; + + +// Mask the bit 8 for the Byte instructions for correct flags generation +wire op_bit8_msk = ~exec_cycle | ~inst_bw; +wire [16:0] op_src_in = {1'b0, {op_src_inv[15:8] & {8{op_bit8_msk}}}, op_src_inv[7:0]}; +wire [16:0] op_dst_in = {1'b0, {op_dst[15:8] & {8{op_bit8_msk}}}, op_dst[7:0]}; + +// Clear the source operand (= jump offset) for conditional jumps +wire jmp_not_taken = (inst_jmp[`JL] & ~(status[3]^status[2])) | + (inst_jmp[`JGE] & (status[3]^status[2])) | + (inst_jmp[`JN] & ~status[2]) | + (inst_jmp[`JC] & ~status[0]) | + (inst_jmp[`JNC] & status[0]) | + (inst_jmp[`JEQ] & ~status[1]) | + (inst_jmp[`JNE] & status[1]); +wire [16:0] op_src_in_jmp = op_src_in & {17{~jmp_not_taken}}; + +// Adder / AND / OR / XOR +wire [16:0] alu_add = op_src_in_jmp + op_dst_in; +wire [16:0] alu_and = op_src_in & op_dst_in; +wire [16:0] alu_or = op_src_in | op_dst_in; +wire [16:0] alu_xor = op_src_in ^ op_dst_in; + + +// Incrementer +wire alu_inc = exec_cycle & ((inst_alu[`ALU_INC_C] & status[0]) | + inst_alu[`ALU_INC]); +wire [16:0] alu_add_inc = alu_add + {16'h0000, alu_inc}; + + + +// Decimal adder (DADD) +wire [4:0] alu_dadd0 = bcd_add(op_src_in[3:0], op_dst_in[3:0], status[0]); +wire [4:0] alu_dadd1 = bcd_add(op_src_in[7:4], op_dst_in[7:4], alu_dadd0[4]); +wire [4:0] alu_dadd2 = bcd_add(op_src_in[11:8], op_dst_in[11:8], alu_dadd1[4]); +wire [4:0] alu_dadd3 = bcd_add(op_src_in[15:12], op_dst_in[15:12],alu_dadd2[4]); +wire [16:0] alu_dadd = {alu_dadd3, alu_dadd2[3:0], alu_dadd1[3:0], alu_dadd0[3:0]}; + + +// Shifter for rotate instructions (RRC & RRA) +wire alu_shift_msb = inst_so[`RRC] ? status[0] : + inst_bw ? op_src[7] : op_src[15]; +wire alu_shift_7 = inst_bw ? alu_shift_msb : op_src[8]; +wire [16:0] alu_shift = {1'b0, alu_shift_msb, op_src[15:9], alu_shift_7, op_src[7:1]}; + + +// Swap bytes / Extend Sign +wire [16:0] alu_swpb = {1'b0, op_src[7:0],op_src[15:8]}; +wire [16:0] alu_sxt = {1'b0, {8{op_src[7]}},op_src[7:0]}; + + +// Combine short paths toghether to simplify final ALU mux +wire alu_short_thro = ~(inst_alu[`ALU_AND] | + inst_alu[`ALU_OR] | + inst_alu[`ALU_XOR] | + inst_alu[`ALU_SHIFT] | + inst_so[`SWPB] | + inst_so[`SXT]); + +wire [16:0] alu_short = ({17{inst_alu[`ALU_AND]}} & alu_and) | + ({17{inst_alu[`ALU_OR]}} & alu_or) | + ({17{inst_alu[`ALU_XOR]}} & alu_xor) | + ({17{inst_alu[`ALU_SHIFT]}} & alu_shift) | + ({17{inst_so[`SWPB]}} & alu_swpb) | + ({17{inst_so[`SXT]}} & alu_sxt) | + ({17{alu_short_thro}} & op_src_in); + + +// ALU output mux +wire [16:0] alu_out_nxt = (inst_so[`IRQ] | dbg_halt_st | + inst_alu[`ALU_ADD]) ? alu_add_inc : + inst_alu[`ALU_DADD] ? alu_dadd : alu_short; + +assign alu_out = alu_out_nxt[15:0]; +assign alu_out_add = alu_add[15:0]; + + +//----------------------------------------------------------------------------- +// STATUS FLAG GENERATION +//----------------------------------------------------------------------------- + +wire V_xor = inst_bw ? (op_src_in[7] & op_dst_in[7]) : + (op_src_in[15] & op_dst_in[15]); + +wire V = inst_bw ? ((~op_src_in[7] & ~op_dst_in[7] & alu_out[7]) | + ( op_src_in[7] & op_dst_in[7] & ~alu_out[7])) : + ((~op_src_in[15] & ~op_dst_in[15] & alu_out[15]) | + ( op_src_in[15] & op_dst_in[15] & ~alu_out[15])); + +wire N = inst_bw ? alu_out[7] : alu_out[15]; +wire Z = inst_bw ? (alu_out[7:0]==0) : (alu_out==0); +wire C = inst_bw ? alu_out[8] : alu_out_nxt[16]; + +assign alu_stat = inst_alu[`ALU_SHIFT] ? {1'b0, N,Z,op_src_in[0]} : + inst_alu[`ALU_STAT_7] ? {1'b0, N,Z,~Z} : + inst_alu[`ALU_XOR] ? {V_xor,N,Z,~Z} : {V,N,Z,C}; + +assign alu_stat_wr = (inst_alu[`ALU_STAT_F] & exec_cycle) ? 4'b1111 : 4'b0000; + + +endmodule // omsp_alu + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_and_gate.v b/tests/openmsp430/rtl/omsp_and_gate.v new file mode 100644 index 00000000..7ceeb8d9 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_and_gate.v @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------- +// 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_and_gate.v +// +// *Module Description: +// Generic AND gate cell for the openMSP430 +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_and_gate ( + +// OUTPUTs + y, // AND gate output + +// INPUTs + a, // AND gate input A + b // AND gate input B +); + +// OUTPUTs +//========= +output y; // AND gate output + +// INPUTs +//========= +input a; // AND gate input A +input b; // AND gate input B + + +//============================================================================= +// 1) SOME COMMENTS ON THIS MODULE +//============================================================================= +// +// In its ASIC version, some combinatorial pathes of the openMSP430 are +// sensitive to glitches, in particular the ones generating the wakeup +// signals. +// To prevent synthesis from optmizing combinatorial clouds into glitchy +// logic, this AND gate module has been instanciated in the critical places. +// +// Make sure that synthesis doesn't ungroup this module. As an alternative, +// a standard cell from the library could also be directly instanciated here +// (don't forget the "dont_touch" attribute) +// +// +//============================================================================= +// 2) AND GATE +//============================================================================= + +assign y = a & b; + + +endmodule // omsp_and_gate + + + diff --git a/tests/openmsp430/rtl/omsp_clock_gate.v b/tests/openmsp430/rtl/omsp_clock_gate.v new file mode 100644 index 00000000..8ffe8e0d --- /dev/null +++ b/tests/openmsp430/rtl/omsp_clock_gate.v @@ -0,0 +1,86 @@ +//---------------------------------------------------------------------------- +// 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_clock_gate.v +// +// *Module Description: +// Generic clock gate cell for the openMSP430 +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_clock_gate ( + +// OUTPUTs + gclk, // Gated clock + +// INPUTs + clk, // Clock + enable, // Clock enable + scan_enable // Scan enable (active during scan shifting) +); + +// OUTPUTs +//========= +output gclk; // Gated clock + +// INPUTs +//========= +input clk; // Clock +input enable; // Clock enable +input scan_enable; // Scan enable (active during scan shifting) + + +//============================================================================= +// CLOCK GATE: LATCH + AND +//============================================================================= + +// Enable clock gate during scan shift +// (the gate itself is checked with the scan capture cycle) +wire enable_in = (enable | scan_enable); + +// LATCH the enable signal +reg enable_latch; +always @(clk or enable_in) + if (~clk) + enable_latch <= enable_in; + +// AND gate +assign gclk = (clk & enable_latch); + + +endmodule // omsp_clock_gate + + diff --git a/tests/openmsp430/rtl/omsp_clock_module.v b/tests/openmsp430/rtl/omsp_clock_module.v new file mode 100644 index 00000000..670c5e59 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_clock_module.v @@ -0,0 +1,1058 @@ +//---------------------------------------------------------------------------- +// 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_clock_module.v +// +// *Module Description: +// Basic clock module implementation. +// +// *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_clock_module ( + +// OUTPUTs + aclk, // ACLK + aclk_en, // ACLK enable + cpu_en_s, // Enable CPU code execution (synchronous) + dbg_clk, // Debug unit clock + dbg_en_s, // Debug interface enable (synchronous) + dbg_rst, // Debug unit reset + dco_enable, // Fast oscillator enable + dco_wkup, // Fast oscillator wake-up (asynchronous) + lfxt_enable, // Low frequency oscillator enable + lfxt_wkup, // Low frequency oscillator wake-up (asynchronous) + mclk, // Main system clock + per_dout, // Peripheral data output + por, // Power-on reset + puc_pnd_set, // PUC pending set for the serial debug interface + puc_rst, // Main system reset + smclk, // SMCLK + smclk_en, // SMCLK enable + +// INPUTs + cpu_en, // Enable CPU code execution (asynchronous) + cpuoff, // Turns off the CPU + dbg_cpu_reset, // Reset CPU from debug interface + dbg_en, // Debug interface enable (asynchronous) + dco_clk, // Fast oscillator (fast clock) + lfxt_clk, // Low frequency oscillator (typ 32kHz) + mclk_enable, // Main System Clock enable + mclk_wkup, // Main System Clock wake-up (asynchronous) + oscoff, // Turns off LFXT1 clock input + per_addr, // Peripheral address + per_din, // Peripheral data input + per_en, // Peripheral enable (high active) + per_we, // Peripheral write enable (high active) + reset_n, // Reset Pin (low active, asynchronous) + scan_enable, // Scan enable (active during scan shifting) + scan_mode, // Scan mode + scg0, // System clock generator 1. Turns off the DCO + scg1, // System clock generator 1. Turns off the SMCLK + wdt_reset // Watchdog-timer reset +); + +// OUTPUTs +//========= +output aclk; // ACLK +output aclk_en; // ACLK enable +output cpu_en_s; // Enable CPU code execution (synchronous) +output dbg_clk; // Debug unit clock +output dbg_en_s; // Debug unit enable (synchronous) +output dbg_rst; // Debug unit reset +output dco_enable; // Fast oscillator enable +output dco_wkup; // Fast oscillator wake-up (asynchronous) +output lfxt_enable; // Low frequency oscillator enable +output lfxt_wkup; // Low frequency oscillator wake-up (asynchronous) +output mclk; // Main system clock +output [15:0] per_dout; // Peripheral data output +output por; // Power-on reset +output puc_pnd_set; // PUC pending set for the serial debug interface +output puc_rst; // Main system reset +output smclk; // SMCLK +output smclk_en; // SMCLK enable + +// INPUTs +//========= +input cpu_en; // Enable CPU code execution (asynchronous) +input cpuoff; // Turns off the CPU +input dbg_cpu_reset;// Reset CPU from debug interface +input dbg_en; // Debug interface enable (asynchronous) +input dco_clk; // Fast oscillator (fast clock) +input lfxt_clk; // Low frequency oscillator (typ 32kHz) +input mclk_enable; // Main System Clock enable +input mclk_wkup; // Main System Clock wake-up (asynchronous) +input oscoff; // Turns off LFXT1 clock input +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 reset_n; // Reset Pin (low active, asynchronous) +input scan_enable; // Scan enable (active during scan shifting) +input scan_mode; // Scan mode +input scg0; // System clock generator 1. Turns off the DCO +input scg1; // System clock generator 1. Turns off the SMCLK +input wdt_reset; // Watchdog-timer reset + + +//============================================================================= +// 1) WIRES & PARAMETER DECLARATION +//============================================================================= + +// Register base address (must be aligned to decoder bit width) +parameter [14:0] BASE_ADDR = 15'h0050; + +// Decoder bit width (defines how many bits are considered for address decoding) +parameter DEC_WD = 4; + +// Register addresses offset +parameter [DEC_WD-1:0] BCSCTL1 = 'h7, + BCSCTL2 = 'h8; + +// 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] BCSCTL1_D = (BASE_REG << BCSCTL1), + BCSCTL2_D = (BASE_REG << BCSCTL2); + +// Local wire declarations +wire nodiv_mclk; +wire nodiv_mclk_n; +wire nodiv_smclk; + + +//============================================================================ +// 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 = {1'b0, per_addr[DEC_WD-2:0]}; + +// Register address decode +wire [DEC_SZ-1:0] reg_dec = (BCSCTL1_D & {DEC_SZ{(reg_addr==(BCSCTL1 >>1))}}) | + (BCSCTL2_D & {DEC_SZ{(reg_addr==(BCSCTL2 >>1))}}); + +// Read/Write probes +wire reg_lo_write = per_we[0] & reg_sel; +wire reg_hi_write = per_we[1] & reg_sel; +wire reg_read = ~|per_we & reg_sel; + +// Read/Write vectors +wire [DEC_SZ-1:0] reg_hi_wr = reg_dec & {DEC_SZ{reg_hi_write}}; +wire [DEC_SZ-1:0] reg_lo_wr = reg_dec & {DEC_SZ{reg_lo_write}}; +wire [DEC_SZ-1:0] reg_rd = reg_dec & {DEC_SZ{reg_read}}; + + +//============================================================================ +// 3) REGISTERS +//============================================================================ + +// BCSCTL1 Register +//-------------- +reg [7:0] bcsctl1; +wire bcsctl1_wr = BCSCTL1[0] ? reg_hi_wr[BCSCTL1] : reg_lo_wr[BCSCTL1]; +wire [7:0] bcsctl1_nxt = BCSCTL1[0] ? per_din[15:8] : per_din[7:0]; + +`ifdef ASIC + `ifdef ACLK_DIVIDER +wire [7:0] divax_mask = 8'h30; + `else +wire [7:0] divax_mask = 8'h00; + `endif +`else +wire [7:0] divax_mask = 8'h30; +`endif + +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) bcsctl1 <= 8'h00; + else if (bcsctl1_wr) bcsctl1 <= bcsctl1_nxt & divax_mask; // Mask unused bits + + +// BCSCTL2 Register +//-------------- +reg [7:0] bcsctl2; +wire bcsctl2_wr = BCSCTL2[0] ? reg_hi_wr[BCSCTL2] : reg_lo_wr[BCSCTL2]; +wire [7:0] bcsctl2_nxt = BCSCTL2[0] ? per_din[15:8] : per_din[7:0]; + +`ifdef MCLK_MUX +wire [7:0] selmx_mask = 8'h80; +`else +wire [7:0] selmx_mask = 8'h00; +`endif +`ifdef MCLK_DIVIDER +wire [7:0] divmx_mask = 8'h30; +`else +wire [7:0] divmx_mask = 8'h00; +`endif +`ifdef ASIC + `ifdef SMCLK_MUX +wire [7:0] sels_mask = 8'h08; + `else +wire [7:0] sels_mask = 8'h00; + `endif + `ifdef SMCLK_DIVIDER +wire [7:0] divsx_mask = 8'h06; + `else +wire [7:0] divsx_mask = 8'h00; + `endif +`else +wire [7:0] sels_mask = 8'h08; +wire [7:0] divsx_mask = 8'h06; +`endif + +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) bcsctl2 <= 8'h00; + else if (bcsctl2_wr) bcsctl2 <= bcsctl2_nxt & ( sels_mask | divsx_mask | + selmx_mask | divmx_mask); // Mask unused bits + + +//============================================================================ +// 4) DATA OUTPUT GENERATION +//============================================================================ + +// Data output mux +wire [15:0] bcsctl1_rd = {8'h00, (bcsctl1 & {8{reg_rd[BCSCTL1]}})} << (8 & {4{BCSCTL1[0]}}); +wire [15:0] bcsctl2_rd = {8'h00, (bcsctl2 & {8{reg_rd[BCSCTL2]}})} << (8 & {4{BCSCTL2[0]}}); + +wire [15:0] per_dout = bcsctl1_rd | + bcsctl2_rd; + + +//============================================================================= +// 5) DCO_CLK / LFXT_CLK INTERFACES (WAKEUP, ENABLE, ...) +//============================================================================= + +`ifdef ASIC + wire cpuoff_and_mclk_enable; + omsp_and_gate and_cpuoff_mclk_en (.y(cpuoff_and_mclk_enable), .a(cpuoff), .b(mclk_enable)); +`endif + +//----------------------------------------------------------- +// 5.1) HIGH SPEED SYSTEM CLOCK GENERATOR (DCO_CLK) +//----------------------------------------------------------- +// Note1: switching off the DCO osillator is only +// supported in ASIC mode with SCG0 low power mode +// +// Note2: unlike the original MSP430 specification, +// we allow to switch off the DCO even +// if it is selected by MCLK or SMCLK. + +wire por_a; +wire dco_wkup; +wire cpu_en_wkup; + +`ifdef SCG0_EN + + // The DCO oscillator is synchronously disabled if: + // - the cpu pin is disabled (in that case, wait for mclk_enable==0) + // - the debug interface is disabled + // - SCG0 is set (in that case, wait for the mclk_enable==0 if selected by SELMx) + // + // Note that we make extensive use of the AND gate module in order + // to prevent glitch propagation on the wakeup logic cone. + wire cpu_enabled_with_dco; + wire dco_not_enabled_by_dbg; + wire dco_disable_by_scg0; + wire dco_disable_by_cpu_en; + wire dco_enable_nxt; + omsp_and_gate and_dco_dis1 (.y(cpu_enabled_with_dco), .a(~bcsctl2[`SELMx]), .b(cpuoff_and_mclk_enable)); + omsp_and_gate and_dco_dis2 (.y(dco_not_enabled_by_dbg), .a(~dbg_en_s), .b(~cpu_enabled_with_dco)); + omsp_and_gate and_dco_dis3 (.y(dco_disable_by_scg0), .a(scg0), .b(dco_not_enabled_by_dbg)); + omsp_and_gate and_dco_dis4 (.y(dco_disable_by_cpu_en), .a(~cpu_en_s), .b(~mclk_enable)); + omsp_and_gate and_dco_dis5 (.y(dco_enable_nxt), .a(~dco_disable_by_scg0), .b(~dco_disable_by_cpu_en)); + + // Register to prevent glitch propagation + reg dco_disable; + always @(posedge nodiv_mclk_n or posedge por) + if (por) dco_disable <= 1'b1; + else dco_disable <= ~dco_enable_nxt; + + // Note that a synchronizer is required if the MCLK mux is included + wire dco_clk_n = ~dco_clk; + `ifdef MCLK_MUX + omsp_sync_cell sync_cell_dco_disable ( + .data_out (dco_enable), + .data_in (~dco_disable), + .clk (dco_clk_n), + .rst (por) + ); + `else + + assign dco_enable = ~dco_disable; + `endif + + // The DCO oscillator will get an asynchronous wakeup if: + // - the MCLK generates a wakeup (only if the MCLK mux selects dco_clk) + // - if the DCO wants to be synchronously enabled (i.e dco_enable_nxt=1) + wire dco_mclk_wkup; + wire dco_en_wkup; + omsp_and_gate and_dco_mclk_wkup (.y(dco_mclk_wkup), .a(mclk_wkup), .b(~bcsctl2[`SELMx])); + omsp_and_gate and_dco_en_wkup (.y(dco_en_wkup), .a(~dco_enable), .b(dco_enable_nxt)); + + wire dco_wkup_set = dco_mclk_wkup | dco_en_wkup | cpu_en_wkup; + + // Scan MUX for the asynchronous SET + wire dco_wkup_set_scan; + omsp_scan_mux scan_mux_dco_wkup ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (dco_wkup_set | por), + .data_out (dco_wkup_set_scan) + ); + + // Scan MUX to increase coverage + wire dco_wkup_clear; + omsp_scan_mux scan_mux_dco_wkup_clear ( + .scan_mode (scan_mode), + .data_in_scan (dco_wkup_set), + .data_in_func (1'b1), + .data_out (dco_wkup_clear) + ); + + // The wakeup is asynchronously set, synchronously released + wire dco_wkup_n; + omsp_sync_cell sync_cell_dco_wkup ( + .data_out (dco_wkup_n), + .data_in (dco_wkup_clear), + .clk (dco_clk_n), + .rst (dco_wkup_set_scan) + ); + + omsp_and_gate and_dco_wkup (.y(dco_wkup), .a(~dco_wkup_n), .b(cpu_en)); + +`else + assign dco_enable = 1'b1; + assign dco_wkup = 1'b1; +`endif + + +//----------------------------------------------------------- +// 5.2) LOW FREQUENCY CRYSTAL CLOCK GENERATOR (LFXT_CLK) +//----------------------------------------------------------- + +// ASIC MODE +//------------------------------------------------ +// Note: unlike the original MSP430 specification, +// we allow to switch off the LFXT even +// if it is selected by MCLK or SMCLK. +`ifdef ASIC + +`ifdef OSCOFF_EN + + // The LFXT is synchronously disabled if: + // - the cpu pin is disabled (in that case, wait for mclk_enable==0) + // - the debug interface is disabled + // - OSCOFF is set (in that case, wait for the mclk_enable==0 if selected by SELMx) + wire cpu_enabled_with_lfxt; + wire lfxt_not_enabled_by_dbg; + wire lfxt_disable_by_oscoff; + wire lfxt_disable_by_cpu_en; + wire lfxt_enable_nxt; + omsp_and_gate and_lfxt_dis1 (.y(cpu_enabled_with_lfxt), .a(bcsctl2[`SELMx]), .b(cpuoff_and_mclk_enable)); + omsp_and_gate and_lfxt_dis2 (.y(lfxt_not_enabled_by_dbg), .a(~dbg_en_s), .b(~cpu_enabled_with_lfxt)); + omsp_and_gate and_lfxt_dis3 (.y(lfxt_disable_by_oscoff), .a(oscoff), .b(lfxt_not_enabled_by_dbg)); + omsp_and_gate and_lfxt_dis4 (.y(lfxt_disable_by_cpu_en), .a(~cpu_en_s), .b(~mclk_enable)); + omsp_and_gate and_lfxt_dis5 (.y(lfxt_enable_nxt), .a(~lfxt_disable_by_oscoff), .b(~lfxt_disable_by_cpu_en)); + + // Register to prevent glitch propagation + reg lfxt_disable; + always @(posedge nodiv_mclk_n or posedge por) + if (por) lfxt_disable <= 1'b1; + else lfxt_disable <= ~lfxt_enable_nxt; + + // Synchronize the OSCOFF control signal to the LFXT clock domain + wire lfxt_clk_n = ~lfxt_clk; + omsp_sync_cell sync_cell_lfxt_disable ( + .data_out (lfxt_enable), + .data_in (~lfxt_disable), + .clk (lfxt_clk_n), + .rst (por) + ); + + // The LFXT will get an asynchronous wakeup if: + // - the MCLK generates a wakeup (only if the MCLK mux selects lfxt_clk) + // - if the LFXT wants to be synchronously enabled (i.e lfxt_enable_nxt=1) + wire lfxt_mclk_wkup; + wire lfxt_en_wkup; + omsp_and_gate and_lfxt_mclk_wkup (.y(lfxt_mclk_wkup), .a(mclk_wkup), .b(bcsctl2[`SELMx])); + omsp_and_gate and_lfxt_en_wkup (.y(lfxt_en_wkup), .a(~lfxt_enable), .b(lfxt_enable_nxt)); + + wire lfxt_wkup_set = lfxt_mclk_wkup | lfxt_en_wkup | cpu_en_wkup; + + // Scan MUX for the asynchronous SET + wire lfxt_wkup_set_scan; + omsp_scan_mux scan_mux_lfxt_wkup ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (lfxt_wkup_set | por), + .data_out (lfxt_wkup_set_scan) + ); + + // Scan MUX to increase coverage + wire lfxt_wkup_clear; + omsp_scan_mux scan_mux_lfxt_wkup_clear ( + .scan_mode (scan_mode), + .data_in_scan (lfxt_wkup_set), + .data_in_func (1'b1), + .data_out (lfxt_wkup_clear) + ); + + // The wakeup is asynchronously set, synchronously released + wire lfxt_wkup_n; + omsp_sync_cell sync_cell_lfxt_wkup ( + .data_out (lfxt_wkup_n), + .data_in (lfxt_wkup_clear), + .clk (lfxt_clk_n), + .rst (lfxt_wkup_set_scan) + ); + + omsp_and_gate and_lfxt_wkup (.y(lfxt_wkup), .a(~lfxt_wkup_n), .b(cpu_en)); + +`else + assign lfxt_enable = 1'b1; + assign lfxt_wkup = 1'b0; +`endif + + +// FPGA MODE +//--------------------------------------- +// Synchronize LFXT_CLK & edge detection +`else + +wire lfxt_clk_s; + +omsp_sync_cell sync_cell_lfxt_clk ( + .data_out (lfxt_clk_s), + .data_in (lfxt_clk), + .clk (mclk), + .rst (por) +); + +reg lfxt_clk_dly; + +always @ (posedge mclk or posedge por) + if (por) lfxt_clk_dly <= 1'b0; + else lfxt_clk_dly <= lfxt_clk_s; + +wire lfxt_clk_en = (lfxt_clk_s & ~lfxt_clk_dly) & ~(oscoff & ~bcsctl2[`SELS]); +assign lfxt_enable = 1'b1; +assign lfxt_wkup = 1'b0; +`endif + + +//============================================================================= +// 6) CLOCK GENERATION +//============================================================================= + +//----------------------------------------------------------- +// 6.1) GLOBAL CPU ENABLE +//----------------------------------------------------------- +// ACLK and SMCLK are directly switched-off +// with the cpu_en pin (after synchronization). +// MCLK will be switched off once the CPU reaches +// its IDLE state (through the mclk_enable signal) + + +// Synchronize CPU_EN signal to the MCLK domain +//---------------------------------------------- +`ifdef SYNC_CPU_EN + omsp_sync_cell sync_cell_cpu_en ( + .data_out (cpu_en_s), + .data_in (cpu_en), + .clk (nodiv_mclk), + .rst (por) + ); + omsp_and_gate and_cpu_en_wkup (.y(cpu_en_wkup), .a(cpu_en), .b(~cpu_en_s)); +`else + assign cpu_en_s = cpu_en; + assign cpu_en_wkup = 1'b0; +`endif + +// Synchronize CPU_EN signal to the ACLK domain +//---------------------------------------------- +`ifdef LFXT_DOMAIN + wire cpu_en_aux_s; + omsp_sync_cell sync_cell_cpu_aux_en ( + .data_out (cpu_en_aux_s), + .data_in (cpu_en), + .clk (lfxt_clk), + .rst (por) + ); +`else + wire cpu_en_aux_s = cpu_en_s; +`endif + +// Synchronize CPU_EN signal to the SMCLK domain +//---------------------------------------------- +// Note: the synchronizer is only required if there is a SMCLK_MUX +`ifdef ASIC + `ifdef SMCLK_MUX + wire cpu_en_sm_s; + omsp_sync_cell sync_cell_cpu_sm_en ( + .data_out (cpu_en_sm_s), + .data_in (cpu_en), + .clk (nodiv_smclk), + .rst (por) + ); + `else + wire cpu_en_sm_s = cpu_en_s; + `endif +`endif + + +//----------------------------------------------------------- +// 6.2) MCLK GENERATION +//----------------------------------------------------------- + +// Clock MUX +//---------------------------- +`ifdef MCLK_MUX +omsp_clock_mux clock_mux_mclk ( + .clk_out (nodiv_mclk), + .clk_in0 (dco_clk), + .clk_in1 (lfxt_clk), + .reset (por), + .scan_mode (scan_mode), + .select (bcsctl2[`SELMx]) +); +`else +assign nodiv_mclk = dco_clk; +`endif +assign nodiv_mclk_n = ~nodiv_mclk; + + +// Wakeup synchronizer +//---------------------------- +wire mclk_wkup_s; + +`ifdef CPUOFF_EN +omsp_sync_cell sync_cell_mclk_wkup ( + .data_out (mclk_wkup_s), + .data_in (mclk_wkup), + .clk (nodiv_mclk), + .rst (puc_rst) +); +`else + assign mclk_wkup_s = 1'b0; +`endif + + +// Clock Divider +//---------------------------- +// No need for extra synchronizer as bcsctl2 +// comes from the same clock domain. + +`ifdef CPUOFF_EN +wire mclk_active = mclk_enable | mclk_wkup_s | (dbg_en_s & cpu_en_s); +`else +wire mclk_active = 1'b1; +`endif + +`ifdef MCLK_DIVIDER +reg [2:0] mclk_div; +always @ (posedge nodiv_mclk or posedge puc_rst) + if (puc_rst) mclk_div <= 3'h0; + else if ((bcsctl2[`DIVMx]!=2'b00)) mclk_div <= mclk_div+3'h1; + + wire mclk_div_en = mclk_active & ((bcsctl2[`DIVMx]==2'b00) ? 1'b1 : + (bcsctl2[`DIVMx]==2'b01) ? mclk_div[0] : + (bcsctl2[`DIVMx]==2'b10) ? &mclk_div[1:0] : + &mclk_div[2:0]); +`else + wire mclk_div_en = mclk_active; +`endif + + +// Generate main system clock +//---------------------------- +`ifdef MCLK_CGATE + +omsp_clock_gate clock_gate_mclk ( + .gclk (mclk), + .clk (nodiv_mclk), + .enable (mclk_div_en), + .scan_enable (scan_enable) +); +`else + assign mclk = nodiv_mclk; +`endif + + +//----------------------------------------------------------- +// 6.3) ACLK GENERATION +//----------------------------------------------------------- + +// ASIC MODE +//---------------------------- +`ifdef ASIC + + `ifdef ACLK_DIVIDER + `ifdef LFXT_DOMAIN + + wire nodiv_aclk = lfxt_clk; + + // Local Reset synchronizer + wire puc_lfxt_rst; + wire puc_lfxt_noscan_n; + omsp_sync_cell sync_cell_puc_lfxt ( + .data_out (puc_lfxt_noscan_n), + .data_in (1'b1), + .clk (nodiv_aclk), + .rst (puc_rst) + ); + omsp_scan_mux scan_mux_puc_lfxt ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (~puc_lfxt_noscan_n), + .data_out (puc_lfxt_rst) + ); + + // Local synchronizer for the bcsctl1.DIVAx configuration + // (note that we can live with a full bus synchronizer as + // it won't hurt if we get a wrong DIVAx value for a single clock cycle) + reg [1:0] divax_s; + reg [1:0] divax_ss; + always @ (posedge nodiv_aclk or posedge puc_lfxt_rst) + if (puc_lfxt_rst) + begin + divax_s <= 2'h0; + divax_ss <= 2'h0; + end + else + begin + divax_s <= bcsctl1[`DIVAx]; + divax_ss <= divax_s; + end + + // If the OSCOFF mode is enabled synchronize OSCOFF signal + wire oscoff_s; + `ifdef OSCOFF_EN + omsp_sync_cell sync_cell_oscoff ( + .data_out (oscoff_s), + .data_in (oscoff), + .clk (nodiv_aclk), + .rst (puc_lfxt_rst) + ); + `else + assign oscoff_s = 1'b0; + `endif + `else + wire puc_lfxt_rst = puc_rst; + wire nodiv_aclk = dco_clk; + wire [1:0] divax_ss = bcsctl1[`DIVAx]; + wire oscoff_s = oscoff; + `endif + + // Divider + reg [2:0] aclk_div; + always @ (posedge nodiv_aclk or posedge puc_lfxt_rst) + if (puc_lfxt_rst) aclk_div <= 3'h0; + else if ((divax_ss!=2'b00)) aclk_div <= aclk_div+3'h1; + + wire aclk_div_en = cpu_en_aux_s & ~oscoff_s & ((divax_ss==2'b00) ? 1'b1 : + (divax_ss==2'b01) ? aclk_div[0] : + (divax_ss==2'b10) ? &aclk_div[1:0] : + &aclk_div[2:0]); + + // Clock gate + omsp_clock_gate clock_gate_aclk ( + .gclk (aclk), + .clk (nodiv_aclk), + .enable (aclk_div_en), + .scan_enable (scan_enable) + ); + + `else + `ifdef LFXT_DOMAIN + assign aclk = lfxt_clk; + `else + assign aclk = dco_clk; + `endif + `endif + + + assign aclk_en = 1'b1; + + +// FPGA MODE +//---------------------------- +`else + reg aclk_en; + reg [2:0] aclk_div; + wire aclk_en_nxt = lfxt_clk_en & ((bcsctl1[`DIVAx]==2'b00) ? 1'b1 : + (bcsctl1[`DIVAx]==2'b01) ? aclk_div[0] : + (bcsctl1[`DIVAx]==2'b10) ? &aclk_div[1:0] : + &aclk_div[2:0]); + + always @ (posedge mclk or posedge puc_rst) + if (puc_rst) aclk_div <= 3'h0; + else if ((bcsctl1[`DIVAx]!=2'b00) & lfxt_clk_en) aclk_div <= aclk_div+3'h1; + + always @ (posedge mclk or posedge puc_rst) + if (puc_rst) aclk_en <= 1'b0; + else aclk_en <= aclk_en_nxt & cpu_en_s; + + assign aclk = mclk; +`endif + +//----------------------------------------------------------- +// 6.4) SMCLK GENERATION +//----------------------------------------------------------- + +// Clock MUX +//---------------------------- +`ifdef SMCLK_MUX +omsp_clock_mux clock_mux_smclk ( + .clk_out (nodiv_smclk), + .clk_in0 (dco_clk), + .clk_in1 (lfxt_clk), + .reset (por), + .scan_mode (scan_mode), + .select (bcsctl2[`SELS]) +); +`else +assign nodiv_smclk = dco_clk; +`endif + + +// ASIC MODE +//---------------------------- +`ifdef ASIC + `ifdef SMCLK_MUX + + // Synchronizers + //------------------------------------------------------ + // When the SMCLK MUX is enabled, the reset and DIVSx + // and SCG1 signals must be synchronized, otherwise not. + + // Local Reset synchronizer + wire puc_sm_noscan_n; + wire puc_sm_rst; + omsp_sync_cell sync_cell_puc_sm ( + .data_out (puc_sm_noscan_n), + .data_in (1'b1), + .clk (nodiv_smclk), + .rst (puc_rst) + ); + omsp_scan_mux scan_mux_puc_sm ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (~puc_sm_noscan_n), + .data_out (puc_sm_rst) + ); + + // SCG1 synchronizer + `ifdef SCG1_EN + wire scg1_s; + omsp_sync_cell sync_cell_scg1 ( + .data_out (scg1_s), + .data_in (scg1), + .clk (nodiv_smclk), + .rst (puc_sm_rst) + ); + `else + wire scg1_s = 1'b0; + `endif + + `ifdef SMCLK_DIVIDER + // Local synchronizer for the bcsctl2.DIVSx configuration + // (note that we can live with a full bus synchronizer as + // it won't hurt if we get a wrong DIVSx value for a single clock cycle) + reg [1:0] divsx_s; + reg [1:0] divsx_ss; + always @ (posedge nodiv_smclk or posedge puc_sm_rst) + if (puc_sm_rst) + begin + divsx_s <= 2'h0; + divsx_ss <= 2'h0; + end + else + begin + divsx_s <= bcsctl2[`DIVSx]; + divsx_ss <= divsx_s; + end + `endif + + `else + + wire puc_sm_rst = puc_rst; + wire [1:0] divsx_ss = bcsctl2[`DIVSx]; + wire scg1_s = scg1; + `endif + + + + // Clock Divider + //---------------------------- + `ifdef SMCLK_DIVIDER + + reg [2:0] smclk_div; + always @ (posedge nodiv_smclk or posedge puc_sm_rst) + if (puc_sm_rst) smclk_div <= 3'h0; + else if ((divsx_ss!=2'b00)) smclk_div <= smclk_div+3'h1; + + wire smclk_div_en = cpu_en_sm_s & ~scg1_s & ((divsx_ss==2'b00) ? 1'b1 : + (divsx_ss==2'b01) ? smclk_div[0] : + (divsx_ss==2'b10) ? &smclk_div[1:0] : + &smclk_div[2:0]); + `else + `ifdef SCG1_EN + wire smclk_div_en = cpu_en_sm_s & ~scg1_s; + `else + wire smclk_div_en = cpu_en_sm_s; + `endif + `endif + + + // Generate sub-system clock + //---------------------------- + `ifdef SMCLK_CGATE + omsp_clock_gate clock_gate_smclk ( + .gclk (smclk), + .clk (nodiv_smclk), + .enable (smclk_div_en), + .scan_enable (scan_enable) + ); + `else + assign smclk = nodiv_smclk; + `endif + + assign smclk_en = 1'b1; + + +// FPGA MODE +//---------------------------- +`else +reg smclk_en; +reg [2:0] smclk_div; + +wire smclk_in = ~scg1 & (bcsctl2[`SELS] ? lfxt_clk_en : 1'b1); + +wire smclk_en_nxt = smclk_in & ((bcsctl2[`DIVSx]==2'b00) ? 1'b1 : + (bcsctl2[`DIVSx]==2'b01) ? smclk_div[0] : + (bcsctl2[`DIVSx]==2'b10) ? &smclk_div[1:0] : + &smclk_div[2:0]); + +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) smclk_en <= 1'b0; + else smclk_en <= smclk_en_nxt & cpu_en_s; + +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) smclk_div <= 3'h0; + else if ((bcsctl2[`DIVSx]!=2'b00) & smclk_in) smclk_div <= smclk_div+3'h1; + +wire smclk = mclk; + +`endif + +//----------------------------------------------------------- +// 6.5) DEBUG INTERFACE CLOCK GENERATION (DBG_CLK) +//----------------------------------------------------------- + +// Synchronize DBG_EN signal to MCLK domain +//------------------------------------------ +`ifdef DBG_EN +`ifdef SYNC_DBG_EN + wire dbg_en_n_s; + omsp_sync_cell sync_cell_dbg_en ( + .data_out (dbg_en_n_s), + .data_in (~dbg_en), + .clk (mclk), + .rst (por) + ); + assign dbg_en_s = ~dbg_en_n_s; + wire dbg_rst_nxt = dbg_en_n_s; +`else + assign dbg_en_s = dbg_en; + wire dbg_rst_nxt = ~dbg_en; +`endif +`else + assign dbg_en_s = 1'b0; + wire dbg_rst_nxt = 1'b0; +`endif + + +// Serial Debug Interface Clock gate +//------------------------------------------------ +`ifdef DBG_EN + `ifdef ASIC + omsp_clock_gate clock_gate_dbg_clk ( + .gclk (dbg_clk), + .clk (mclk), + .enable (dbg_en_s), + .scan_enable (scan_enable) + ); + `else + assign dbg_clk = dco_clk; + `endif +`else + assign dbg_clk = 1'b0; +`endif + + +//============================================================================= +// 7) RESET GENERATION +//============================================================================= +// +// Whenever the reset pin (reset_n) is deasserted, the internal resets of the +// openMSP430 will be released in the following order: +// 1- POR +// 2- DBG_RST (if the sdi interface is enabled, i.e. dbg_en=1) +// 3- PUC +// +// Note: releasing the DBG_RST before PUC is particularly important in order +// to allow the sdi interface to halt the cpu immediately after a PUC. +// + +// Generate synchronized POR to MCLK domain +//------------------------------------------ + +// Asynchronous reset source +assign por_a = !reset_n; +wire por_noscan; + +// Reset Synchronizer +omsp_sync_reset sync_reset_por ( + .rst_s (por_noscan), + .clk (nodiv_mclk), + .rst_a (por_a) +); + +// Scan Reset Mux +`ifdef ASIC +omsp_scan_mux scan_mux_por ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (por_noscan), + .data_out (por) +); +`else + assign por = por_noscan; +`endif + +// Generate synchronized reset for the SDI +//------------------------------------------ +`ifdef DBG_EN + +// Reset Generation +reg dbg_rst_noscan; +always @ (posedge mclk or posedge por) + if (por) dbg_rst_noscan <= 1'b1; + else dbg_rst_noscan <= dbg_rst_nxt; + + // Scan Reset Mux + `ifdef ASIC + omsp_scan_mux scan_mux_dbg_rst ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (dbg_rst_noscan), + .data_out (dbg_rst) + ); + `else + assign dbg_rst = dbg_rst_noscan; + `endif + +`else + wire dbg_rst_noscan = 1'b1; + assign dbg_rst = 1'b1; +`endif + + +// Generate main system reset (PUC_RST) +//-------------------------------------- +wire puc_noscan_n; +wire puc_a_scan; + +// Asynchronous PUC reset +wire puc_a = por | wdt_reset; + +// Synchronous PUC reset +wire puc_s = dbg_cpu_reset | // With the debug interface command + + (dbg_en_s & dbg_rst_noscan & ~puc_noscan_n); // Sequencing making sure PUC is released + // after DBG_RST if the debug interface is + // enabled at power-on-reset time +// Scan Reset Mux +`ifdef ASIC +omsp_scan_mux scan_mux_puc_rst_a ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (puc_a), + .data_out (puc_a_scan) +); +`else + assign puc_a_scan = puc_a; +`endif + +// Reset Synchronizer +// (required because of the asynchronous watchdog reset) +omsp_sync_cell sync_cell_puc ( + .data_out (puc_noscan_n), + .data_in (~puc_s), + .clk (mclk), + .rst (puc_a_scan) +); + +// Scan Reset Mux +`ifdef ASIC +omsp_scan_mux scan_mux_puc_rst ( + .scan_mode (scan_mode), + .data_in_scan (por_a), + .data_in_func (~puc_noscan_n), + .data_out (puc_rst) +); +`else + assign puc_rst = ~puc_noscan_n; +`endif + +// PUC pending set the serial debug interface +assign puc_pnd_set = ~puc_noscan_n; + + +endmodule // omsp_clock_module + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_clock_mux.v b/tests/openmsp430/rtl/omsp_clock_mux.v new file mode 100644 index 00000000..5f8406ad --- /dev/null +++ b/tests/openmsp430/rtl/omsp_clock_mux.v @@ -0,0 +1,192 @@ +//---------------------------------------------------------------------------- +// 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_clock_mux.v +// +// *Module Description: +// Standard clock mux for the openMSP430 +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_clock_mux ( + +// OUTPUTs + clk_out, // Clock output + +// INPUTs + clk_in0, // Clock input 0 + clk_in1, // Clock input 1 + reset, // Reset + scan_mode, // Scan mode (clk_in0 is selected in scan mode) + select // Clock selection +); + +// OUTPUTs +//========= +output clk_out; // Clock output + +// INPUTs +//========= +input clk_in0; // Clock input 0 +input clk_in1; // Clock input 1 +input reset; // Reset +input scan_mode; // Scan mode (clk_in0 is selected in scan mode) +input select; // Clock selection + + +//===========================================================================================================================// +// 1) CLOCK MUX // +//===========================================================================================================================// +// // +// The following (glitch free) clock mux is implemented as following: // +// // +// // +// // +// // +// +-----. +--------+ +--------+ // +// select >>----+-------------O| \ | | | | +-----. // +// | | |---| D Q |---| D Q |--+-------| \ // +// | +-------O| / | | | | | | |O-+ // +// | | +-----' | | | | | +--O| / | // +// | | | /\ | | /\ | | | +-----' | // +// | | +--+--+--+ +--+--+--+ | | | // +// | | O | | | | // +// | | | | | | | +-----. // +// clk_in0 >>----------------------------------+------------+-----------+ +--| \ // +// | | | | |----<< clk_out // +// | | +---------------------------------------+ +--| / // +// | | | | +-----' // +// | +---------------------------------------------+ | // +// | | | | // +// | | +-----. +--------+ +--------+ | | // +// | +-O| \ | | | | | +-----. | // +// | | |---| D Q |---| D Q |--+-------| \ | // +// +--------------| / | | | | | |O-+ // +// +-----' | | | | +--O| / // +// | /\ | | /\ | | +-----' // +// +--+--+--+ +--+--+--+ | // +// O | | // +// | | | // +// clk_in1 >>----------------------------------+------------+-----------+ // +// // +// // +//===========================================================================================================================// + +//----------------------------------------------------------------------------- +// Wire declarations +//----------------------------------------------------------------------------- + +wire in0_select; +reg in0_select_s; +reg in0_select_ss; +wire in0_enable; + +wire in1_select; +reg in1_select_s; +reg in1_select_ss; +wire in1_enable; + +wire clk_in0_inv; +wire clk_in1_inv; +wire gated_clk_in0; +wire gated_clk_in1; + + +//----------------------------------------------------------------------------- +// CLK_IN0 Selection +//----------------------------------------------------------------------------- + +assign in0_select = ~select & ~in1_select_ss; + +always @ (posedge clk_in0_inv or posedge reset) + if (reset) in0_select_s <= 1'b1; + else in0_select_s <= in0_select; + +always @ (posedge clk_in0 or posedge reset) + if (reset) in0_select_ss <= 1'b1; + else in0_select_ss <= in0_select_s; + +assign in0_enable = in0_select_ss | scan_mode; + + +//----------------------------------------------------------------------------- +// CLK_IN1 Selection +//----------------------------------------------------------------------------- + +assign in1_select = select & ~in0_select_ss; + +always @ (posedge clk_in1_inv or posedge reset) + if (reset) in1_select_s <= 1'b0; + else in1_select_s <= in1_select; + +always @ (posedge clk_in1 or posedge reset) + if (reset) in1_select_ss <= 1'b0; + else in1_select_ss <= in1_select_s; + +assign in1_enable = in1_select_ss & ~scan_mode; + + +//----------------------------------------------------------------------------- +// Clock MUX +//----------------------------------------------------------------------------- +// +// IMPORTANT NOTE: +// Because the clock network is a critical part of the design, +// the following combinatorial logic should be replaced with +// direct instanciation of standard cells from target library. +// Don't forget the "dont_touch" attribute to make sure +// synthesis won't mess it up. +// + +// Replace with standard cell INVERTER +assign clk_in0_inv = ~clk_in0; +assign clk_in1_inv = ~clk_in1; + + +// Replace with standard cell NAND2 +assign gated_clk_in0 = ~(clk_in0_inv & in0_enable); +assign gated_clk_in1 = ~(clk_in1_inv & in1_enable); + + +// Replace with standard cell AND2 +assign clk_out = (gated_clk_in0 & gated_clk_in1); + + + +endmodule // omsp_clock_gate + + + diff --git a/tests/openmsp430/rtl/omsp_dbg.v b/tests/openmsp430/rtl/omsp_dbg.v new file mode 100644 index 00000000..97e9ede4 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_dbg.v @@ -0,0 +1,827 @@ +//---------------------------------------------------------------------------- +// 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_dbg.v +// +// *Module Description: +// Debug interface +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 149 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2012-07-19 22:21:12 +0200 (Thu, 19 Jul 2012) $ +//---------------------------------------------------------------------------- +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_defines.v" +`endif + +module omsp_dbg ( + +// OUTPUTs + dbg_freeze, // Freeze peripherals + dbg_halt_cmd, // Halt CPU command + dbg_mem_addr, // Debug address for rd/wr access + dbg_mem_dout, // Debug unit data output + dbg_mem_en, // Debug unit memory enable + dbg_mem_wr, // Debug unit memory write + dbg_reg_wr, // Debug unit CPU register write + dbg_cpu_reset, // Reset CPU from debug interface + dbg_uart_txd, // Debug interface: UART TXD + +// INPUTs + cpu_en_s, // Enable CPU code execution (synchronous) + cpu_id, // CPU ID + dbg_clk, // Debug unit clock + dbg_en_s, // Debug interface enable (synchronous) + dbg_halt_st, // Halt/Run status from CPU + dbg_mem_din, // Debug unit Memory data input + dbg_reg_din, // Debug unit CPU register data input + dbg_rst, // Debug unit reset + dbg_uart_rxd, // Debug interface: UART RXD (asynchronous) + decode_noirq, // Frontend decode instruction + eu_mab, // Execution-Unit Memory address bus + eu_mb_en, // Execution-Unit Memory bus enable + eu_mb_wr, // Execution-Unit Memory bus write transfer + eu_mdb_in, // Memory data bus input + eu_mdb_out, // Memory data bus output + exec_done, // Execution completed + fe_mb_en, // Frontend Memory bus enable + fe_mdb_in, // Frontend Memory data bus input + pc, // Program counter + puc_pnd_set // PUC pending set for the serial debug interface +); + +// OUTPUTs +//========= +output dbg_freeze; // Freeze peripherals +output dbg_halt_cmd; // Halt CPU command +output [15:0] dbg_mem_addr; // Debug address for rd/wr access +output [15:0] dbg_mem_dout; // Debug unit data output +output dbg_mem_en; // Debug unit memory enable +output [1:0] dbg_mem_wr; // Debug unit memory write +output dbg_reg_wr; // Debug unit CPU register write +output dbg_cpu_reset; // Reset CPU from debug interface +output dbg_uart_txd; // Debug interface: UART TXD + +// INPUTs +//========= +input cpu_en_s; // Enable CPU code execution (synchronous) +input [31:0] cpu_id; // CPU ID +input dbg_clk; // Debug unit clock +input dbg_en_s; // Debug interface enable (synchronous) +input dbg_halt_st; // Halt/Run status from CPU +input [15:0] dbg_mem_din; // Debug unit Memory data input +input [15:0] dbg_reg_din; // Debug unit CPU register data input +input dbg_rst; // Debug unit reset +input dbg_uart_rxd; // Debug interface: UART RXD (asynchronous) +input decode_noirq; // Frontend decode instruction +input [15:0] eu_mab; // Execution-Unit Memory address bus +input eu_mb_en; // Execution-Unit Memory bus enable +input [1:0] eu_mb_wr; // Execution-Unit Memory bus write transfer +input [15:0] eu_mdb_in; // Memory data bus input +input [15:0] eu_mdb_out; // Memory data bus output +input exec_done; // Execution completed +input fe_mb_en; // Frontend Memory bus enable +input [15:0] fe_mdb_in; // Frontend Memory data bus input +input [15:0] pc; // Program counter +input puc_pnd_set; // PUC pending set for the serial debug interface + + +//============================================================================= +// 1) WIRE & PARAMETER DECLARATION +//============================================================================= + +// Diverse wires and registers +wire [5:0] dbg_addr; +wire [15:0] dbg_din; +wire dbg_wr; +reg mem_burst; +wire dbg_reg_rd; +wire dbg_mem_rd; +reg dbg_mem_rd_dly; +wire dbg_swbrk; +wire dbg_rd; +reg dbg_rd_rdy; +wire mem_burst_rd; +wire mem_burst_wr; +wire brk0_halt; +wire brk0_pnd; +wire [15:0] brk0_dout; +wire brk1_halt; +wire brk1_pnd; +wire [15:0] brk1_dout; +wire brk2_halt; +wire brk2_pnd; +wire [15:0] brk2_dout; +wire brk3_halt; +wire brk3_pnd; +wire [15:0] brk3_dout; + +// Number of registers +parameter NR_REG = 24; + +// Register addresses +parameter CPU_ID_LO = 6'h00; +parameter CPU_ID_HI = 6'h01; +parameter CPU_CTL = 6'h02; +parameter CPU_STAT = 6'h03; +parameter MEM_CTL = 6'h04; +parameter MEM_ADDR = 6'h05; +parameter MEM_DATA = 6'h06; +parameter MEM_CNT = 6'h07; +`ifdef DBG_HWBRK_0 +parameter BRK0_CTL = 6'h08; +parameter BRK0_STAT = 6'h09; +parameter BRK0_ADDR0 = 6'h0A; +parameter BRK0_ADDR1 = 6'h0B; +`endif +`ifdef DBG_HWBRK_1 +parameter BRK1_CTL = 6'h0C; +parameter BRK1_STAT = 6'h0D; +parameter BRK1_ADDR0 = 6'h0E; +parameter BRK1_ADDR1 = 6'h0F; +`endif +`ifdef DBG_HWBRK_2 +parameter BRK2_CTL = 6'h10; +parameter BRK2_STAT = 6'h11; +parameter BRK2_ADDR0 = 6'h12; +parameter BRK2_ADDR1 = 6'h13; +`endif +`ifdef DBG_HWBRK_3 +parameter BRK3_CTL = 6'h14; +parameter BRK3_STAT = 6'h15; +parameter BRK3_ADDR0 = 6'h16; +parameter BRK3_ADDR1 = 6'h17; +`endif + +// Register one-hot decoder +parameter BASE_D = {{NR_REG-1{1'b0}}, 1'b1}; +parameter CPU_ID_LO_D = (BASE_D << CPU_ID_LO); +parameter CPU_ID_HI_D = (BASE_D << CPU_ID_HI); +parameter CPU_CTL_D = (BASE_D << CPU_CTL); +parameter CPU_STAT_D = (BASE_D << CPU_STAT); +parameter MEM_CTL_D = (BASE_D << MEM_CTL); +parameter MEM_ADDR_D = (BASE_D << MEM_ADDR); +parameter MEM_DATA_D = (BASE_D << MEM_DATA); +parameter MEM_CNT_D = (BASE_D << MEM_CNT); +`ifdef DBG_HWBRK_0 +parameter BRK0_CTL_D = (BASE_D << BRK0_CTL); +parameter BRK0_STAT_D = (BASE_D << BRK0_STAT); +parameter BRK0_ADDR0_D = (BASE_D << BRK0_ADDR0); +parameter BRK0_ADDR1_D = (BASE_D << BRK0_ADDR1); +`endif +`ifdef DBG_HWBRK_1 +parameter BRK1_CTL_D = (BASE_D << BRK1_CTL); +parameter BRK1_STAT_D = (BASE_D << BRK1_STAT); +parameter BRK1_ADDR0_D = (BASE_D << BRK1_ADDR0); +parameter BRK1_ADDR1_D = (BASE_D << BRK1_ADDR1); +`endif +`ifdef DBG_HWBRK_2 +parameter BRK2_CTL_D = (BASE_D << BRK2_CTL); +parameter BRK2_STAT_D = (BASE_D << BRK2_STAT); +parameter BRK2_ADDR0_D = (BASE_D << BRK2_ADDR0); +parameter BRK2_ADDR1_D = (BASE_D << BRK2_ADDR1); +`endif +`ifdef DBG_HWBRK_3 +parameter BRK3_CTL_D = (BASE_D << BRK3_CTL); +parameter BRK3_STAT_D = (BASE_D << BRK3_STAT); +parameter BRK3_ADDR0_D = (BASE_D << BRK3_ADDR0); +parameter BRK3_ADDR1_D = (BASE_D << BRK3_ADDR1); +`endif + + +//============================================================================ +// 2) REGISTER DECODER +//============================================================================ + +// Select Data register during a burst +wire [5:0] dbg_addr_in = mem_burst ? MEM_DATA : dbg_addr; + +// Register address decode +reg [NR_REG-1:0] reg_dec; +always @(dbg_addr_in) + case (dbg_addr_in) + CPU_ID_LO : reg_dec = CPU_ID_LO_D; + CPU_ID_HI : reg_dec = CPU_ID_HI_D; + CPU_CTL : reg_dec = CPU_CTL_D; + CPU_STAT : reg_dec = CPU_STAT_D; + MEM_CTL : reg_dec = MEM_CTL_D; + MEM_ADDR : reg_dec = MEM_ADDR_D; + MEM_DATA : reg_dec = MEM_DATA_D; + MEM_CNT : reg_dec = MEM_CNT_D; +`ifdef DBG_HWBRK_0 + BRK0_CTL : reg_dec = BRK0_CTL_D; + BRK0_STAT : reg_dec = BRK0_STAT_D; + BRK0_ADDR0: reg_dec = BRK0_ADDR0_D; + BRK0_ADDR1: reg_dec = BRK0_ADDR1_D; +`endif +`ifdef DBG_HWBRK_1 + BRK1_CTL : reg_dec = BRK1_CTL_D; + BRK1_STAT : reg_dec = BRK1_STAT_D; + BRK1_ADDR0: reg_dec = BRK1_ADDR0_D; + BRK1_ADDR1: reg_dec = BRK1_ADDR1_D; +`endif +`ifdef DBG_HWBRK_2 + BRK2_CTL : reg_dec = BRK2_CTL_D; + BRK2_STAT : reg_dec = BRK2_STAT_D; + BRK2_ADDR0: reg_dec = BRK2_ADDR0_D; + BRK2_ADDR1: reg_dec = BRK2_ADDR1_D; +`endif +`ifdef DBG_HWBRK_3 + BRK3_CTL : reg_dec = BRK3_CTL_D; + BRK3_STAT : reg_dec = BRK3_STAT_D; + BRK3_ADDR0: reg_dec = BRK3_ADDR0_D; + BRK3_ADDR1: reg_dec = BRK3_ADDR1_D; +`endif + // pragma coverage off + default: reg_dec = {NR_REG{1'b0}}; + // pragma coverage on + endcase + +// Read/Write probes +wire reg_write = dbg_wr; +wire reg_read = 1'b1; + +// Read/Write vectors +wire [NR_REG-1:0] reg_wr = reg_dec & {NR_REG{reg_write}}; +wire [NR_REG-1:0] reg_rd = reg_dec & {NR_REG{reg_read}}; + + +//============================================================================= +// 3) REGISTER: CORE INTERFACE +//============================================================================= + +// CPU_ID Register +//----------------- +// ------------------------------------------------------------------- +// CPU_ID_LO: | 15 14 13 12 11 10 9 | 8 7 6 5 4 | 3 | 2 1 0 | +// |----------------------------+-----------------+------+-------------| +// | PER_SPACE | USER_VERSION | ASIC | CPU_VERSION | +// -------------------------------------------------------------------- +// CPU_ID_HI: | 15 14 13 12 11 10 | 9 8 7 6 5 4 3 2 1 | 0 | +// |----------------------------+-------------------------------+------| +// | PMEM_SIZE | DMEM_SIZE | MPY | +// ------------------------------------------------------------------- + +// This register is assigned in the SFR module + + +// CPU_CTL Register +//----------------------------------------------------------------------------- +// 7 6 5 4 3 2 1 0 +// Reserved CPU_RST RST_BRK_EN FRZ_BRK_EN SW_BRK_EN ISTEP RUN HALT +//----------------------------------------------------------------------------- +reg [6:3] cpu_ctl; + +wire cpu_ctl_wr = reg_wr[CPU_CTL]; + +always @ (posedge dbg_clk or posedge dbg_rst) +`ifdef DBG_RST_BRK_EN + if (dbg_rst) cpu_ctl <= 4'h6; +`else + if (dbg_rst) cpu_ctl <= 4'h2; +`endif + else if (cpu_ctl_wr) cpu_ctl <= dbg_din[6:3]; + +wire [7:0] cpu_ctl_full = {1'b0, cpu_ctl, 3'b000}; + +wire halt_cpu = cpu_ctl_wr & dbg_din[`HALT] & ~dbg_halt_st; +wire run_cpu = cpu_ctl_wr & dbg_din[`RUN] & dbg_halt_st; +wire istep = cpu_ctl_wr & dbg_din[`ISTEP] & dbg_halt_st; + + +// CPU_STAT Register +//------------------------------------------------------------------------------------ +// 7 6 5 4 3 2 1 0 +// HWBRK3_PND HWBRK2_PND HWBRK1_PND HWBRK0_PND SWBRK_PND PUC_PND Res. HALT_RUN +//------------------------------------------------------------------------------------ +reg [3:2] cpu_stat; + +wire cpu_stat_wr = reg_wr[CPU_STAT]; +wire [3:2] cpu_stat_set = {dbg_swbrk, puc_pnd_set}; +wire [3:2] cpu_stat_clr = ~dbg_din[3:2]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) cpu_stat <= 2'b00; + else if (cpu_stat_wr) cpu_stat <= ((cpu_stat & cpu_stat_clr) | cpu_stat_set); + else cpu_stat <= (cpu_stat | cpu_stat_set); + +wire [7:0] cpu_stat_full = {brk3_pnd, brk2_pnd, brk1_pnd, brk0_pnd, + cpu_stat, 1'b0, dbg_halt_st}; + + +//============================================================================= +// 4) REGISTER: MEMORY INTERFACE +//============================================================================= + +// MEM_CTL Register +//----------------------------------------------------------------------------- +// 7 6 5 4 3 2 1 0 +// Reserved B/W MEM/REG RD/WR START +// +// START : - 0 : Do nothing. +// - 1 : Initiate memory transfer. +// +// RD/WR : - 0 : Read access. +// - 1 : Write access. +// +// MEM/REG: - 0 : Memory access. +// - 1 : CPU Register access. +// +// B/W : - 0 : 16 bit access. +// - 1 : 8 bit access (not valid for CPU Registers). +// +//----------------------------------------------------------------------------- +reg [3:1] mem_ctl; + +wire mem_ctl_wr = reg_wr[MEM_CTL]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_ctl <= 3'h0; + else if (mem_ctl_wr) mem_ctl <= dbg_din[3:1]; + +wire [7:0] mem_ctl_full = {4'b0000, mem_ctl, 1'b0}; + +reg mem_start; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_start <= 1'b0; + else mem_start <= mem_ctl_wr & dbg_din[0]; + +wire mem_bw = mem_ctl[3]; + +// MEM_DATA Register +//------------------ +reg [15:0] mem_data; +reg [15:0] mem_addr; +wire mem_access; + +wire mem_data_wr = reg_wr[MEM_DATA]; + +wire [15:0] dbg_mem_din_bw = ~mem_bw ? dbg_mem_din : + mem_addr[0] ? {8'h00, dbg_mem_din[15:8]} : + {8'h00, dbg_mem_din[7:0]}; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_data <= 16'h0000; + else if (mem_data_wr) mem_data <= dbg_din; + else if (dbg_reg_rd) mem_data <= dbg_reg_din; + else if (dbg_mem_rd_dly) mem_data <= dbg_mem_din_bw; + + +// MEM_ADDR Register +//------------------ +reg [15:0] mem_cnt; + +wire mem_addr_wr = reg_wr[MEM_ADDR]; +wire dbg_mem_acc = (|dbg_mem_wr | (dbg_rd_rdy & ~mem_ctl[2])); +wire dbg_reg_acc = ( dbg_reg_wr | (dbg_rd_rdy & mem_ctl[2])); + +wire [15:0] mem_addr_inc = (mem_cnt==16'h0000) ? 16'h0000 : + (dbg_mem_acc & ~mem_bw) ? 16'h0002 : + (dbg_mem_acc | dbg_reg_acc) ? 16'h0001 : 16'h0000; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_addr <= 16'h0000; + else if (mem_addr_wr) mem_addr <= dbg_din; + else mem_addr <= mem_addr + mem_addr_inc; + +// MEM_CNT Register +//------------------ + +wire mem_cnt_wr = reg_wr[MEM_CNT]; + +wire [15:0] mem_cnt_dec = (mem_cnt==16'h0000) ? 16'h0000 : + (mem_burst & (dbg_mem_acc | dbg_reg_acc)) ? 16'hffff : 16'h0000; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_cnt <= 16'h0000; + else if (mem_cnt_wr) mem_cnt <= dbg_din; + else mem_cnt <= mem_cnt + mem_cnt_dec; + + +//============================================================================= +// 5) BREAKPOINTS / WATCHPOINTS +//============================================================================= + +`ifdef DBG_HWBRK_0 +// Hardware Breakpoint/Watchpoint Register read select +wire [3:0] brk0_reg_rd = {reg_rd[BRK0_ADDR1], + reg_rd[BRK0_ADDR0], + reg_rd[BRK0_STAT], + reg_rd[BRK0_CTL]}; + +// Hardware Breakpoint/Watchpoint Register write select +wire [3:0] brk0_reg_wr = {reg_wr[BRK0_ADDR1], + reg_wr[BRK0_ADDR0], + reg_wr[BRK0_STAT], + reg_wr[BRK0_CTL]}; + +omsp_dbg_hwbrk dbg_hwbr_0 ( + +// OUTPUTs + .brk_halt (brk0_halt), // Hardware breakpoint command + .brk_pnd (brk0_pnd), // Hardware break/watch-point pending + .brk_dout (brk0_dout), // Hardware break/watch-point register data input + +// INPUTs + .brk_reg_rd (brk0_reg_rd), // Hardware break/watch-point register read select + .brk_reg_wr (brk0_reg_wr), // Hardware break/watch-point register write select + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_din (dbg_din), // Debug register data input + .dbg_rst (dbg_rst), // Debug unit reset + .eu_mab (eu_mab), // Execution-Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution-Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution-Unit Memory bus write transfer + .eu_mdb_in (eu_mdb_in), // Memory data bus input + .eu_mdb_out (eu_mdb_out), // Memory data bus output + .exec_done (exec_done), // Execution completed + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .pc (pc) // Program counter +); + +`else +assign brk0_halt = 1'b0; +assign brk0_pnd = 1'b0; +assign brk0_dout = 16'h0000; +`endif + +`ifdef DBG_HWBRK_1 +// Hardware Breakpoint/Watchpoint Register read select +wire [3:0] brk1_reg_rd = {reg_rd[BRK1_ADDR1], + reg_rd[BRK1_ADDR0], + reg_rd[BRK1_STAT], + reg_rd[BRK1_CTL]}; + +// Hardware Breakpoint/Watchpoint Register write select +wire [3:0] brk1_reg_wr = {reg_wr[BRK1_ADDR1], + reg_wr[BRK1_ADDR0], + reg_wr[BRK1_STAT], + reg_wr[BRK1_CTL]}; + +omsp_dbg_hwbrk dbg_hwbr_1 ( + +// OUTPUTs + .brk_halt (brk1_halt), // Hardware breakpoint command + .brk_pnd (brk1_pnd), // Hardware break/watch-point pending + .brk_dout (brk1_dout), // Hardware break/watch-point register data input + +// INPUTs + .brk_reg_rd (brk1_reg_rd), // Hardware break/watch-point register read select + .brk_reg_wr (brk1_reg_wr), // Hardware break/watch-point register write select + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_din (dbg_din), // Debug register data input + .dbg_rst (dbg_rst), // Debug unit reset + .eu_mab (eu_mab), // Execution-Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution-Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution-Unit Memory bus write transfer + .eu_mdb_in (eu_mdb_in), // Memory data bus input + .eu_mdb_out (eu_mdb_out), // Memory data bus output + .exec_done (exec_done), // Execution completed + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .pc (pc) // Program counter +); + +`else +assign brk1_halt = 1'b0; +assign brk1_pnd = 1'b0; +assign brk1_dout = 16'h0000; +`endif + + `ifdef DBG_HWBRK_2 +// Hardware Breakpoint/Watchpoint Register read select +wire [3:0] brk2_reg_rd = {reg_rd[BRK2_ADDR1], + reg_rd[BRK2_ADDR0], + reg_rd[BRK2_STAT], + reg_rd[BRK2_CTL]}; + +// Hardware Breakpoint/Watchpoint Register write select +wire [3:0] brk2_reg_wr = {reg_wr[BRK2_ADDR1], + reg_wr[BRK2_ADDR0], + reg_wr[BRK2_STAT], + reg_wr[BRK2_CTL]}; + +omsp_dbg_hwbrk dbg_hwbr_2 ( + +// OUTPUTs + .brk_halt (brk2_halt), // Hardware breakpoint command + .brk_pnd (brk2_pnd), // Hardware break/watch-point pending + .brk_dout (brk2_dout), // Hardware break/watch-point register data input + +// INPUTs + .brk_reg_rd (brk2_reg_rd), // Hardware break/watch-point register read select + .brk_reg_wr (brk2_reg_wr), // Hardware break/watch-point register write select + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_din (dbg_din), // Debug register data input + .dbg_rst (dbg_rst), // Debug unit reset + .eu_mab (eu_mab), // Execution-Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution-Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution-Unit Memory bus write transfer + .eu_mdb_in (eu_mdb_in), // Memory data bus input + .eu_mdb_out (eu_mdb_out), // Memory data bus output + .exec_done (exec_done), // Execution completed + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .pc (pc) // Program counter +); + +`else +assign brk2_halt = 1'b0; +assign brk2_pnd = 1'b0; +assign brk2_dout = 16'h0000; +`endif + +`ifdef DBG_HWBRK_3 +// Hardware Breakpoint/Watchpoint Register read select +wire [3:0] brk3_reg_rd = {reg_rd[BRK3_ADDR1], + reg_rd[BRK3_ADDR0], + reg_rd[BRK3_STAT], + reg_rd[BRK3_CTL]}; + +// Hardware Breakpoint/Watchpoint Register write select +wire [3:0] brk3_reg_wr = {reg_wr[BRK3_ADDR1], + reg_wr[BRK3_ADDR0], + reg_wr[BRK3_STAT], + reg_wr[BRK3_CTL]}; + +omsp_dbg_hwbrk dbg_hwbr_3 ( + +// OUTPUTs + .brk_halt (brk3_halt), // Hardware breakpoint command + .brk_pnd (brk3_pnd), // Hardware break/watch-point pending + .brk_dout (brk3_dout), // Hardware break/watch-point register data input + +// INPUTs + .brk_reg_rd (brk3_reg_rd), // Hardware break/watch-point register read select + .brk_reg_wr (brk3_reg_wr), // Hardware break/watch-point register write select + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_din (dbg_din), // Debug register data input + .dbg_rst (dbg_rst), // Debug unit reset + .eu_mab (eu_mab), // Execution-Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution-Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution-Unit Memory bus write transfer + .eu_mdb_in (eu_mdb_in), // Memory data bus input + .eu_mdb_out (eu_mdb_out), // Memory data bus output + .exec_done (exec_done), // Execution completed + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .pc (pc) // Program counter +); + +`else +assign brk3_halt = 1'b0; +assign brk3_pnd = 1'b0; +assign brk3_dout = 16'h0000; +`endif + + +//============================================================================ +// 6) DATA OUTPUT GENERATION +//============================================================================ + +wire [15:0] cpu_id_lo_rd = cpu_id[15:0] & {16{reg_rd[CPU_ID_LO]}}; +wire [15:0] cpu_id_hi_rd = cpu_id[31:16] & {16{reg_rd[CPU_ID_HI]}}; +wire [15:0] cpu_ctl_rd = {8'h00, cpu_ctl_full} & {16{reg_rd[CPU_CTL]}}; +wire [15:0] cpu_stat_rd = {8'h00, cpu_stat_full} & {16{reg_rd[CPU_STAT]}}; +wire [15:0] mem_ctl_rd = {8'h00, mem_ctl_full} & {16{reg_rd[MEM_CTL]}}; +wire [15:0] mem_data_rd = mem_data & {16{reg_rd[MEM_DATA]}}; +wire [15:0] mem_addr_rd = mem_addr & {16{reg_rd[MEM_ADDR]}}; +wire [15:0] mem_cnt_rd = mem_cnt & {16{reg_rd[MEM_CNT]}}; + +wire [15:0] dbg_dout = cpu_id_lo_rd | + cpu_id_hi_rd | + cpu_ctl_rd | + cpu_stat_rd | + mem_ctl_rd | + mem_data_rd | + mem_addr_rd | + mem_cnt_rd | + brk0_dout | + brk1_dout | + brk2_dout | + brk3_dout; + +// Tell UART/JTAG interface that the data is ready to be read +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) dbg_rd_rdy <= 1'b0; + else if (mem_burst | mem_burst_rd) dbg_rd_rdy <= (dbg_reg_rd | dbg_mem_rd_dly); + else dbg_rd_rdy <= dbg_rd; + + +//============================================================================ +// 7) CPU CONTROL +//============================================================================ + +// Reset CPU +//-------------------------- +wire dbg_cpu_reset = cpu_ctl[`CPU_RST]; + + +// Break after reset +//-------------------------- +wire halt_rst = cpu_ctl[`RST_BRK_EN] & dbg_en_s & puc_pnd_set; + + +// Freeze peripherals +//-------------------------- +wire dbg_freeze = dbg_halt_st & (cpu_ctl[`FRZ_BRK_EN] | ~cpu_en_s); + + +// Software break +//-------------------------- +assign dbg_swbrk = (fe_mdb_in==`DBG_SWBRK_OP) & decode_noirq & cpu_ctl[`SW_BRK_EN]; + + +// Single step +//-------------------------- +reg [1:0] inc_step; +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) inc_step <= 2'b00; + else if (istep) inc_step <= 2'b11; + else inc_step <= {inc_step[0], 1'b0}; + + +// Run / Halt +//-------------------------- +reg halt_flag; + +wire mem_halt_cpu; +wire mem_run_cpu; + +wire halt_flag_clr = run_cpu | mem_run_cpu; +wire halt_flag_set = halt_cpu | halt_rst | dbg_swbrk | mem_halt_cpu | + brk0_halt | brk1_halt | brk2_halt | brk3_halt; + +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) halt_flag <= 1'b0; + else if (halt_flag_clr) halt_flag <= 1'b0; + else if (halt_flag_set) halt_flag <= 1'b1; + +wire dbg_halt_cmd = (halt_flag | halt_flag_set) & ~inc_step[1]; + + +//============================================================================ +// 8) MEMORY CONTROL +//============================================================================ + +// Control Memory bursts +//------------------------------ + +wire mem_burst_start = (mem_start & |mem_cnt); +wire mem_burst_end = ((dbg_wr | dbg_rd_rdy) & ~|mem_cnt); + +// Detect when burst is on going +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_burst <= 1'b0; + else if (mem_burst_start) mem_burst <= 1'b1; + else if (mem_burst_end) mem_burst <= 1'b0; + +// Control signals for UART/JTAG interface +assign mem_burst_rd = (mem_burst_start & ~mem_ctl[1]); +assign mem_burst_wr = (mem_burst_start & mem_ctl[1]); + +// Trigger CPU Register or memory access during a burst +reg mem_startb; +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_startb <= 1'b0; + else mem_startb <= (mem_burst & (dbg_wr | dbg_rd)) | mem_burst_rd; + +// Combine single and burst memory start of sequence +wire mem_seq_start = ((mem_start & ~|mem_cnt) | mem_startb); + + +// Memory access state machine +//------------------------------ +reg [1:0] mem_state; +reg [1:0] mem_state_nxt; + +// State machine definition +parameter M_IDLE = 2'h0; +parameter M_SET_BRK = 2'h1; +parameter M_ACCESS_BRK = 2'h2; +parameter M_ACCESS = 2'h3; + +// State transition +always @(mem_state or mem_seq_start or dbg_halt_st) + case (mem_state) + M_IDLE : mem_state_nxt = ~mem_seq_start ? M_IDLE : + dbg_halt_st ? M_ACCESS : M_SET_BRK; + M_SET_BRK : mem_state_nxt = dbg_halt_st ? M_ACCESS_BRK : M_SET_BRK; + M_ACCESS_BRK : mem_state_nxt = M_IDLE; + M_ACCESS : mem_state_nxt = M_IDLE; + // pragma coverage off + default : mem_state_nxt = M_IDLE; + // pragma coverage on + endcase + +// State machine +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) mem_state <= M_IDLE; + else mem_state <= mem_state_nxt; + +// Utility signals +assign mem_halt_cpu = (mem_state==M_IDLE) & (mem_state_nxt==M_SET_BRK); +assign mem_run_cpu = (mem_state==M_ACCESS_BRK) & (mem_state_nxt==M_IDLE); +assign mem_access = (mem_state==M_ACCESS) | (mem_state==M_ACCESS_BRK); + + +// Interface to CPU Registers and Memory bacbkone +//------------------------------------------------ +assign dbg_mem_addr = mem_addr; +assign dbg_mem_dout = ~mem_bw ? mem_data : + mem_addr[0] ? {mem_data[7:0], 8'h00} : + {8'h00, mem_data[7:0]}; + +assign dbg_reg_wr = mem_access & mem_ctl[1] & mem_ctl[2]; +assign dbg_reg_rd = mem_access & ~mem_ctl[1] & mem_ctl[2]; + +assign dbg_mem_en = mem_access & ~mem_ctl[2]; +assign dbg_mem_rd = dbg_mem_en & ~mem_ctl[1]; + +wire [1:0] dbg_mem_wr_msk = ~mem_bw ? 2'b11 : + mem_addr[0] ? 2'b10 : 2'b01; +assign dbg_mem_wr = {2{dbg_mem_en & mem_ctl[1]}} & dbg_mem_wr_msk; + + +// It takes one additional cycle to read from Memory as from registers +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) dbg_mem_rd_dly <= 1'b0; + else dbg_mem_rd_dly <= dbg_mem_rd; + + +//============================================================================= +// 9) UART COMMUNICATION +//============================================================================= +`ifdef DBG_UART +omsp_dbg_uart dbg_uart_0 ( + +// OUTPUTs + .dbg_addr (dbg_addr), // Debug register address + .dbg_din (dbg_din), // Debug register data input + .dbg_rd (dbg_rd), // Debug register data read + .dbg_uart_txd (dbg_uart_txd), // Debug interface: UART TXD + .dbg_wr (dbg_wr), // Debug register data write + +// INPUTs + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_dout (dbg_dout), // Debug register data output + .dbg_rd_rdy (dbg_rd_rdy), // Debug register data is ready for read + .dbg_rst (dbg_rst), // Debug unit reset + .dbg_uart_rxd (dbg_uart_rxd), // Debug interface: UART RXD + .mem_burst (mem_burst), // Burst on going + .mem_burst_end(mem_burst_end), // End TX/RX burst + .mem_burst_rd (mem_burst_rd), // Start TX burst + .mem_burst_wr (mem_burst_wr), // Start RX burst + .mem_bw (mem_bw) // Burst byte width +); + +`else +assign dbg_addr = 6'h00; +assign dbg_din = 16'h0000; +assign dbg_rd = 1'b0; +assign dbg_uart_txd = 1'b0; +assign dbg_wr = 1'b0; +`endif + + +//============================================================================= +// 10) JTAG COMMUNICATION +//============================================================================= +`ifdef DBG_JTAG +JTAG INTERFACE IS NOT SUPPORTED YET +`else +`endif + +endmodule // dbg + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_dbg_hwbrk.v b/tests/openmsp430/rtl/omsp_dbg_hwbrk.v new file mode 100644 index 00000000..6f639aee --- /dev/null +++ b/tests/openmsp430/rtl/omsp_dbg_hwbrk.v @@ -0,0 +1,282 @@ +//---------------------------------------------------------------------------- +// 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_dbg_hwbrk.v +// +// *Module Description: +// Hardware Breakpoint / Watchpoint module +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 117 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-06-23 21:30:51 +0200 (Thu, 23 Jun 2011) $ +//---------------------------------------------------------------------------- +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_defines.v" +`endif + +module omsp_dbg_hwbrk ( + +// OUTPUTs + brk_halt, // Hardware breakpoint command + brk_pnd, // Hardware break/watch-point pending + brk_dout, // Hardware break/watch-point register data input + +// INPUTs + brk_reg_rd, // Hardware break/watch-point register read select + brk_reg_wr, // Hardware break/watch-point register write select + dbg_clk, // Debug unit clock + dbg_din, // Debug register data input + dbg_rst, // Debug unit reset + eu_mab, // Execution-Unit Memory address bus + eu_mb_en, // Execution-Unit Memory bus enable + eu_mb_wr, // Execution-Unit Memory bus write transfer + eu_mdb_in, // Memory data bus input + eu_mdb_out, // Memory data bus output + exec_done, // Execution completed + fe_mb_en, // Frontend Memory bus enable + pc // Program counter +); + +// OUTPUTs +//========= +output brk_halt; // Hardware breakpoint command +output brk_pnd; // Hardware break/watch-point pending +output [15:0] brk_dout; // Hardware break/watch-point register data input + +// INPUTs +//========= +input [3:0] brk_reg_rd; // Hardware break/watch-point register read select +input [3:0] brk_reg_wr; // Hardware break/watch-point register write select +input dbg_clk; // Debug unit clock +input [15:0] dbg_din; // Debug register data input +input dbg_rst; // Debug unit reset +input [15:0] eu_mab; // Execution-Unit Memory address bus +input eu_mb_en; // Execution-Unit Memory bus enable +input [1:0] eu_mb_wr; // Execution-Unit Memory bus write transfer +input [15:0] eu_mdb_in; // Memory data bus input +input [15:0] eu_mdb_out; // Memory data bus output +input exec_done; // Execution completed +input fe_mb_en; // Frontend Memory bus enable +input [15:0] pc; // Program counter + + +//============================================================================= +// 1) WIRE & PARAMETER DECLARATION +//============================================================================= + +wire range_wr_set; +wire range_rd_set; +wire addr1_wr_set; +wire addr1_rd_set; +wire addr0_wr_set; +wire addr0_rd_set; + + +parameter BRK_CTL = 0, + BRK_STAT = 1, + BRK_ADDR0 = 2, + BRK_ADDR1 = 3; + + +//============================================================================= +// 2) CONFIGURATION REGISTERS +//============================================================================= + +// BRK_CTL Register +//----------------------------------------------------------------------------- +// 7 6 5 4 3 2 1 0 +// Reserved RANGE_MODE INST_EN BREAK_EN ACCESS_MODE +// +// ACCESS_MODE: - 00 : Disabled +// - 01 : Detect read access +// - 10 : Detect write access +// - 11 : Detect read/write access +// NOTE: '10' & '11' modes are not supported on the instruction flow +// +// BREAK_EN: - 0 : Watchmode enable +// - 1 : Break enable +// +// INST_EN: - 0 : Checks are done on the execution unit (data flow) +// - 1 : Checks are done on the frontend (instruction flow) +// +// RANGE_MODE: - 0 : Address match on BRK_ADDR0 or BRK_ADDR1 +// - 1 : Address match on BRK_ADDR0->BRK_ADDR1 range +// +//----------------------------------------------------------------------------- +reg [4:0] brk_ctl; + +wire brk_ctl_wr = brk_reg_wr[BRK_CTL]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) brk_ctl <= 5'h00; + else if (brk_ctl_wr) brk_ctl <= {`HWBRK_RANGE & dbg_din[4], dbg_din[3:0]}; + +wire [7:0] brk_ctl_full = {3'b000, brk_ctl}; + + +// BRK_STAT Register +//----------------------------------------------------------------------------- +// 7 6 5 4 3 2 1 0 +// Reserved RANGE_WR RANGE_RD ADDR1_WR ADDR1_RD ADDR0_WR ADDR0_RD +//----------------------------------------------------------------------------- +reg [5:0] brk_stat; + +wire brk_stat_wr = brk_reg_wr[BRK_STAT]; +wire [5:0] brk_stat_set = {range_wr_set & `HWBRK_RANGE, + range_rd_set & `HWBRK_RANGE, + addr1_wr_set, addr1_rd_set, + addr0_wr_set, addr0_rd_set}; +wire [5:0] brk_stat_clr = ~dbg_din[5:0]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) brk_stat <= 6'h00; + else if (brk_stat_wr) brk_stat <= ((brk_stat & brk_stat_clr) | brk_stat_set); + else brk_stat <= (brk_stat | brk_stat_set); + +wire [7:0] brk_stat_full = {2'b00, brk_stat}; +wire brk_pnd = |brk_stat; + + +// BRK_ADDR0 Register +//----------------------------------------------------------------------------- +reg [15:0] brk_addr0; + +wire brk_addr0_wr = brk_reg_wr[BRK_ADDR0]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) brk_addr0 <= 16'h0000; + else if (brk_addr0_wr) brk_addr0 <= dbg_din; + + +// BRK_ADDR1/DATA0 Register +//----------------------------------------------------------------------------- +reg [15:0] brk_addr1; + +wire brk_addr1_wr = brk_reg_wr[BRK_ADDR1]; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) brk_addr1 <= 16'h0000; + else if (brk_addr1_wr) brk_addr1 <= dbg_din; + + +//============================================================================ +// 3) DATA OUTPUT GENERATION +//============================================================================ + +wire [15:0] brk_ctl_rd = {8'h00, brk_ctl_full} & {16{brk_reg_rd[BRK_CTL]}}; +wire [15:0] brk_stat_rd = {8'h00, brk_stat_full} & {16{brk_reg_rd[BRK_STAT]}}; +wire [15:0] brk_addr0_rd = brk_addr0 & {16{brk_reg_rd[BRK_ADDR0]}}; +wire [15:0] brk_addr1_rd = brk_addr1 & {16{brk_reg_rd[BRK_ADDR1]}}; + +wire [15:0] brk_dout = brk_ctl_rd | + brk_stat_rd | + brk_addr0_rd | + brk_addr1_rd; + + +//============================================================================ +// 4) BREAKPOINT / WATCHPOINT GENERATION +//============================================================================ + +// Comparators +//--------------------------- +// Note: here the comparison logic is instanciated several times in order +// to improve the timings, at the cost of a bit more area. + +wire equ_d_addr0 = eu_mb_en & (eu_mab==brk_addr0) & ~brk_ctl[`BRK_RANGE]; +wire equ_d_addr1 = eu_mb_en & (eu_mab==brk_addr1) & ~brk_ctl[`BRK_RANGE]; +wire equ_d_range = eu_mb_en & ((eu_mab>=brk_addr0) & (eu_mab<=brk_addr1)) & + brk_ctl[`BRK_RANGE] & `HWBRK_RANGE; + +reg fe_mb_en_buf; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) fe_mb_en_buf <= 1'b0; + else fe_mb_en_buf <= fe_mb_en; + +wire equ_i_addr0 = fe_mb_en_buf & (pc==brk_addr0) & ~brk_ctl[`BRK_RANGE]; +wire equ_i_addr1 = fe_mb_en_buf & (pc==brk_addr1) & ~brk_ctl[`BRK_RANGE]; +wire equ_i_range = fe_mb_en_buf & ((pc>=brk_addr0) & (pc<=brk_addr1)) & + brk_ctl[`BRK_RANGE] & `HWBRK_RANGE; + + +// Detect accesses +//--------------------------- + +// Detect Instruction read access +wire i_addr0_rd = equ_i_addr0 & brk_ctl[`BRK_I_EN]; +wire i_addr1_rd = equ_i_addr1 & brk_ctl[`BRK_I_EN]; +wire i_range_rd = equ_i_range & brk_ctl[`BRK_I_EN]; + +// Detect Execution-Unit write access +wire d_addr0_wr = equ_d_addr0 & ~brk_ctl[`BRK_I_EN] & |eu_mb_wr; +wire d_addr1_wr = equ_d_addr1 & ~brk_ctl[`BRK_I_EN] & |eu_mb_wr; +wire d_range_wr = equ_d_range & ~brk_ctl[`BRK_I_EN] & |eu_mb_wr; + +// Detect DATA read access +// Whenever an "ADD r9. &0x200" instruction is executed, &0x200 will be read +// before being written back. In that case, the read flag should not be set. +// In general, We should here make sure no write access occures during the +// same instruction cycle before setting the read flag. +reg [2:0] d_rd_trig; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) d_rd_trig <= 3'h0; + else if (exec_done) d_rd_trig <= 3'h0; + else d_rd_trig <= {equ_d_range & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr, + equ_d_addr1 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr, + equ_d_addr0 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr}; + +wire d_addr0_rd = d_rd_trig[0] & exec_done & ~d_addr0_wr; +wire d_addr1_rd = d_rd_trig[1] & exec_done & ~d_addr1_wr; +wire d_range_rd = d_rd_trig[2] & exec_done & ~d_range_wr; + + +// Set flags +assign addr0_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr0_rd | i_addr0_rd); +assign addr0_wr_set = brk_ctl[`BRK_MODE_WR] & d_addr0_wr; +assign addr1_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr1_rd | i_addr1_rd); +assign addr1_wr_set = brk_ctl[`BRK_MODE_WR] & d_addr1_wr; +assign range_rd_set = brk_ctl[`BRK_MODE_RD] & (d_range_rd | i_range_rd); +assign range_wr_set = brk_ctl[`BRK_MODE_WR] & d_range_wr; + + +// Break CPU +assign brk_halt = brk_ctl[`BRK_EN] & |brk_stat_set; + + +endmodule // omsp_dbg_hwbrk + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_dbg_uart.v b/tests/openmsp430/rtl/omsp_dbg_uart.v new file mode 100644 index 00000000..319099a5 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_dbg_uart.v @@ -0,0 +1,298 @@ +//---------------------------------------------------------------------------- +// 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_dbg_uart.v +// +// *Module Description: +// Debug UART communication interface (8N1, Half-duplex) +// +// *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_dbg_uart ( + +// OUTPUTs + dbg_addr, // Debug register address + dbg_din, // Debug register data input + dbg_rd, // Debug register data read + dbg_uart_txd, // Debug interface: UART TXD + dbg_wr, // Debug register data write + +// INPUTs + dbg_clk, // Debug unit clock + dbg_dout, // Debug register data output + dbg_rd_rdy, // Debug register data is ready for read + dbg_rst, // Debug unit reset + dbg_uart_rxd, // Debug interface: UART RXD + mem_burst, // Burst on going + mem_burst_end, // End TX/RX burst + mem_burst_rd, // Start TX burst + mem_burst_wr, // Start RX burst + mem_bw // Burst byte width +); + +// OUTPUTs +//========= +output [5:0] dbg_addr; // Debug register address +output [15:0] dbg_din; // Debug register data input +output dbg_rd; // Debug register data read +output dbg_uart_txd; // Debug interface: UART TXD +output dbg_wr; // Debug register data write + +// INPUTs +//========= +input dbg_clk; // Debug unit clock +input [15:0] dbg_dout; // Debug register data output +input dbg_rd_rdy; // Debug register data is ready for read +input dbg_rst; // Debug unit reset +input dbg_uart_rxd; // Debug interface: UART RXD +input mem_burst; // Burst on going +input mem_burst_end; // End TX/RX burst +input mem_burst_rd; // Start TX burst +input mem_burst_wr; // Start RX burst +input mem_bw; // Burst byte width + + +//============================================================================= +// 1) UART RECEIVE LINE SYNCHRONIZTION & FILTERING +//============================================================================= + +// Synchronize RXD input +//-------------------------------- +`ifdef SYNC_DBG_UART_RXD + + wire uart_rxd_n; + + omsp_sync_cell sync_cell_uart_rxd ( + .data_out (uart_rxd_n), + .data_in (~dbg_uart_rxd), + .clk (dbg_clk), + .rst (dbg_rst) + ); + wire uart_rxd = ~uart_rxd_n; +`else + wire uart_rxd = dbg_uart_rxd; +`endif + +// RXD input buffer +//-------------------------------- +reg [1:0] rxd_buf; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) rxd_buf <= 2'h3; + else rxd_buf <= {rxd_buf[0], uart_rxd}; + +// Majority decision +//------------------------ +reg rxd_maj; + +wire rxd_maj_nxt = (uart_rxd & rxd_buf[0]) | + (uart_rxd & rxd_buf[1]) | + (rxd_buf[0] & rxd_buf[1]); + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) rxd_maj <= 1'b1; + else rxd_maj <= rxd_maj_nxt; + +wire rxd_s = rxd_maj; +wire rxd_fe = rxd_maj & ~rxd_maj_nxt; +wire rxd_re = ~rxd_maj & rxd_maj_nxt; +wire rxd_edge = rxd_maj ^ rxd_maj_nxt; + +//============================================================================= +// 2) UART STATE MACHINE +//============================================================================= + +// Receive state +//------------------------ +reg [2:0] uart_state; +reg [2:0] uart_state_nxt; + +wire sync_done; +wire xfer_done; +reg [19:0] xfer_buf; +wire [19:0] xfer_buf_nxt; + +// State machine definition +parameter RX_SYNC = 3'h0; +parameter RX_CMD = 3'h1; +parameter RX_DATA1 = 3'h2; +parameter RX_DATA2 = 3'h3; +parameter TX_DATA1 = 3'h4; +parameter TX_DATA2 = 3'h5; + +// State transition +always @(uart_state or xfer_buf_nxt or mem_burst or mem_burst_wr or mem_burst_rd or mem_burst_end or mem_bw) + case (uart_state) + RX_SYNC : uart_state_nxt = RX_CMD; + RX_CMD : uart_state_nxt = mem_burst_wr ? + (mem_bw ? RX_DATA2 : RX_DATA1) : + mem_burst_rd ? + (mem_bw ? TX_DATA2 : TX_DATA1) : + (xfer_buf_nxt[`DBG_UART_WR] ? + (xfer_buf_nxt[`DBG_UART_BW] ? RX_DATA2 : RX_DATA1) : + (xfer_buf_nxt[`DBG_UART_BW] ? TX_DATA2 : TX_DATA1)); + RX_DATA1 : uart_state_nxt = RX_DATA2; + RX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ? + (mem_bw ? RX_DATA2 : RX_DATA1) : + RX_CMD; + TX_DATA1 : uart_state_nxt = TX_DATA2; + TX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ? + (mem_bw ? TX_DATA2 : TX_DATA1) : + RX_CMD; + // pragma coverage off + default : uart_state_nxt = RX_CMD; + // pragma coverage on + endcase + +// State machine +always @(posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) uart_state <= RX_SYNC; + else if (xfer_done | sync_done | + mem_burst_wr | mem_burst_rd) uart_state <= uart_state_nxt; + +// Utility signals +wire cmd_valid = (uart_state==RX_CMD) & xfer_done; +wire rx_active = (uart_state==RX_DATA1) | (uart_state==RX_DATA2) | (uart_state==RX_CMD); +wire tx_active = (uart_state==TX_DATA1) | (uart_state==TX_DATA2); + + +//============================================================================= +// 3) UART SYNCHRONIZATION +//============================================================================= +// After DBG_RST, the host needs to fist send a synchronization character (0x80) +// If this feature doesn't work properly, it is possible to disable it by +// commenting the DBG_UART_AUTO_SYNC define in the openMSP430.inc file. + +reg sync_busy; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) sync_busy <= 1'b0; + else if ((uart_state==RX_SYNC) & rxd_fe) sync_busy <= 1'b1; + else if ((uart_state==RX_SYNC) & rxd_re) sync_busy <= 1'b0; + +assign sync_done = (uart_state==RX_SYNC) & rxd_re & sync_busy; + +`ifdef DBG_UART_AUTO_SYNC + +reg [`DBG_UART_XFER_CNT_W+2:0] sync_cnt; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) sync_cnt <= {{`DBG_UART_XFER_CNT_W{1'b1}}, 3'b000}; + else if (sync_busy | (~sync_busy & sync_cnt[2])) sync_cnt <= sync_cnt+{{`DBG_UART_XFER_CNT_W+2{1'b0}}, 1'b1}; + +wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = sync_cnt[`DBG_UART_XFER_CNT_W+2:3]; +`else +wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = `DBG_UART_CNT; +`endif + + +//============================================================================= +// 4) UART RECEIVE / TRANSMIT +//============================================================================= + +// Transfer counter +//------------------------ +reg [3:0] xfer_bit; +reg [`DBG_UART_XFER_CNT_W-1:0] xfer_cnt; + +wire txd_start = dbg_rd_rdy | (xfer_done & (uart_state==TX_DATA1)); +wire rxd_start = (xfer_bit==4'h0) & rxd_fe & ((uart_state!=RX_SYNC)); +wire xfer_bit_inc = (xfer_bit!=4'h0) & (xfer_cnt=={`DBG_UART_XFER_CNT_W{1'b0}}); +assign xfer_done = rx_active ? (xfer_bit==4'ha) : (xfer_bit==4'hb); + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) xfer_bit <= 4'h0; + else if (txd_start | rxd_start) xfer_bit <= 4'h1; + else if (xfer_done) xfer_bit <= 4'h0; + else if (xfer_bit_inc) xfer_bit <= xfer_bit+4'h1; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) xfer_cnt <= {`DBG_UART_XFER_CNT_W{1'b0}}; + else if (rx_active & rxd_edge) xfer_cnt <= {1'b0, bit_cnt_max[`DBG_UART_XFER_CNT_W-1:1]}; + else if (txd_start | xfer_bit_inc) xfer_cnt <= bit_cnt_max; + else if (|xfer_cnt) xfer_cnt <= xfer_cnt+{`DBG_UART_XFER_CNT_W{1'b1}}; + + +// Receive/Transmit buffer +//------------------------- +assign xfer_buf_nxt = {rxd_s, xfer_buf[19:1]}; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) xfer_buf <= 20'h00000; + else if (dbg_rd_rdy) xfer_buf <= {1'b1, dbg_dout[15:8], 2'b01, dbg_dout[7:0], 1'b0}; + else if (xfer_bit_inc) xfer_buf <= xfer_buf_nxt; + + +// Generate TXD output +//------------------------ +reg dbg_uart_txd; + +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) dbg_uart_txd <= 1'b1; + else if (xfer_bit_inc & tx_active) dbg_uart_txd <= xfer_buf[0]; + + +//============================================================================= +// 5) INTERFACE TO DEBUG REGISTERS +//============================================================================= + +reg [5:0] dbg_addr; + always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) dbg_addr <= 6'h00; + else if (cmd_valid) dbg_addr <= xfer_buf_nxt[`DBG_UART_ADDR]; + +reg dbg_bw; +always @ (posedge dbg_clk or posedge dbg_rst) + if (dbg_rst) dbg_bw <= 1'b0; + else if (cmd_valid) dbg_bw <= xfer_buf_nxt[`DBG_UART_BW]; + +wire dbg_din_bw = mem_burst ? mem_bw : dbg_bw; + +wire [15:0] dbg_din = dbg_din_bw ? {8'h00, xfer_buf_nxt[18:11]} : + {xfer_buf_nxt[18:11], xfer_buf_nxt[9:2]}; +wire dbg_wr = (xfer_done & (uart_state==RX_DATA2)); +wire dbg_rd = mem_burst ? (xfer_done & (uart_state==TX_DATA2)) : + (cmd_valid & ~xfer_buf_nxt[`DBG_UART_WR]) | mem_burst_rd; + + + +endmodule // omsp_dbg_uart + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_execution_unit.v b/tests/openmsp430/rtl/omsp_execution_unit.v new file mode 100644 index 00000000..8a2965e5 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_execution_unit.v @@ -0,0 +1,420 @@ +//---------------------------------------------------------------------------- +// 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_execution_unit.v +// +// *Module Description: +// openMSP430 Execution unit +// +// *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_execution_unit ( + +// OUTPUTs + cpuoff, // Turns off the CPU + dbg_reg_din, // Debug unit CPU register data input + gie, // General interrupt enable + mab, // Memory address bus + mb_en, // Memory bus enable + mb_wr, // Memory bus write transfer + mdb_out, // Memory data bus output + oscoff, // Turns off LFXT1 clock input + pc_sw, // Program counter software value + pc_sw_wr, // Program counter software write + scg0, // System clock generator 1. Turns off the DCO + scg1, // System clock generator 1. Turns off the SMCLK + +// INPUTs + dbg_halt_st, // Halt/Run status from CPU + dbg_mem_dout, // Debug unit data output + dbg_reg_wr, // Debug unit CPU register write + e_state, // Execution state + exec_done, // Execution completed + inst_ad, // Decoded Inst: destination addressing mode + inst_as, // Decoded Inst: source addressing mode + inst_alu, // ALU control signals + inst_bw, // Decoded Inst: byte width + inst_dest, // Decoded Inst: destination (one hot) + inst_dext, // Decoded Inst: destination extended instruction word + inst_irq_rst, // Decoded Inst: reset interrupt + inst_jmp, // Decoded Inst: Conditional jump + inst_mov, // Decoded Inst: mov instruction + inst_sext, // Decoded Inst: source extended instruction word + inst_so, // Decoded Inst: Single-operand arithmetic + inst_src, // Decoded Inst: source (one hot) + inst_type, // Decoded Instruction type + mclk, // Main system clock + mdb_in, // Memory data bus input + pc, // Program counter + pc_nxt, // Next PC value (for CALL & IRQ) + puc_rst, // Main system reset + scan_enable // Scan enable (active during scan shifting) +); + +// OUTPUTs +//========= +output cpuoff; // Turns off the CPU +output [15:0] dbg_reg_din; // Debug unit CPU register data input +output gie; // General interrupt enable +output [15:0] mab; // Memory address bus +output mb_en; // Memory bus enable +output [1:0] mb_wr; // Memory bus write transfer +output [15:0] mdb_out; // Memory data bus output +output oscoff; // Turns off LFXT1 clock input +output [15:0] pc_sw; // Program counter software value +output pc_sw_wr; // Program counter software write +output scg0; // System clock generator 1. Turns off the DCO +output scg1; // System clock generator 1. Turns off the SMCLK + +// INPUTs +//========= +input dbg_halt_st; // Halt/Run status from CPU +input [15:0] dbg_mem_dout; // Debug unit data output +input dbg_reg_wr; // Debug unit CPU register write +input [3:0] e_state; // Execution state +input exec_done; // Execution completed +input [7:0] inst_ad; // Decoded Inst: destination addressing mode +input [7:0] inst_as; // Decoded Inst: source addressing mode +input [11:0] inst_alu; // ALU control signals +input inst_bw; // Decoded Inst: byte width +input [15:0] inst_dest; // Decoded Inst: destination (one hot) +input [15:0] inst_dext; // Decoded Inst: destination extended instruction word +input inst_irq_rst; // Decoded Inst: reset interrupt +input [7:0] inst_jmp; // Decoded Inst: Conditional jump +input inst_mov; // Decoded Inst: mov instruction +input [15:0] inst_sext; // Decoded Inst: source extended instruction word +input [7:0] inst_so; // Decoded Inst: Single-operand arithmetic +input [15:0] inst_src; // Decoded Inst: source (one hot) +input [2:0] inst_type; // Decoded Instruction type +input mclk; // Main system clock +input [15:0] mdb_in; // Memory data bus input +input [15:0] pc; // Program counter +input [15:0] pc_nxt; // Next PC value (for CALL & IRQ) +input puc_rst; // Main system reset +input scan_enable; // Scan enable (active during scan shifting) + + +//============================================================================= +// 1) INTERNAL WIRES/REGISTERS/PARAMETERS DECLARATION +//============================================================================= + +wire [15:0] alu_out; +wire [15:0] alu_out_add; +wire [3:0] alu_stat; +wire [3:0] alu_stat_wr; +wire [15:0] op_dst; +wire [15:0] op_src; +wire [15:0] reg_dest; +wire [15:0] reg_src; +wire [15:0] mdb_in_bw; +wire [15:0] mdb_in_val; +wire [3:0] status; + + +//============================================================================= +// 2) REGISTER FILE +//============================================================================= + +wire reg_dest_wr = ((e_state==`E_EXEC) & ( + (inst_type[`INST_TO] & inst_ad[`DIR] & ~inst_alu[`EXEC_NO_WR]) | + (inst_type[`INST_SO] & inst_as[`DIR] & ~(inst_so[`PUSH] | inst_so[`CALL] | inst_so[`RETI])) | + inst_type[`INST_JMP])) | dbg_reg_wr; + +wire reg_sp_wr = (((e_state==`E_IRQ_1) | (e_state==`E_IRQ_3)) & ~inst_irq_rst) | + ((e_state==`E_DST_RD) & ((inst_so[`PUSH] | inst_so[`CALL]) & ~inst_as[`IDX] & ~((inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1]))) | + ((e_state==`E_SRC_AD) & ((inst_so[`PUSH] | inst_so[`CALL]) & inst_as[`IDX])) | + ((e_state==`E_SRC_RD) & ((inst_so[`PUSH] | inst_so[`CALL]) & ((inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1]))); + +wire reg_sr_wr = (e_state==`E_DST_RD) & inst_so[`RETI]; + +wire reg_sr_clr = (e_state==`E_IRQ_2); + +wire reg_pc_call = ((e_state==`E_EXEC) & inst_so[`CALL]) | + ((e_state==`E_DST_WR) & inst_so[`RETI]); + +wire reg_incr = (exec_done & inst_as[`INDIR_I]) | + ((e_state==`E_SRC_RD) & inst_so[`RETI]) | + ((e_state==`E_EXEC) & inst_so[`RETI]); + +assign dbg_reg_din = reg_dest; + + +omsp_register_file register_file_0 ( + +// OUTPUTs + .cpuoff (cpuoff), // Turns off the CPU + .gie (gie), // General interrupt enable + .oscoff (oscoff), // Turns off LFXT1 clock input + .pc_sw (pc_sw), // Program counter software value + .pc_sw_wr (pc_sw_wr), // Program counter software write + .reg_dest (reg_dest), // Selected register destination content + .reg_src (reg_src), // Selected register source content + .scg0 (scg0), // System clock generator 1. Turns off the DCO + .scg1 (scg1), // System clock generator 1. Turns off the SMCLK + .status (status), // R2 Status {V,N,Z,C} + +// INPUTs + .alu_stat (alu_stat), // ALU Status {V,N,Z,C} + .alu_stat_wr (alu_stat_wr), // ALU Status write {V,N,Z,C} + .inst_bw (inst_bw), // Decoded Inst: byte width + .inst_dest (inst_dest), // Register destination selection + .inst_src (inst_src), // Register source selection + .mclk (mclk), // Main system clock + .pc (pc), // Program counter + .puc_rst (puc_rst), // Main system reset + .reg_dest_val (alu_out), // Selected register destination value + .reg_dest_wr (reg_dest_wr), // Write selected register destination + .reg_pc_call (reg_pc_call), // Trigger PC update for a CALL instruction + .reg_sp_val (alu_out_add), // Stack Pointer next value + .reg_sp_wr (reg_sp_wr), // Stack Pointer write + .reg_sr_clr (reg_sr_clr), // Status register clear for interrupts + .reg_sr_wr (reg_sr_wr), // Status Register update for RETI instruction + .reg_incr (reg_incr), // Increment source register + .scan_enable (scan_enable) // Scan enable (active during scan shifting) +); + + +//============================================================================= +// 3) SOURCE OPERAND MUXING +//============================================================================= +// inst_as[`DIR] : Register direct. -> Source is in register +// inst_as[`IDX] : Register indexed. -> Source is in memory, address is register+offset +// inst_as[`INDIR] : Register indirect. +// inst_as[`INDIR_I]: Register indirect autoincrement. +// inst_as[`SYMB] : Symbolic (operand is in memory at address PC+x). +// inst_as[`IMM] : Immediate (operand is next word in the instruction stream). +// inst_as[`ABS] : Absolute (operand is in memory at address x). +// inst_as[`CONST] : Constant. + +wire src_reg_src_sel = (e_state==`E_IRQ_0) | + (e_state==`E_IRQ_2) | + ((e_state==`E_SRC_RD) & ~inst_as[`ABS]) | + ((e_state==`E_SRC_WR) & ~inst_as[`ABS]) | + ((e_state==`E_EXEC) & inst_as[`DIR] & ~inst_type[`INST_JMP]); + +wire src_reg_dest_sel = (e_state==`E_IRQ_1) | + (e_state==`E_IRQ_3) | + ((e_state==`E_DST_RD) & (inst_so[`PUSH] | inst_so[`CALL])) | + ((e_state==`E_SRC_AD) & (inst_so[`PUSH] | inst_so[`CALL]) & inst_as[`IDX]); + +wire src_mdb_in_val_sel = ((e_state==`E_DST_RD) & inst_so[`RETI]) | + ((e_state==`E_EXEC) & (inst_as[`INDIR] | inst_as[`INDIR_I] | + inst_as[`IDX] | inst_as[`SYMB] | + inst_as[`ABS])); + +wire src_inst_dext_sel = ((e_state==`E_DST_RD) & ~(inst_so[`PUSH] | inst_so[`CALL])) | + ((e_state==`E_DST_WR) & ~(inst_so[`PUSH] | inst_so[`CALL] | + inst_so[`RETI])); + +wire src_inst_sext_sel = ((e_state==`E_EXEC) & (inst_type[`INST_JMP] | inst_as[`IMM] | + inst_as[`CONST] | inst_so[`RETI])); + + +assign op_src = src_reg_src_sel ? reg_src : + src_reg_dest_sel ? reg_dest : + src_mdb_in_val_sel ? mdb_in_val : + src_inst_dext_sel ? inst_dext : + src_inst_sext_sel ? inst_sext : 16'h0000; + + +//============================================================================= +// 4) DESTINATION OPERAND MUXING +//============================================================================= +// inst_ad[`DIR] : Register direct. +// inst_ad[`IDX] : Register indexed. +// inst_ad[`SYMB] : Symbolic (operand is in memory at address PC+x). +// inst_ad[`ABS] : Absolute (operand is in memory at address x). + + +wire dst_inst_sext_sel = ((e_state==`E_SRC_RD) & (inst_as[`IDX] | inst_as[`SYMB] | + inst_as[`ABS])) | + ((e_state==`E_SRC_WR) & (inst_as[`IDX] | inst_as[`SYMB] | + inst_as[`ABS])); + +wire dst_mdb_in_bw_sel = ((e_state==`E_DST_WR) & inst_so[`RETI]) | + ((e_state==`E_EXEC) & ~(inst_ad[`DIR] | inst_type[`INST_JMP] | + inst_type[`INST_SO]) & ~inst_so[`RETI]); + +wire dst_fffe_sel = (e_state==`E_IRQ_0) | + (e_state==`E_IRQ_1) | + (e_state==`E_IRQ_3) | + ((e_state==`E_DST_RD) & (inst_so[`PUSH] | inst_so[`CALL]) & ~inst_so[`RETI]) | + ((e_state==`E_SRC_AD) & (inst_so[`PUSH] | inst_so[`CALL]) & inst_as[`IDX]) | + ((e_state==`E_SRC_RD) & (inst_so[`PUSH] | inst_so[`CALL]) & (inst_as[`INDIR] | inst_as[`INDIR_I]) & inst_src[1]); + +wire dst_reg_dest_sel = ((e_state==`E_DST_RD) & ~(inst_so[`PUSH] | inst_so[`CALL] | inst_ad[`ABS] | inst_so[`RETI])) | + ((e_state==`E_DST_WR) & ~inst_ad[`ABS]) | + ((e_state==`E_EXEC) & (inst_ad[`DIR] | inst_type[`INST_JMP] | + inst_type[`INST_SO]) & ~inst_so[`RETI]); + + +assign op_dst = dbg_halt_st ? dbg_mem_dout : + dst_inst_sext_sel ? inst_sext : + dst_mdb_in_bw_sel ? mdb_in_bw : + dst_reg_dest_sel ? reg_dest : + dst_fffe_sel ? 16'hfffe : 16'h0000; + + +//============================================================================= +// 5) ALU +//============================================================================= + +wire exec_cycle = (e_state==`E_EXEC); + +omsp_alu alu_0 ( + +// OUTPUTs + .alu_out (alu_out), // ALU output value + .alu_out_add (alu_out_add), // ALU adder output value + .alu_stat (alu_stat), // ALU Status {V,N,Z,C} + .alu_stat_wr (alu_stat_wr), // ALU Status write {V,N,Z,C} + +// INPUTs + .dbg_halt_st (dbg_halt_st), // Halt/Run status from CPU + .exec_cycle (exec_cycle), // Instruction execution cycle + .inst_alu (inst_alu), // ALU control signals + .inst_bw (inst_bw), // Decoded Inst: byte width + .inst_jmp (inst_jmp), // Decoded Inst: Conditional jump + .inst_so (inst_so), // Single-operand arithmetic + .op_dst (op_dst), // Destination operand + .op_src (op_src), // Source operand + .status (status) // R2 Status {V,N,Z,C} +); + + +//============================================================================= +// 6) MEMORY INTERFACE +//============================================================================= + +// Detect memory read/write access +assign mb_en = ((e_state==`E_IRQ_1) & ~inst_irq_rst) | + ((e_state==`E_IRQ_3) & ~inst_irq_rst) | + ((e_state==`E_SRC_RD) & ~inst_as[`IMM]) | + (e_state==`E_SRC_WR) | + ((e_state==`E_EXEC) & inst_so[`RETI]) | + ((e_state==`E_DST_RD) & ~inst_type[`INST_SO] + & ~inst_mov) | + (e_state==`E_DST_WR); + +wire [1:0] mb_wr_msk = inst_alu[`EXEC_NO_WR] ? 2'b00 : + ~inst_bw ? 2'b11 : + alu_out_add[0] ? 2'b10 : 2'b01; +assign mb_wr = ({2{(e_state==`E_IRQ_1)}} | + {2{(e_state==`E_IRQ_3)}} | + {2{(e_state==`E_DST_WR)}} | + {2{(e_state==`E_SRC_WR)}}) & mb_wr_msk; + +// Memory address bus +assign mab = alu_out_add[15:0]; + +// Memory data bus output +reg [15:0] mdb_out_nxt; + +`ifdef CLOCK_GATING +wire mdb_out_nxt_en = (e_state==`E_DST_RD) | + (((e_state==`E_EXEC) & ~inst_so[`CALL]) | + (e_state==`E_IRQ_0) | (e_state==`E_IRQ_2)); +wire mclk_mdb_out_nxt; +omsp_clock_gate clock_gate_mdb_out_nxt (.gclk(mclk_mdb_out_nxt), + .clk (mclk), .enable(mdb_out_nxt_en), .scan_enable(scan_enable)); +`else +wire mclk_mdb_out_nxt = mclk; +`endif + +always @(posedge mclk_mdb_out_nxt or posedge puc_rst) + if (puc_rst) mdb_out_nxt <= 16'h0000; + else if (e_state==`E_DST_RD) mdb_out_nxt <= pc_nxt; +`ifdef CLOCK_GATING + else mdb_out_nxt <= alu_out; +`else + else if ((e_state==`E_EXEC & ~inst_so[`CALL]) | + (e_state==`E_IRQ_0) | (e_state==`E_IRQ_2)) mdb_out_nxt <= alu_out; +`endif + +assign mdb_out = inst_bw ? {2{mdb_out_nxt[7:0]}} : mdb_out_nxt; + +// Format memory data bus input depending on BW +reg mab_lsb; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) mab_lsb <= 1'b0; + else if (mb_en) mab_lsb <= alu_out_add[0]; + +assign mdb_in_bw = ~inst_bw ? mdb_in : + mab_lsb ? {2{mdb_in[15:8]}} : mdb_in; + +// Memory data bus input buffer (buffer after a source read) +reg mdb_in_buf_en; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) mdb_in_buf_en <= 1'b0; + else mdb_in_buf_en <= (e_state==`E_SRC_RD); + +reg mdb_in_buf_valid; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) mdb_in_buf_valid <= 1'b0; + else if (e_state==`E_EXEC) mdb_in_buf_valid <= 1'b0; + else if (mdb_in_buf_en) mdb_in_buf_valid <= 1'b1; + +reg [15:0] mdb_in_buf; + +`ifdef CLOCK_GATING +wire mclk_mdb_in_buf; +omsp_clock_gate clock_gate_mdb_in_buf (.gclk(mclk_mdb_in_buf), + .clk (mclk), .enable(mdb_in_buf_en), .scan_enable(scan_enable)); +`else +wire mclk_mdb_in_buf = mclk; +`endif + +always @(posedge mclk_mdb_in_buf or posedge puc_rst) + if (puc_rst) mdb_in_buf <= 16'h0000; +`ifdef CLOCK_GATING + else mdb_in_buf <= mdb_in_bw; +`else + else if (mdb_in_buf_en) mdb_in_buf <= mdb_in_bw; +`endif + +assign mdb_in_val = mdb_in_buf_valid ? mdb_in_buf : mdb_in_bw; + + +endmodule // omsp_execution_unit + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_frontend.v b/tests/openmsp430/rtl/omsp_frontend.v new file mode 100644 index 00000000..343944bd --- /dev/null +++ b/tests/openmsp430/rtl/omsp_frontend.v @@ -0,0 +1,966 @@ +//---------------------------------------------------------------------------- +// 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_frontend.v +// +// *Module Description: +// openMSP430 Instruction fetch and decode unit +// +// *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_frontend ( + +// OUTPUTs + dbg_halt_st, // Halt/Run status from CPU + decode_noirq, // Frontend decode instruction + e_state, // Execution state + exec_done, // Execution completed + inst_ad, // Decoded Inst: destination addressing mode + inst_as, // Decoded Inst: source addressing mode + inst_alu, // ALU control signals + inst_bw, // Decoded Inst: byte width + inst_dest, // Decoded Inst: destination (one hot) + inst_dext, // Decoded Inst: destination extended instruction word + inst_irq_rst, // Decoded Inst: Reset interrupt + inst_jmp, // Decoded Inst: Conditional jump + inst_mov, // Decoded Inst: mov instruction + inst_sext, // Decoded Inst: source extended instruction word + inst_so, // Decoded Inst: Single-operand arithmetic + inst_src, // Decoded Inst: source (one hot) + inst_type, // Decoded Instruction type + irq_acc, // Interrupt request accepted (one-hot signal) + mab, // Frontend Memory address bus + mb_en, // Frontend Memory bus enable + mclk_enable, // Main System Clock enable + mclk_wkup, // Main System Clock wake-up (asynchronous) + nmi_acc, // Non-Maskable interrupt request accepted + pc, // Program counter + pc_nxt, // Next PC value (for CALL & IRQ) + +// INPUTs + cpu_en_s, // Enable CPU code execution (synchronous) + cpuoff, // Turns off the CPU + dbg_halt_cmd, // Halt CPU command + dbg_reg_sel, // Debug selected register for rd/wr access + fe_pmem_wait, // Frontend wait for Instruction fetch + gie, // General interrupt enable + irq, // Maskable interrupts + mclk, // Main system clock + mdb_in, // Frontend Memory data bus input + nmi_pnd, // Non-maskable interrupt pending + nmi_wkup, // NMI Wakeup + pc_sw, // Program counter software value + pc_sw_wr, // Program counter software write + puc_rst, // Main system reset + scan_enable, // Scan enable (active during scan shifting) + wdt_irq, // Watchdog-timer interrupt + wdt_wkup, // Watchdog Wakeup + wkup // System Wake-up (asynchronous) +); + +// OUTPUTs +//========= +output dbg_halt_st; // Halt/Run status from CPU +output decode_noirq; // Frontend decode instruction +output [3:0] e_state; // Execution state +output exec_done; // Execution completed +output [7:0] inst_ad; // Decoded Inst: destination addressing mode +output [7:0] inst_as; // Decoded Inst: source addressing mode +output [11:0] inst_alu; // ALU control signals +output inst_bw; // Decoded Inst: byte width +output [15:0] inst_dest; // Decoded Inst: destination (one hot) +output [15:0] inst_dext; // Decoded Inst: destination extended instruction word +output inst_irq_rst; // Decoded Inst: Reset interrupt +output [7:0] inst_jmp; // Decoded Inst: Conditional jump +output inst_mov; // Decoded Inst: mov instruction +output [15:0] inst_sext; // Decoded Inst: source extended instruction word +output [7:0] inst_so; // Decoded Inst: Single-operand arithmetic +output [15:0] inst_src; // Decoded Inst: source (one hot) +output [2:0] inst_type; // Decoded Instruction type +output [13:0] irq_acc; // Interrupt request accepted (one-hot signal) +output [15:0] mab; // Frontend Memory address bus +output mb_en; // Frontend Memory bus enable +output mclk_enable; // Main System Clock enable +output mclk_wkup; // Main System Clock wake-up (asynchronous) +output nmi_acc; // Non-Maskable interrupt request accepted +output [15:0] pc; // Program counter +output [15:0] pc_nxt; // Next PC value (for CALL & IRQ) + +// INPUTs +//========= +input cpu_en_s; // Enable CPU code execution (synchronous) +input cpuoff; // Turns off the CPU +input dbg_halt_cmd; // Halt CPU command +input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access +input fe_pmem_wait; // Frontend wait for Instruction fetch +input gie; // General interrupt enable +input [13:0] irq; // Maskable interrupts +input mclk; // Main system clock +input [15:0] mdb_in; // Frontend Memory data bus input +input nmi_pnd; // Non-maskable interrupt pending +input nmi_wkup; // NMI Wakeup +input [15:0] pc_sw; // Program counter software value +input pc_sw_wr; // Program counter software write +input puc_rst; // Main system reset +input scan_enable; // Scan enable (active during scan shifting) +input wdt_irq; // Watchdog-timer interrupt +input wdt_wkup; // Watchdog Wakeup +input wkup; // System Wake-up (asynchronous) + + +//============================================================================= +// 1) UTILITY FUNCTIONS +//============================================================================= + +// 16 bits one-hot decoder +function [15:0] one_hot16; + input [3:0] binary; + begin + one_hot16 = 16'h0000; + one_hot16[binary] = 1'b1; + end +endfunction + +// 8 bits one-hot decoder +function [7:0] one_hot8; + input [2:0] binary; + begin + one_hot8 = 8'h00; + one_hot8[binary] = 1'b1; + end +endfunction + + +//============================================================================= +// 2) PARAMETER DEFINITIONS +//============================================================================= + +// +// 2.1) Instruction State machine definitons +//------------------------------------------- + +parameter I_IRQ_FETCH = `I_IRQ_FETCH; +parameter I_IRQ_DONE = `I_IRQ_DONE; +parameter I_DEC = `I_DEC; // New instruction ready for decode +parameter I_EXT1 = `I_EXT1; // 1st Extension word +parameter I_EXT2 = `I_EXT2; // 2nd Extension word +parameter I_IDLE = `I_IDLE; // CPU is in IDLE mode + +// +// 2.2) Execution State machine definitons +//------------------------------------------- + +parameter E_IRQ_0 = `E_IRQ_0; +parameter E_IRQ_1 = `E_IRQ_1; +parameter E_IRQ_2 = `E_IRQ_2; +parameter E_IRQ_3 = `E_IRQ_3; +parameter E_IRQ_4 = `E_IRQ_4; +parameter E_SRC_AD = `E_SRC_AD; +parameter E_SRC_RD = `E_SRC_RD; +parameter E_SRC_WR = `E_SRC_WR; +parameter E_DST_AD = `E_DST_AD; +parameter E_DST_RD = `E_DST_RD; +parameter E_DST_WR = `E_DST_WR; +parameter E_EXEC = `E_EXEC; +parameter E_JUMP = `E_JUMP; +parameter E_IDLE = `E_IDLE; + + +//============================================================================= +// 3) FRONTEND STATE MACHINE +//============================================================================= + +// The wire "conv" is used as state bits to calculate the next response +reg [2:0] i_state; +reg [2:0] i_state_nxt; + +reg [1:0] inst_sz; +wire [1:0] inst_sz_nxt; +wire irq_detect; +wire [2:0] inst_type_nxt; +wire is_const; +reg [15:0] sconst_nxt; +reg [3:0] e_state_nxt; + +// CPU on/off through the debug interface or cpu_en port +wire cpu_halt_cmd = dbg_halt_cmd | ~cpu_en_s; + +// States Transitions +always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or + irq_detect or cpuoff or cpu_halt_cmd or e_state) + case(i_state) + I_IDLE : i_state_nxt = (irq_detect & ~cpu_halt_cmd) ? I_IRQ_FETCH : + (~cpuoff & ~cpu_halt_cmd) ? I_DEC : I_IDLE; + I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE; + I_IRQ_DONE : i_state_nxt = I_DEC; + I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH : + (cpuoff | cpu_halt_cmd) & exec_done ? I_IDLE : + cpu_halt_cmd & (e_state==E_IDLE) ? I_IDLE : + pc_sw_wr ? I_DEC : + ~exec_done & ~(e_state==E_IDLE) ? I_DEC : // Wait in decode state + (inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed + I_EXT1 : i_state_nxt = pc_sw_wr ? I_DEC : + (inst_sz!=2'b01) ? I_EXT2 : I_DEC; + I_EXT2 : i_state_nxt = I_DEC; + // pragma coverage off + default : i_state_nxt = I_IRQ_FETCH; + // pragma coverage on + endcase + +// State machine +always @(posedge mclk or posedge puc_rst) + if (puc_rst) i_state <= I_IRQ_FETCH; + else i_state <= i_state_nxt; + +// Utility signals +wire decode_noirq = ((i_state==I_DEC) & (exec_done | (e_state==E_IDLE))); +wire decode = decode_noirq | irq_detect; +wire fetch = ~((i_state==I_DEC) & ~(exec_done | (e_state==E_IDLE))) & ~(e_state_nxt==E_IDLE); + +// Debug interface cpu status +reg dbg_halt_st; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) dbg_halt_st <= 1'b0; + else dbg_halt_st <= cpu_halt_cmd & (i_state_nxt==I_IDLE); + + +//============================================================================= +// 4) INTERRUPT HANDLING & SYSTEM WAKEUP +//============================================================================= + +// +// 4.1) INTERRUPT HANDLING +//----------------------------------------- + +// Detect reset interrupt +reg inst_irq_rst; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) inst_irq_rst <= 1'b1; + else if (exec_done) inst_irq_rst <= 1'b0; + +// Detect other interrupts +assign irq_detect = (nmi_pnd | ((|irq | wdt_irq) & gie)) & ~cpu_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE)); + +`ifdef CLOCK_GATING +wire mclk_irq_num; +omsp_clock_gate clock_gate_irq_num (.gclk(mclk_irq_num), + .clk (mclk), .enable(irq_detect), .scan_enable(scan_enable)); +`else +wire mclk_irq_num = mclk; +`endif + +// Select interrupt vector +reg [3:0] irq_num; +always @(posedge mclk_irq_num or posedge puc_rst) + if (puc_rst) irq_num <= 4'hf; +`ifdef CLOCK_GATING + else irq_num <= nmi_pnd ? 4'he : +`else + else if (irq_detect) irq_num <= nmi_pnd ? 4'he : +`endif + irq[13] ? 4'hd : + irq[12] ? 4'hc : + irq[11] ? 4'hb : + (irq[10] | wdt_irq) ? 4'ha : + irq[9] ? 4'h9 : + irq[8] ? 4'h8 : + irq[7] ? 4'h7 : + irq[6] ? 4'h6 : + irq[5] ? 4'h5 : + irq[4] ? 4'h4 : + irq[3] ? 4'h3 : + irq[2] ? 4'h2 : + irq[1] ? 4'h1 : + irq[0] ? 4'h0 : 4'hf; + +wire [15:0] irq_addr = {11'h7ff, irq_num, 1'b0}; + +// Interrupt request accepted +wire [15:0] irq_acc_all = one_hot16(irq_num) & {16{(i_state==I_IRQ_FETCH)}}; +wire [13:0] irq_acc = irq_acc_all[13:0]; +wire nmi_acc = irq_acc_all[14]; + +// +// 4.2) SYSTEM WAKEUP +//----------------------------------------- +`ifdef CPUOFF_EN + +// Generate the main system clock enable signal + // Keep the clock running if: +wire mclk_enable = inst_irq_rst ? cpu_en_s : // - the RESET interrupt is currently executing + // and if the CPU is enabled + // otherwise if: + ~((cpuoff | ~cpu_en_s) & // - the CPUOFF flag, cpu_en command, instruction + (i_state==I_IDLE) & // and execution state machines are all two + (e_state==E_IDLE)); // not idle. + + +// Wakeup condition from maskable interrupts +wire mirq_wkup; +omsp_and_gate and_mirq_wkup (.y(mirq_wkup), .a(wkup | wdt_wkup), .b(gie)); + +// Combined asynchronous wakeup detection from nmi & irq (masked if the cpu is disabled) +omsp_and_gate and_mclk_wkup (.y(mclk_wkup), .a(nmi_wkup | mirq_wkup), .b(cpu_en_s)); + +`else + +// In the CPUOFF feature is disabled, the wake-up and enable signals are always 1 +assign mclk_wkup = 1'b1; +assign mclk_enable = 1'b1; +`endif + +//============================================================================= +// 5) FETCH INSTRUCTION +//============================================================================= + +// +// 5.1) PROGRAM COUNTER & MEMORY INTERFACE +//----------------------------------------- + +// Program counter +reg [15:0] pc; + +// Compute next PC value +wire [15:0] pc_incr = pc + {14'h0000, fetch, 1'b0}; +wire [15:0] pc_nxt = pc_sw_wr ? pc_sw : + (i_state==I_IRQ_FETCH) ? irq_addr : + (i_state==I_IRQ_DONE) ? mdb_in : pc_incr; + +`ifdef CLOCK_GATING +wire pc_en = fetch | + pc_sw_wr | + (i_state==I_IRQ_FETCH) | + (i_state==I_IRQ_DONE); +wire mclk_pc; +omsp_clock_gate clock_gate_pc (.gclk(mclk_pc), + .clk (mclk), .enable(pc_en), .scan_enable(scan_enable)); +`else +wire mclk_pc = mclk; +`endif + +always @(posedge mclk_pc or posedge puc_rst) + if (puc_rst) pc <= 16'h0000; + else pc <= pc_nxt; + +// Check if ROM has been busy in order to retry ROM access +reg pmem_busy; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) pmem_busy <= 1'b0; + else pmem_busy <= fe_pmem_wait; + +// Memory interface +wire [15:0] mab = pc_nxt; +wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~cpu_halt_cmd); + + +// +// 5.2) INSTRUCTION REGISTER +//-------------------------------- + +// Instruction register +wire [15:0] ir = mdb_in; + +// Detect if source extension word is required +wire is_sext = (inst_as[`IDX] | inst_as[`SYMB] | inst_as[`ABS] | inst_as[`IMM]); + +// For the Symbolic addressing mode, add -2 to the extension word in order +// to make up for the PC address +wire [15:0] ext_incr = ((i_state==I_EXT1) & inst_as[`SYMB]) | + ((i_state==I_EXT2) & inst_ad[`SYMB]) | + ((i_state==I_EXT1) & ~inst_as[`SYMB] & + ~(i_state_nxt==I_EXT2) & inst_ad[`SYMB]) ? 16'hfffe : 16'h0000; + +wire [15:0] ext_nxt = ir + ext_incr; + +// Store source extension word +reg [15:0] inst_sext; + +`ifdef CLOCK_GATING +wire inst_sext_en = (decode & is_const) | + (decode & inst_type_nxt[`INST_JMP]) | + ((i_state==I_EXT1) & is_sext); +wire mclk_inst_sext; +omsp_clock_gate clock_gate_inst_sext (.gclk(mclk_inst_sext), + .clk (mclk), .enable(inst_sext_en), .scan_enable(scan_enable)); +`else +wire mclk_inst_sext = mclk; +`endif + +always @(posedge mclk_inst_sext or posedge puc_rst) + if (puc_rst) inst_sext <= 16'h0000; + else if (decode & is_const) inst_sext <= sconst_nxt; + else if (decode & inst_type_nxt[`INST_JMP]) inst_sext <= {{5{ir[9]}},ir[9:0],1'b0}; +`ifdef CLOCK_GATING + else inst_sext <= ext_nxt; +`else + else if ((i_state==I_EXT1) & is_sext) inst_sext <= ext_nxt; +`endif + +// Source extension word is ready +wire inst_sext_rdy = (i_state==I_EXT1) & is_sext; + + +// Store destination extension word +reg [15:0] inst_dext; + +`ifdef CLOCK_GATING +wire inst_dext_en = ((i_state==I_EXT1) & ~is_sext) | + (i_state==I_EXT2); +wire mclk_inst_dext; +omsp_clock_gate clock_gate_inst_dext (.gclk(mclk_inst_dext), + .clk (mclk), .enable(inst_dext_en), .scan_enable(scan_enable)); +`else +wire mclk_inst_dext = mclk; +`endif + +always @(posedge mclk_inst_dext or posedge puc_rst) + if (puc_rst) inst_dext <= 16'h0000; + else if ((i_state==I_EXT1) & ~is_sext) inst_dext <= ext_nxt; +`ifdef CLOCK_GATING + else inst_dext <= ext_nxt; +`else + else if (i_state==I_EXT2) inst_dext <= ext_nxt; +`endif + +// Destination extension word is ready +wire inst_dext_rdy = (((i_state==I_EXT1) & ~is_sext) | (i_state==I_EXT2)); + + +//============================================================================= +// 6) DECODE INSTRUCTION +//============================================================================= + +`ifdef CLOCK_GATING +wire mclk_decode; +omsp_clock_gate clock_gate_decode (.gclk(mclk_decode), + .clk (mclk), .enable(decode), .scan_enable(scan_enable)); +`else +wire mclk_decode = mclk; +`endif + +// +// 6.1) OPCODE: INSTRUCTION TYPE +//---------------------------------------- +// Instructions type is encoded in a one hot fashion as following: +// +// 3'b001: Single-operand arithmetic +// 3'b010: Conditional jump +// 3'b100: Two-operand arithmetic + +reg [2:0] inst_type; +assign inst_type_nxt = {(ir[15:14]!=2'b00), + (ir[15:13]==3'b001), + (ir[15:13]==3'b000)} & {3{~irq_detect}}; + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_type <= 3'b000; +`ifdef CLOCK_GATING + else inst_type <= inst_type_nxt; +`else + else if (decode) inst_type <= inst_type_nxt; +`endif + +// +// 6.2) OPCODE: SINGLE-OPERAND ARITHMETIC +//---------------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 8'b00000001: RRC +// 8'b00000010: SWPB +// 8'b00000100: RRA +// 8'b00001000: SXT +// 8'b00010000: PUSH +// 8'b00100000: CALL +// 8'b01000000: RETI +// 8'b10000000: IRQ + +reg [7:0] inst_so; +wire [7:0] inst_so_nxt = irq_detect ? 8'h80 : (one_hot8(ir[9:7]) & {8{inst_type_nxt[`INST_SO]}}); + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_so <= 8'h00; +`ifdef CLOCK_GATING + else inst_so <= inst_so_nxt; +`else + else if (decode) inst_so <= inst_so_nxt; +`endif + +// +// 6.3) OPCODE: CONDITIONAL JUMP +//-------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 8'b00000001: JNE/JNZ +// 8'b00000010: JEQ/JZ +// 8'b00000100: JNC/JLO +// 8'b00001000: JC/JHS +// 8'b00010000: JN +// 8'b00100000: JGE +// 8'b01000000: JL +// 8'b10000000: JMP + +reg [2:0] inst_jmp_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_jmp_bin <= 3'h0; +`ifdef CLOCK_GATING + else inst_jmp_bin <= ir[12:10]; +`else + else if (decode) inst_jmp_bin <= ir[12:10]; +`endif + +wire [7:0] inst_jmp = one_hot8(inst_jmp_bin) & {8{inst_type[`INST_JMP]}}; + + +// +// 6.4) OPCODE: TWO-OPERAND ARITHMETIC +//------------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 12'b000000000001: MOV +// 12'b000000000010: ADD +// 12'b000000000100: ADDC +// 12'b000000001000: SUBC +// 12'b000000010000: SUB +// 12'b000000100000: CMP +// 12'b000001000000: DADD +// 12'b000010000000: BIT +// 12'b000100000000: BIC +// 12'b001000000000: BIS +// 12'b010000000000: XOR +// 12'b100000000000: AND + +wire [15:0] inst_to_1hot = one_hot16(ir[15:12]) & {16{inst_type_nxt[`INST_TO]}}; +wire [11:0] inst_to_nxt = inst_to_1hot[15:4]; + +reg inst_mov; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_mov <= 1'b0; +`ifdef CLOCK_GATING + else inst_mov <= inst_to_nxt[`MOV]; +`else + else if (decode) inst_mov <= inst_to_nxt[`MOV]; +`endif + + +// +// 6.5) SOURCE AND DESTINATION REGISTERS +//--------------------------------------- + +// Destination register +reg [3:0] inst_dest_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_dest_bin <= 4'h0; +`ifdef CLOCK_GATING + else inst_dest_bin <= ir[3:0]; +`else + else if (decode) inst_dest_bin <= ir[3:0]; +`endif + +wire [15:0] inst_dest = dbg_halt_st ? one_hot16(dbg_reg_sel) : + inst_type[`INST_JMP] ? 16'h0001 : + inst_so[`IRQ] | + inst_so[`PUSH] | + inst_so[`CALL] ? 16'h0002 : + one_hot16(inst_dest_bin); + + +// Source register +reg [3:0] inst_src_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_src_bin <= 4'h0; +`ifdef CLOCK_GATING + else inst_src_bin <= ir[11:8]; +`else + else if (decode) inst_src_bin <= ir[11:8]; +`endif + +wire [15:0] inst_src = inst_type[`INST_TO] ? one_hot16(inst_src_bin) : + inst_so[`RETI] ? 16'h0002 : + inst_so[`IRQ] ? 16'h0001 : + inst_type[`INST_SO] ? one_hot16(inst_dest_bin) : 16'h0000; + + +// +// 6.6) SOURCE ADDRESSING MODES +//-------------------------------- +// Source addressing modes are encoded in a one hot fashion as following: +// +// 13'b0000000000001: Register direct. +// 13'b0000000000010: Register indexed. +// 13'b0000000000100: Register indirect. +// 13'b0000000001000: Register indirect autoincrement. +// 13'b0000000010000: Symbolic (operand is in memory at address PC+x). +// 13'b0000000100000: Immediate (operand is next word in the instruction stream). +// 13'b0000001000000: Absolute (operand is in memory at address x). +// 13'b0000010000000: Constant 4. +// 13'b0000100000000: Constant 8. +// 13'b0001000000000: Constant 0. +// 13'b0010000000000: Constant 1. +// 13'b0100000000000: Constant 2. +// 13'b1000000000000: Constant -1. + +reg [12:0] inst_as_nxt; + +wire [3:0] src_reg = inst_type_nxt[`INST_SO] ? ir[3:0] : ir[11:8]; + +always @(src_reg or ir or inst_type_nxt) + begin + if (inst_type_nxt[`INST_JMP]) + inst_as_nxt = 13'b0000000000001; + else if (src_reg==4'h3) // Addressing mode using R3 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b1000000000000; + 2'b10 : inst_as_nxt = 13'b0100000000000; + 2'b01 : inst_as_nxt = 13'b0010000000000; + default: inst_as_nxt = 13'b0001000000000; + endcase + else if (src_reg==4'h2) // Addressing mode using R2 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000100000000; + 2'b10 : inst_as_nxt = 13'b0000010000000; + 2'b01 : inst_as_nxt = 13'b0000001000000; + default: inst_as_nxt = 13'b0000000000001; + endcase + else if (src_reg==4'h0) // Addressing mode using R0 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000000100000; + 2'b10 : inst_as_nxt = 13'b0000000000100; + 2'b01 : inst_as_nxt = 13'b0000000010000; + default: inst_as_nxt = 13'b0000000000001; + endcase + else // General Addressing mode + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000000001000; + 2'b10 : inst_as_nxt = 13'b0000000000100; + 2'b01 : inst_as_nxt = 13'b0000000000010; + default: inst_as_nxt = 13'b0000000000001; + endcase + end +assign is_const = |inst_as_nxt[12:7]; + +reg [7:0] inst_as; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_as <= 8'h00; +`ifdef CLOCK_GATING + else inst_as <= {is_const, inst_as_nxt[6:0]}; +`else + else if (decode) inst_as <= {is_const, inst_as_nxt[6:0]}; +`endif + + +// 13'b0000010000000: Constant 4. +// 13'b0000100000000: Constant 8. +// 13'b0001000000000: Constant 0. +// 13'b0010000000000: Constant 1. +// 13'b0100000000000: Constant 2. +// 13'b1000000000000: Constant -1. +always @(inst_as_nxt) + begin + if (inst_as_nxt[7]) sconst_nxt = 16'h0004; + else if (inst_as_nxt[8]) sconst_nxt = 16'h0008; + else if (inst_as_nxt[9]) sconst_nxt = 16'h0000; + else if (inst_as_nxt[10]) sconst_nxt = 16'h0001; + else if (inst_as_nxt[11]) sconst_nxt = 16'h0002; + else if (inst_as_nxt[12]) sconst_nxt = 16'hffff; + else sconst_nxt = 16'h0000; + end + + +// +// 6.7) DESTINATION ADDRESSING MODES +//----------------------------------- +// Destination addressing modes are encoded in a one hot fashion as following: +// +// 8'b00000001: Register direct. +// 8'b00000010: Register indexed. +// 8'b00010000: Symbolic (operand is in memory at address PC+x). +// 8'b01000000: Absolute (operand is in memory at address x). + +reg [7:0] inst_ad_nxt; + +wire [3:0] dest_reg = ir[3:0]; + +always @(dest_reg or ir or inst_type_nxt) + begin + if (~inst_type_nxt[`INST_TO]) + inst_ad_nxt = 8'b00000000; + else if (dest_reg==4'h2) // Addressing mode using R2 + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b01000000; + default: inst_ad_nxt = 8'b00000001; + endcase + else if (dest_reg==4'h0) // Addressing mode using R0 + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b00010000; + default: inst_ad_nxt = 8'b00000001; + endcase + else // General Addressing mode + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b00000010; + default: inst_ad_nxt = 8'b00000001; + endcase + end + +reg [7:0] inst_ad; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_ad <= 8'h00; +`ifdef CLOCK_GATING + else inst_ad <= inst_ad_nxt; +`else + else if (decode) inst_ad <= inst_ad_nxt; +`endif + + +// +// 6.8) REMAINING INSTRUCTION DECODING +//------------------------------------- + +// Operation size +reg inst_bw; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) inst_bw <= 1'b0; + else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_cmd; + +// Extended instruction size +assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} + + {1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])}; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_sz <= 2'b00; +`ifdef CLOCK_GATING + else inst_sz <= inst_sz_nxt; +`else + else if (decode) inst_sz <= inst_sz_nxt; +`endif + + +//============================================================================= +// 7) EXECUTION-UNIT STATE MACHINE +//============================================================================= + +// State machine registers +reg [3:0] e_state; + + +// State machine control signals +//-------------------------------- + +wire src_acalc_pre = inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS]; +wire src_rd_pre = inst_as_nxt[`INDIR] | inst_as_nxt[`INDIR_I] | inst_as_nxt[`IMM] | inst_so_nxt[`RETI]; +wire dst_acalc_pre = inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]; +wire dst_acalc = inst_ad[`IDX] | inst_ad[`SYMB] | inst_ad[`ABS]; +wire dst_rd_pre = inst_ad_nxt[`IDX] | inst_so_nxt[`PUSH] | inst_so_nxt[`CALL] | inst_so_nxt[`RETI]; +wire dst_rd = inst_ad[`IDX] | inst_so[`PUSH] | inst_so[`CALL] | inst_so[`RETI]; + +wire inst_branch = (inst_ad_nxt[`DIR] & (ir[3:0]==4'h0)) | inst_type_nxt[`INST_JMP] | inst_so_nxt[`RETI]; + +reg exec_jmp; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_jmp <= 1'b0; + else if (inst_branch & decode) exec_jmp <= 1'b1; + else if (e_state==E_JUMP) exec_jmp <= 1'b0; + +reg exec_dst_wr; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_dst_wr <= 1'b0; + else if (e_state==E_DST_RD) exec_dst_wr <= 1'b1; + else if (e_state==E_DST_WR) exec_dst_wr <= 1'b0; + +reg exec_src_wr; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_src_wr <= 1'b0; + else if (inst_type[`INST_SO] & (e_state==E_SRC_RD)) exec_src_wr <= 1'b1; + else if ((e_state==E_SRC_WR) || (e_state==E_DST_WR)) exec_src_wr <= 1'b0; + +reg exec_dext_rdy; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_dext_rdy <= 1'b0; + else if (e_state==E_DST_RD) exec_dext_rdy <= 1'b0; + else if (inst_dext_rdy) exec_dext_rdy <= 1'b1; + +// Execution first state +wire [3:0] e_first_state = ~dbg_halt_st & inst_so_nxt[`IRQ] ? E_IRQ_0 : + cpu_halt_cmd | (i_state==I_IDLE) ? E_IDLE : + cpuoff ? E_IDLE : + src_acalc_pre ? E_SRC_AD : + src_rd_pre ? E_SRC_RD : + dst_acalc_pre ? E_DST_AD : + dst_rd_pre ? E_DST_RD : E_EXEC; + + +// State machine +//-------------------------------- + +// States Transitions +always @(e_state or dst_acalc or dst_rd or inst_sext_rdy or + inst_dext_rdy or exec_dext_rdy or exec_jmp or exec_dst_wr or + e_first_state or exec_src_wr) + case(e_state) + E_IDLE : e_state_nxt = e_first_state; + E_IRQ_0 : e_state_nxt = E_IRQ_1; + E_IRQ_1 : e_state_nxt = E_IRQ_2; + E_IRQ_2 : e_state_nxt = E_IRQ_3; + E_IRQ_3 : e_state_nxt = E_IRQ_4; + E_IRQ_4 : e_state_nxt = E_EXEC; + + E_SRC_AD : e_state_nxt = inst_sext_rdy ? E_SRC_RD : E_SRC_AD; + + E_SRC_RD : e_state_nxt = dst_acalc ? E_DST_AD : + dst_rd ? E_DST_RD : E_EXEC; + + E_DST_AD : e_state_nxt = (inst_dext_rdy | + exec_dext_rdy) ? E_DST_RD : E_DST_AD; + + E_DST_RD : e_state_nxt = E_EXEC; + + E_EXEC : e_state_nxt = exec_dst_wr ? E_DST_WR : + exec_jmp ? E_JUMP : + exec_src_wr ? E_SRC_WR : e_first_state; + + E_JUMP : e_state_nxt = e_first_state; + E_DST_WR : e_state_nxt = exec_jmp ? E_JUMP : e_first_state; + E_SRC_WR : e_state_nxt = e_first_state; + // pragma coverage off + default : e_state_nxt = E_IRQ_0; + // pragma coverage on + endcase + +// State machine +always @(posedge mclk or posedge puc_rst) + if (puc_rst) e_state <= E_IRQ_1; + else e_state <= e_state_nxt; + + +// Frontend State machine control signals +//---------------------------------------- + +wire exec_done = exec_jmp ? (e_state==E_JUMP) : + exec_dst_wr ? (e_state==E_DST_WR) : + exec_src_wr ? (e_state==E_SRC_WR) : (e_state==E_EXEC); + + +//============================================================================= +// 8) EXECUTION-UNIT STATE CONTROL +//============================================================================= + +// +// 8.1) ALU CONTROL SIGNALS +//------------------------------------- +// +// 12'b000000000001: Enable ALU source inverter +// 12'b000000000010: Enable Incrementer +// 12'b000000000100: Enable Incrementer on carry bit +// 12'b000000001000: Select Adder +// 12'b000000010000: Select AND +// 12'b000000100000: Select OR +// 12'b000001000000: Select XOR +// 12'b000010000000: Select DADD +// 12'b000100000000: Update N, Z & C (C=~Z) +// 12'b001000000000: Update all status bits +// 12'b010000000000: Update status bit for XOR instruction +// 12'b100000000000: Don't write to destination + +reg [11:0] inst_alu; + +wire alu_src_inv = inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_to_nxt[`BIC] ; + +wire alu_inc = inst_to_nxt[`SUB] | inst_to_nxt[`CMP]; + +wire alu_inc_c = inst_to_nxt[`ADDC] | inst_to_nxt[`DADD] | + inst_to_nxt[`SUBC]; + +wire alu_add = inst_to_nxt[`ADD] | inst_to_nxt[`ADDC] | + inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_type_nxt[`INST_JMP] | + inst_so_nxt[`RETI]; + + +wire alu_and = inst_to_nxt[`AND] | inst_to_nxt[`BIC] | + inst_to_nxt[`BIT]; + +wire alu_or = inst_to_nxt[`BIS]; + +wire alu_xor = inst_to_nxt[`XOR]; + +wire alu_dadd = inst_to_nxt[`DADD]; + +wire alu_stat_7 = inst_to_nxt[`BIT] | inst_to_nxt[`AND] | + inst_so_nxt[`SXT]; + +wire alu_stat_f = inst_to_nxt[`ADD] | inst_to_nxt[`ADDC] | + inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_to_nxt[`DADD] | + inst_to_nxt[`BIT] | inst_to_nxt[`XOR] | + inst_to_nxt[`AND] | + inst_so_nxt[`RRC] | inst_so_nxt[`RRA] | + inst_so_nxt[`SXT]; + +wire alu_shift = inst_so_nxt[`RRC] | inst_so_nxt[`RRA]; + +wire exec_no_wr = inst_to_nxt[`CMP] | inst_to_nxt[`BIT]; + +wire [11:0] inst_alu_nxt = {exec_no_wr, + alu_shift, + alu_stat_f, + alu_stat_7, + alu_dadd, + alu_xor, + alu_or, + alu_and, + alu_add, + alu_inc_c, + alu_inc, + alu_src_inv}; + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_alu <= 12'h000; +`ifdef CLOCK_GATING + else inst_alu <= inst_alu_nxt; +`else + else if (decode) inst_alu <= inst_alu_nxt; +`endif + + +endmodule // omsp_frontend + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_mem_backbone.v b/tests/openmsp430/rtl/omsp_mem_backbone.v new file mode 100644 index 00000000..299cbff8 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_mem_backbone.v @@ -0,0 +1,275 @@ +//---------------------------------------------------------------------------- +// 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_mem_backbone.v +// +// *Module Description: +// Memory interface backbone (decoder + arbiter) +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 151 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2012-07-23 00:24:11 +0200 (Mon, 23 Jul 2012) $ +//---------------------------------------------------------------------------- +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_defines.v" +`endif + +module omsp_mem_backbone ( + +// OUTPUTs + dbg_mem_din, // Debug unit Memory data input + dmem_addr, // Data Memory address + dmem_cen, // Data Memory chip enable (low active) + dmem_din, // Data Memory data input + dmem_wen, // Data Memory write enable (low active) + eu_mdb_in, // Execution Unit Memory data bus input + fe_mdb_in, // Frontend Memory data bus input + fe_pmem_wait, // Frontend wait for Instruction fetch + per_addr, // Peripheral address + per_din, // Peripheral data input + per_we, // Peripheral write enable (high active) + per_en, // Peripheral enable (high active) + pmem_addr, // Program Memory address + pmem_cen, // Program Memory chip enable (low active) + pmem_din, // Program Memory data input (optional) + pmem_wen, // Program Memory write enable (low active) (optional) + +// INPUTs + dbg_halt_st, // Halt/Run status from CPU + dbg_mem_addr, // Debug address for rd/wr access + dbg_mem_dout, // Debug unit data output + dbg_mem_en, // Debug unit memory enable + dbg_mem_wr, // Debug unit memory write + dmem_dout, // Data Memory data output + eu_mab, // Execution Unit Memory address bus + eu_mb_en, // Execution Unit Memory bus enable + eu_mb_wr, // Execution Unit Memory bus write transfer + eu_mdb_out, // Execution Unit Memory data bus output + fe_mab, // Frontend Memory address bus + fe_mb_en, // Frontend Memory bus enable + mclk, // Main system clock + per_dout, // Peripheral data output + pmem_dout, // Program Memory data output + puc_rst, // Main system reset + scan_enable // Scan enable (active during scan shifting) +); + +// OUTPUTs +//========= +output [15:0] dbg_mem_din; // Debug unit Memory data input +output [`DMEM_MSB:0] dmem_addr; // Data Memory address +output dmem_cen; // Data Memory chip enable (low active) +output [15:0] dmem_din; // Data Memory data input +output [1:0] dmem_wen; // Data Memory write enable (low active) +output [15:0] eu_mdb_in; // Execution Unit Memory data bus input +output [15:0] fe_mdb_in; // Frontend Memory data bus input +output fe_pmem_wait; // Frontend wait for Instruction fetch +output [13:0] per_addr; // Peripheral address +output [15:0] per_din; // Peripheral data input +output [1:0] per_we; // Peripheral write enable (high active) +output per_en; // Peripheral enable (high active) +output [`PMEM_MSB:0] pmem_addr; // Program Memory address +output pmem_cen; // Program Memory chip enable (low active) +output [15:0] pmem_din; // Program Memory data input (optional) +output [1:0] pmem_wen; // Program Memory write enable (low active) (optional) + +// INPUTs +//========= +input dbg_halt_st; // Halt/Run status from CPU +input [15:0] dbg_mem_addr; // Debug address for rd/wr access +input [15:0] dbg_mem_dout; // Debug unit data output +input dbg_mem_en; // Debug unit memory enable +input [1:0] dbg_mem_wr; // Debug unit memory write +input [15:0] dmem_dout; // Data Memory data output +input [14:0] eu_mab; // Execution Unit Memory address bus +input eu_mb_en; // Execution Unit Memory bus enable +input [1:0] eu_mb_wr; // Execution Unit Memory bus write transfer +input [15:0] eu_mdb_out; // Execution Unit Memory data bus output +input [14:0] fe_mab; // Frontend Memory address bus +input fe_mb_en; // Frontend Memory bus enable +input mclk; // Main system clock +input [15:0] per_dout; // Peripheral data output +input [15:0] pmem_dout; // Program Memory data output +input puc_rst; // Main system reset +input scan_enable; // Scan enable (active during scan shifting) + + +//============================================================================= +// 1) DECODER +//============================================================================= + +// RAM Interface +//------------------ + +// Execution unit access +wire eu_dmem_cen = ~(eu_mb_en & (eu_mab>=(`DMEM_BASE>>1)) & + (eu_mab<((`DMEM_BASE+`DMEM_SIZE)>>1))); +wire [15:0] eu_dmem_addr = {1'b0, eu_mab}-(`DMEM_BASE>>1); + +// Debug interface access +wire dbg_dmem_cen = ~(dbg_mem_en & (dbg_mem_addr[15:1]>=(`DMEM_BASE>>1)) & + (dbg_mem_addr[15:1]<((`DMEM_BASE+`DMEM_SIZE)>>1))); +wire [15:0] dbg_dmem_addr = {1'b0, dbg_mem_addr[15:1]}-(`DMEM_BASE>>1); + + +// RAM Interface +wire [`DMEM_MSB:0] dmem_addr = ~dbg_dmem_cen ? dbg_dmem_addr[`DMEM_MSB:0] : eu_dmem_addr[`DMEM_MSB:0]; +wire dmem_cen = dbg_dmem_cen & eu_dmem_cen; +wire [1:0] dmem_wen = ~(dbg_mem_wr | eu_mb_wr); +wire [15:0] dmem_din = ~dbg_dmem_cen ? dbg_mem_dout : eu_mdb_out; + + +// ROM Interface +//------------------ +parameter PMEM_OFFSET = (16'hFFFF-`PMEM_SIZE+1); + +// Execution unit access (only read access are accepted) +wire eu_pmem_cen = ~(eu_mb_en & ~|eu_mb_wr & (eu_mab>=(PMEM_OFFSET>>1))); +wire [15:0] eu_pmem_addr = eu_mab-(PMEM_OFFSET>>1); + +// Front-end access +wire fe_pmem_cen = ~(fe_mb_en & (fe_mab>=(PMEM_OFFSET>>1))); +wire [15:0] fe_pmem_addr = fe_mab-(PMEM_OFFSET>>1); + +// Debug interface access +wire dbg_pmem_cen = ~(dbg_mem_en & (dbg_mem_addr[15:1]>=(PMEM_OFFSET>>1))); +wire [15:0] dbg_pmem_addr = {1'b0, dbg_mem_addr[15:1]}-(PMEM_OFFSET>>1); + + +// ROM Interface (Execution unit has priority) +wire [`PMEM_MSB:0] pmem_addr = ~dbg_pmem_cen ? dbg_pmem_addr[`PMEM_MSB:0] : + ~eu_pmem_cen ? eu_pmem_addr[`PMEM_MSB:0] : fe_pmem_addr[`PMEM_MSB:0]; +wire pmem_cen = fe_pmem_cen & eu_pmem_cen & dbg_pmem_cen; +wire [1:0] pmem_wen = ~dbg_mem_wr; +wire [15:0] pmem_din = dbg_mem_dout; + +wire fe_pmem_wait = (~fe_pmem_cen & ~eu_pmem_cen); + + +// Peripherals +//-------------------- +wire dbg_per_en = dbg_mem_en & (dbg_mem_addr[15:1]<(`PER_SIZE>>1)); +wire eu_per_en = eu_mb_en & (eu_mab<(`PER_SIZE>>1)); + +wire [15:0] per_din = dbg_mem_en ? dbg_mem_dout : eu_mdb_out; +wire [1:0] per_we = dbg_mem_en ? dbg_mem_wr : eu_mb_wr; +wire per_en = dbg_mem_en ? dbg_per_en : eu_per_en; +wire [`PER_MSB:0] per_addr_mux = dbg_mem_en ? dbg_mem_addr[`PER_MSB+1:1] : eu_mab[`PER_MSB:0]; +wire [14:0] per_addr_ful = {{15-`PER_AWIDTH{1'b0}}, per_addr_mux}; +wire [13:0] per_addr = per_addr_ful[13:0]; + +reg [15:0] per_dout_val; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) per_dout_val <= 16'h0000; + else per_dout_val <= per_dout; + + +// Frontend data Mux +//--------------------------------- +// Whenever the frontend doesn't access the ROM, backup the data + +// Detect whenever the data should be backuped and restored +reg fe_pmem_cen_dly; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) fe_pmem_cen_dly <= 1'b0; + else fe_pmem_cen_dly <= fe_pmem_cen; + +wire fe_pmem_save = ( fe_pmem_cen & ~fe_pmem_cen_dly) & ~dbg_halt_st; +wire fe_pmem_restore = (~fe_pmem_cen & fe_pmem_cen_dly) | dbg_halt_st; + +`ifdef CLOCK_GATING +wire mclk_bckup; +omsp_clock_gate clock_gate_bckup (.gclk(mclk_bckup), + .clk (mclk), .enable(fe_pmem_save), .scan_enable(scan_enable)); +`else +wire mclk_bckup = mclk; +`endif + +reg [15:0] pmem_dout_bckup; +always @(posedge mclk_bckup or posedge puc_rst) + if (puc_rst) pmem_dout_bckup <= 16'h0000; +`ifdef CLOCK_GATING + else pmem_dout_bckup <= pmem_dout; +`else + else if (fe_pmem_save) pmem_dout_bckup <= pmem_dout; +`endif + +// Mux between the ROM data and the backup +reg pmem_dout_bckup_sel; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) pmem_dout_bckup_sel <= 1'b0; + else if (fe_pmem_save) pmem_dout_bckup_sel <= 1'b1; + else if (fe_pmem_restore) pmem_dout_bckup_sel <= 1'b0; + +assign fe_mdb_in = pmem_dout_bckup_sel ? pmem_dout_bckup : pmem_dout; + + +// Execution-Unit data Mux +//--------------------------------- + +// Select between peripherals, RAM and ROM +reg [1:0] eu_mdb_in_sel; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) eu_mdb_in_sel <= 2'b00; + else eu_mdb_in_sel <= {~eu_pmem_cen, per_en}; + +// Mux +assign eu_mdb_in = eu_mdb_in_sel[1] ? pmem_dout : + eu_mdb_in_sel[0] ? per_dout_val : dmem_dout; + +// Debug interface data Mux +//--------------------------------- + +// Select between peripherals, RAM and ROM +`ifdef DBG_EN +reg [1:0] dbg_mem_din_sel; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) dbg_mem_din_sel <= 2'b00; + else dbg_mem_din_sel <= {~dbg_pmem_cen, dbg_per_en}; + +`else +wire [1:0] dbg_mem_din_sel = 2'b00; +`endif + +// Mux +assign dbg_mem_din = dbg_mem_din_sel[1] ? pmem_dout : + dbg_mem_din_sel[0] ? per_dout_val : dmem_dout; + + +endmodule // omsp_mem_backbone + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_multiplier.v b/tests/openmsp430/rtl/omsp_multiplier.v new file mode 100644 index 00000000..4f7b04ca --- /dev/null +++ b/tests/openmsp430/rtl/omsp_multiplier.v @@ -0,0 +1,420 @@ +//---------------------------------------------------------------------------- +// 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_multiplier.v +// +// *Module Description: +// 16x16 Hardware multiplier. +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 23 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2009-08-30 18:39:26 +0200 (Sun, 30 Aug 2009) $ +//---------------------------------------------------------------------------- +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_defines.v" +`endif + +module omsp_multiplier ( + +// OUTPUTs + per_dout, // Peripheral data output + +// INPUTs + 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) + puc_rst, // Main system reset + scan_enable // Scan enable (active during scan shifting) +); + +// OUTPUTs +//========= +output [15:0] per_dout; // Peripheral data output + +// INPUTs +//========= +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 puc_rst; // Main system reset +input scan_enable; // Scan enable (active during scan shifting) + + +//============================================================================= +// 1) PARAMETER/REGISTERS & WIRE DECLARATION +//============================================================================= + +// Register base address (must be aligned to decoder bit width) +parameter [14:0] BASE_ADDR = 15'h0130; + +// Decoder bit width (defines how many bits are considered for address decoding) +parameter DEC_WD = 4; + +// Register addresses offset +parameter [DEC_WD-1:0] OP1_MPY = 'h0, + OP1_MPYS = 'h2, + OP1_MAC = 'h4, + OP1_MACS = 'h6, + OP2 = 'h8, + RESLO = 'hA, + RESHI = 'hC, + SUMEXT = 'hE; + +// 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] OP1_MPY_D = (BASE_REG << OP1_MPY), + OP1_MPYS_D = (BASE_REG << OP1_MPYS), + OP1_MAC_D = (BASE_REG << OP1_MAC), + OP1_MACS_D = (BASE_REG << OP1_MACS), + OP2_D = (BASE_REG << OP2), + RESLO_D = (BASE_REG << RESLO), + RESHI_D = (BASE_REG << RESHI), + SUMEXT_D = (BASE_REG << SUMEXT); + + +// Wire pre-declarations +wire result_wr; +wire result_clr; +wire early_read; + + +//============================================================================ +// 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 = (OP1_MPY_D & {DEC_SZ{(reg_addr == OP1_MPY )}}) | + (OP1_MPYS_D & {DEC_SZ{(reg_addr == OP1_MPYS )}}) | + (OP1_MAC_D & {DEC_SZ{(reg_addr == OP1_MAC )}}) | + (OP1_MACS_D & {DEC_SZ{(reg_addr == OP1_MACS )}}) | + (OP2_D & {DEC_SZ{(reg_addr == OP2 )}}) | + (RESLO_D & {DEC_SZ{(reg_addr == RESLO )}}) | + (RESHI_D & {DEC_SZ{(reg_addr == RESHI )}}) | + (SUMEXT_D & {DEC_SZ{(reg_addr == SUMEXT )}}); + +// 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 +//============================================================================ + +// OP1 Register +//----------------- +reg [15:0] op1; + +wire op1_wr = reg_wr[OP1_MPY] | + reg_wr[OP1_MPYS] | + reg_wr[OP1_MAC] | + reg_wr[OP1_MACS]; + +`ifdef CLOCK_GATING +wire mclk_op1; +omsp_clock_gate clock_gate_op1 (.gclk(mclk_op1), + .clk (mclk), .enable(op1_wr), .scan_enable(scan_enable)); +`else +wire mclk_op1 = mclk; +`endif + +always @ (posedge mclk_op1 or posedge puc_rst) + if (puc_rst) op1 <= 16'h0000; +`ifdef CLOCK_GATING + else op1 <= per_din; +`else + else if (op1_wr) op1 <= per_din; +`endif + +wire [15:0] op1_rd = op1; + + +// OP2 Register +//----------------- +reg [15:0] op2; + +wire op2_wr = reg_wr[OP2]; + +`ifdef CLOCK_GATING +wire mclk_op2; +omsp_clock_gate clock_gate_op2 (.gclk(mclk_op2), + .clk (mclk), .enable(op2_wr), .scan_enable(scan_enable)); +`else +wire mclk_op2 = mclk; +`endif + +always @ (posedge mclk_op2 or posedge puc_rst) + if (puc_rst) op2 <= 16'h0000; +`ifdef CLOCK_GATING + else op2 <= per_din; +`else + else if (op2_wr) op2 <= per_din; +`endif + +wire [15:0] op2_rd = op2; + + +// RESLO Register +//----------------- +reg [15:0] reslo; + +wire [15:0] reslo_nxt; +wire reslo_wr = reg_wr[RESLO]; + +`ifdef CLOCK_GATING +wire reslo_en = reslo_wr | result_clr | result_wr; +wire mclk_reslo; +omsp_clock_gate clock_gate_reslo (.gclk(mclk_reslo), + .clk (mclk), .enable(reslo_en), .scan_enable(scan_enable)); +`else +wire mclk_reslo = mclk; +`endif + +always @ (posedge mclk_reslo or posedge puc_rst) + if (puc_rst) reslo <= 16'h0000; + else if (reslo_wr) reslo <= per_din; + else if (result_clr) reslo <= 16'h0000; +`ifdef CLOCK_GATING + else reslo <= reslo_nxt; +`else + else if (result_wr) reslo <= reslo_nxt; +`endif + +wire [15:0] reslo_rd = early_read ? reslo_nxt : reslo; + + +// RESHI Register +//----------------- +reg [15:0] reshi; + +wire [15:0] reshi_nxt; +wire reshi_wr = reg_wr[RESHI]; + +`ifdef CLOCK_GATING +wire reshi_en = reshi_wr | result_clr | result_wr; +wire mclk_reshi; +omsp_clock_gate clock_gate_reshi (.gclk(mclk_reshi), + .clk (mclk), .enable(reshi_en), .scan_enable(scan_enable)); +`else +wire mclk_reshi = mclk; +`endif + +always @ (posedge mclk_reshi or posedge puc_rst) + if (puc_rst) reshi <= 16'h0000; + else if (reshi_wr) reshi <= per_din; + else if (result_clr) reshi <= 16'h0000; +`ifdef CLOCK_GATING + else reshi <= reshi_nxt; +`else + else if (result_wr) reshi <= reshi_nxt; +`endif + +wire [15:0] reshi_rd = early_read ? reshi_nxt : reshi; + + +// SUMEXT Register +//----------------- +reg [1:0] sumext_s; + +wire [1:0] sumext_s_nxt; + +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) sumext_s <= 2'b00; + else if (op2_wr) sumext_s <= 2'b00; + else if (result_wr) sumext_s <= sumext_s_nxt; + +wire [15:0] sumext_nxt = {{14{sumext_s_nxt[1]}}, sumext_s_nxt}; +wire [15:0] sumext = {{14{sumext_s[1]}}, sumext_s}; +wire [15:0] sumext_rd = early_read ? sumext_nxt : sumext; + + +//============================================================================ +// 4) DATA OUTPUT GENERATION +//============================================================================ + +// Data output mux +wire [15:0] op1_mux = op1_rd & {16{reg_rd[OP1_MPY] | + reg_rd[OP1_MPYS] | + reg_rd[OP1_MAC] | + reg_rd[OP1_MACS]}}; +wire [15:0] op2_mux = op2_rd & {16{reg_rd[OP2]}}; +wire [15:0] reslo_mux = reslo_rd & {16{reg_rd[RESLO]}}; +wire [15:0] reshi_mux = reshi_rd & {16{reg_rd[RESHI]}}; +wire [15:0] sumext_mux = sumext_rd & {16{reg_rd[SUMEXT]}}; + +wire [15:0] per_dout = op1_mux | + op2_mux | + reslo_mux | + reshi_mux | + sumext_mux; + + +//============================================================================ +// 5) HARDWARE MULTIPLIER FUNCTIONAL LOGIC +//============================================================================ + +// Multiplier configuration +//-------------------------- + +// Detect signed mode +reg sign_sel; +always @ (posedge mclk_op1 or posedge puc_rst) + if (puc_rst) sign_sel <= 1'b0; +`ifdef CLOCK_GATING + else sign_sel <= reg_wr[OP1_MPYS] | reg_wr[OP1_MACS]; +`else + else if (op1_wr) sign_sel <= reg_wr[OP1_MPYS] | reg_wr[OP1_MACS]; +`endif + + +// Detect accumulate mode +reg acc_sel; +always @ (posedge mclk_op1 or posedge puc_rst) + if (puc_rst) acc_sel <= 1'b0; +`ifdef CLOCK_GATING + else acc_sel <= reg_wr[OP1_MAC] | reg_wr[OP1_MACS]; +`else + else if (op1_wr) acc_sel <= reg_wr[OP1_MAC] | reg_wr[OP1_MACS]; +`endif + + +// Detect whenever the RESHI and RESLO registers should be cleared +assign result_clr = op2_wr & ~acc_sel; + +// Combine RESHI & RESLO +wire [31:0] result = {reshi, reslo}; + + +// 16x16 Multiplier (result computed in 1 clock cycle) +//----------------------------------------------------- +`ifdef MPY_16x16 + +// Detect start of a multiplication +reg cycle; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) cycle <= 1'b0; + else cycle <= op2_wr; + +assign result_wr = cycle; + +// Expand the operands to support signed & unsigned operations +wire signed [16:0] op1_xp = {sign_sel & op1[15], op1}; +wire signed [16:0] op2_xp = {sign_sel & op2[15], op2}; + + +// 17x17 signed multiplication +wire signed [33:0] product = op1_xp * op2_xp; + +// Accumulate +wire [32:0] result_nxt = {1'b0, result} + {1'b0, product[31:0]}; + + +// Next register values +assign reslo_nxt = result_nxt[15:0]; +assign reshi_nxt = result_nxt[31:16]; +assign sumext_s_nxt = sign_sel ? {2{result_nxt[31]}} : + {1'b0, result_nxt[32]}; + + +// Since the MAC is completed within 1 clock cycle, +// an early read can't happen. +assign early_read = 1'b0; + + +// 16x8 Multiplier (result computed in 2 clock cycles) +//----------------------------------------------------- +`else + +// Detect start of a multiplication +reg [1:0] cycle; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) cycle <= 2'b00; + else cycle <= {cycle[0], op2_wr}; + +assign result_wr = |cycle; + + +// Expand the operands to support signed & unsigned operations +wire signed [16:0] op1_xp = {sign_sel & op1[15], op1}; +wire signed [8:0] op2_hi_xp = {sign_sel & op2[15], op2[15:8]}; +wire signed [8:0] op2_lo_xp = { 1'b0, op2[7:0]}; +wire signed [8:0] op2_xp = cycle[0] ? op2_hi_xp : op2_lo_xp; + + +// 17x9 signed multiplication +wire signed [25:0] product = op1_xp * op2_xp; + +wire [31:0] product_xp = cycle[0] ? {product[23:0], 8'h00} : + {{8{sign_sel & product[23]}}, product[23:0]}; + +// Accumulate +wire [32:0] result_nxt = {1'b0, result} + {1'b0, product_xp[31:0]}; + + +// Next register values +assign reslo_nxt = result_nxt[15:0]; +assign reshi_nxt = result_nxt[31:16]; +assign sumext_s_nxt = sign_sel ? {2{result_nxt[31]}} : + {1'b0, result_nxt[32] | sumext_s[0]}; + +// Since the MAC is completed within 2 clock cycle, +// an early read can happen during the second cycle. +assign early_read = cycle[1]; + +`endif + + +endmodule // omsp_multiplier + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_register_file.v b/tests/openmsp430/rtl/omsp_register_file.v new file mode 100644 index 00000000..2ccd2499 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_register_file.v @@ -0,0 +1,618 @@ +//---------------------------------------------------------------------------- +// 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_register_file.v +// +// *Module Description: +// openMSP430 Register files +// +// *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_register_file ( + +// OUTPUTs + cpuoff, // Turns off the CPU + gie, // General interrupt enable + oscoff, // Turns off LFXT1 clock input + pc_sw, // Program counter software value + pc_sw_wr, // Program counter software write + reg_dest, // Selected register destination content + reg_src, // Selected register source content + scg0, // System clock generator 1. Turns off the DCO + scg1, // System clock generator 1. Turns off the SMCLK + status, // R2 Status {V,N,Z,C} + +// INPUTs + alu_stat, // ALU Status {V,N,Z,C} + alu_stat_wr, // ALU Status write {V,N,Z,C} + inst_bw, // Decoded Inst: byte width + inst_dest, // Register destination selection + inst_src, // Register source selection + mclk, // Main system clock + pc, // Program counter + puc_rst, // Main system reset + reg_dest_val, // Selected register destination value + reg_dest_wr, // Write selected register destination + reg_pc_call, // Trigger PC update for a CALL instruction + reg_sp_val, // Stack Pointer next value + reg_sp_wr, // Stack Pointer write + reg_sr_wr, // Status register update for RETI instruction + reg_sr_clr, // Status register clear for interrupts + reg_incr, // Increment source register + scan_enable // Scan enable (active during scan shifting) +); + +// OUTPUTs +//========= +output cpuoff; // Turns off the CPU +output gie; // General interrupt enable +output oscoff; // Turns off LFXT1 clock input +output [15:0] pc_sw; // Program counter software value +output pc_sw_wr; // Program counter software write +output [15:0] reg_dest; // Selected register destination content +output [15:0] reg_src; // Selected register source content +output scg0; // System clock generator 1. Turns off the DCO +output scg1; // System clock generator 1. Turns off the SMCLK +output [3:0] status; // R2 Status {V,N,Z,C} + +// INPUTs +//========= +input [3:0] alu_stat; // ALU Status {V,N,Z,C} +input [3:0] alu_stat_wr; // ALU Status write {V,N,Z,C} +input inst_bw; // Decoded Inst: byte width +input [15:0] inst_dest; // Register destination selection +input [15:0] inst_src; // Register source selection +input mclk; // Main system clock +input [15:0] pc; // Program counter +input puc_rst; // Main system reset +input [15:0] reg_dest_val; // Selected register destination value +input reg_dest_wr; // Write selected register destination +input reg_pc_call; // Trigger PC update for a CALL instruction +input [15:0] reg_sp_val; // Stack Pointer next value +input reg_sp_wr; // Stack Pointer write +input reg_sr_wr; // Status register update for RETI instruction +input reg_sr_clr; // Status register clear for interrupts +input reg_incr; // Increment source register +input scan_enable; // Scan enable (active during scan shifting) + + +//============================================================================= +// 1) AUTOINCREMENT UNIT +//============================================================================= + +wire [15:0] inst_src_in; +wire [15:0] incr_op = (inst_bw & ~inst_src_in[1]) ? 16'h0001 : 16'h0002; +wire [15:0] reg_incr_val = reg_src+incr_op; + +wire [15:0] reg_dest_val_in = inst_bw ? {8'h00,reg_dest_val[7:0]} : reg_dest_val; + + +//============================================================================= +// 2) SPECIAL REGISTERS (R1/R2/R3) +//============================================================================= + +// Source input selection mask (for interrupt support) +//----------------------------------------------------- + +assign inst_src_in = reg_sr_clr ? 16'h0004 : inst_src; + + +// R0: Program counter +//--------------------- + +wire [15:0] r0 = pc; + +wire [15:0] pc_sw = reg_dest_val_in; +wire pc_sw_wr = (inst_dest[0] & reg_dest_wr) | reg_pc_call; + + +// R1: Stack pointer +//------------------- +reg [15:0] r1; +wire r1_wr = inst_dest[1] & reg_dest_wr; +wire r1_inc = inst_src_in[1] & reg_incr; + +`ifdef CLOCK_GATING +wire r1_en = r1_wr | reg_sp_wr | r1_inc; +wire mclk_r1; +omsp_clock_gate clock_gate_r1 (.gclk(mclk_r1), + .clk (mclk), .enable(r1_en), .scan_enable(scan_enable)); +`else +wire mclk_r1 = mclk; +`endif + +always @(posedge mclk_r1 or posedge puc_rst) + if (puc_rst) r1 <= 16'h0000; + else if (r1_wr) r1 <= reg_dest_val_in & 16'hfffe; + else if (reg_sp_wr) r1 <= reg_sp_val & 16'hfffe; +`ifdef CLOCK_GATING + else r1 <= reg_incr_val & 16'hfffe; +`else + else if (r1_inc) r1 <= reg_incr_val & 16'hfffe; +`endif + + +// R2: Status register +//--------------------- +reg [15:0] r2; +wire r2_wr = (inst_dest[2] & reg_dest_wr) | reg_sr_wr; + +`ifdef CLOCK_GATING // -- WITH CLOCK GATING -- +wire r2_c = alu_stat_wr[0] ? alu_stat[0] : reg_dest_val_in[0]; // C + +wire r2_z = alu_stat_wr[1] ? alu_stat[1] : reg_dest_val_in[1]; // Z + +wire r2_n = alu_stat_wr[2] ? alu_stat[2] : reg_dest_val_in[2]; // N + +wire [7:3] r2_nxt = r2_wr ? reg_dest_val_in[7:3] : r2[7:3]; + +wire r2_v = alu_stat_wr[3] ? alu_stat[3] : reg_dest_val_in[8]; // V + +wire r2_en = |alu_stat_wr | r2_wr | reg_sr_clr; +wire mclk_r2; +omsp_clock_gate clock_gate_r2 (.gclk(mclk_r2), + .clk (mclk), .enable(r2_en), .scan_enable(scan_enable)); + +`else // -- WITHOUT CLOCK GATING -- +wire r2_c = alu_stat_wr[0] ? alu_stat[0] : + r2_wr ? reg_dest_val_in[0] : r2[0]; // C + +wire r2_z = alu_stat_wr[1] ? alu_stat[1] : + r2_wr ? reg_dest_val_in[1] : r2[1]; // Z + +wire r2_n = alu_stat_wr[2] ? alu_stat[2] : + r2_wr ? reg_dest_val_in[2] : r2[2]; // N + +wire [7:3] r2_nxt = r2_wr ? reg_dest_val_in[7:3] : r2[7:3]; + +wire r2_v = alu_stat_wr[3] ? alu_stat[3] : + r2_wr ? reg_dest_val_in[8] : r2[8]; // V + + +wire mclk_r2 = mclk; +`endif + +`ifdef ASIC + `ifdef CPUOFF_EN + wire [15:0] cpuoff_mask = 16'h0010; + `else + wire [15:0] cpuoff_mask = 16'h0000; + `endif + `ifdef OSCOFF_EN + wire [15:0] oscoff_mask = 16'h0020; + `else + wire [15:0] oscoff_mask = 16'h0000; + `endif + `ifdef SCG0_EN + wire [15:0] scg0_mask = 16'h0040; + `else + wire [15:0] scg0_mask = 16'h0000; + `endif + `ifdef SCG1_EN + wire [15:0] scg1_mask = 16'h0080; + `else + wire [15:0] scg1_mask = 16'h0000; + `endif +`else + wire [15:0] cpuoff_mask = 16'h0010; // For the FPGA version: - the CPUOFF mode is emulated + wire [15:0] oscoff_mask = 16'h0020; // - the SCG1 mode is emulated + wire [15:0] scg0_mask = 16'h0000; // - the SCG0 is not supported + wire [15:0] scg1_mask = 16'h0080; // - the SCG1 mode is emulated +`endif + + wire [15:0] r2_mask = cpuoff_mask | oscoff_mask | scg0_mask | scg1_mask | 16'h010f; + +always @(posedge mclk_r2 or posedge puc_rst) + if (puc_rst) r2 <= 16'h0000; + else if (reg_sr_clr) r2 <= 16'h0000; + else r2 <= {7'h00, r2_v, r2_nxt, r2_n, r2_z, r2_c} & r2_mask; + +assign status = {r2[8], r2[2:0]}; +assign gie = r2[3]; +assign cpuoff = r2[4] | (r2_nxt[4] & r2_wr & cpuoff_mask[4]); +assign oscoff = r2[5]; +assign scg0 = r2[6]; +assign scg1 = r2[7]; + + +// R3: Constant generator +//------------------------------------------------------------- +// Note: the auto-increment feature is not implemented for R3 +// because the @R3+ addressing mode is used for constant +// generation (#-1). +reg [15:0] r3; +wire r3_wr = inst_dest[3] & reg_dest_wr; + +`ifdef CLOCK_GATING +wire r3_en = r3_wr; +wire mclk_r3; +omsp_clock_gate clock_gate_r3 (.gclk(mclk_r3), + .clk (mclk), .enable(r3_en), .scan_enable(scan_enable)); +`else +wire mclk_r3 = mclk; +`endif + +always @(posedge mclk_r3 or posedge puc_rst) + if (puc_rst) r3 <= 16'h0000; +`ifdef CLOCK_GATING + else r3 <= reg_dest_val_in; +`else + else if (r3_wr) r3 <= reg_dest_val_in; +`endif + + +//============================================================================= +// 4) GENERAL PURPOSE REGISTERS (R4...R15) +//============================================================================= + +// R4 +//------------ +reg [15:0] r4; +wire r4_wr = inst_dest[4] & reg_dest_wr; +wire r4_inc = inst_src_in[4] & reg_incr; + +`ifdef CLOCK_GATING +wire r4_en = r4_wr | r4_inc; +wire mclk_r4; +omsp_clock_gate clock_gate_r4 (.gclk(mclk_r4), + .clk (mclk), .enable(r4_en), .scan_enable(scan_enable)); +`else +wire mclk_r4 = mclk; +`endif + +always @(posedge mclk_r4 or posedge puc_rst) + if (puc_rst) r4 <= 16'h0000; + else if (r4_wr) r4 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r4 <= reg_incr_val; +`else + else if (r4_inc) r4 <= reg_incr_val; +`endif + +// R5 +//------------ +reg [15:0] r5; +wire r5_wr = inst_dest[5] & reg_dest_wr; +wire r5_inc = inst_src_in[5] & reg_incr; + +`ifdef CLOCK_GATING +wire r5_en = r5_wr | r5_inc; +wire mclk_r5; +omsp_clock_gate clock_gate_r5 (.gclk(mclk_r5), + .clk (mclk), .enable(r5_en), .scan_enable(scan_enable)); +`else +wire mclk_r5 = mclk; +`endif + +always @(posedge mclk_r5 or posedge puc_rst) + if (puc_rst) r5 <= 16'h0000; + else if (r5_wr) r5 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r5 <= reg_incr_val; +`else + else if (r5_inc) r5 <= reg_incr_val; +`endif + +// R6 +//------------ +reg [15:0] r6; +wire r6_wr = inst_dest[6] & reg_dest_wr; +wire r6_inc = inst_src_in[6] & reg_incr; + +`ifdef CLOCK_GATING +wire r6_en = r6_wr | r6_inc; +wire mclk_r6; +omsp_clock_gate clock_gate_r6 (.gclk(mclk_r6), + .clk (mclk), .enable(r6_en), .scan_enable(scan_enable)); +`else +wire mclk_r6 = mclk; +`endif + +always @(posedge mclk_r6 or posedge puc_rst) + if (puc_rst) r6 <= 16'h0000; + else if (r6_wr) r6 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r6 <= reg_incr_val; +`else + else if (r6_inc) r6 <= reg_incr_val; +`endif + +// R7 +//------------ +reg [15:0] r7; +wire r7_wr = inst_dest[7] & reg_dest_wr; +wire r7_inc = inst_src_in[7] & reg_incr; + +`ifdef CLOCK_GATING +wire r7_en = r7_wr | r7_inc; +wire mclk_r7; +omsp_clock_gate clock_gate_r7 (.gclk(mclk_r7), + .clk (mclk), .enable(r7_en), .scan_enable(scan_enable)); +`else +wire mclk_r7 = mclk; +`endif + +always @(posedge mclk_r7 or posedge puc_rst) + if (puc_rst) r7 <= 16'h0000; + else if (r7_wr) r7 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r7 <= reg_incr_val; +`else + else if (r7_inc) r7 <= reg_incr_val; +`endif + +// R8 +//------------ +reg [15:0] r8; +wire r8_wr = inst_dest[8] & reg_dest_wr; +wire r8_inc = inst_src_in[8] & reg_incr; + +`ifdef CLOCK_GATING +wire r8_en = r8_wr | r8_inc; +wire mclk_r8; +omsp_clock_gate clock_gate_r8 (.gclk(mclk_r8), + .clk (mclk), .enable(r8_en), .scan_enable(scan_enable)); +`else +wire mclk_r8 = mclk; +`endif + +always @(posedge mclk_r8 or posedge puc_rst) + if (puc_rst) r8 <= 16'h0000; + else if (r8_wr) r8 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r8 <= reg_incr_val; +`else + else if (r8_inc) r8 <= reg_incr_val; +`endif + +// R9 +//------------ +reg [15:0] r9; +wire r9_wr = inst_dest[9] & reg_dest_wr; +wire r9_inc = inst_src_in[9] & reg_incr; + +`ifdef CLOCK_GATING +wire r9_en = r9_wr | r9_inc; +wire mclk_r9; +omsp_clock_gate clock_gate_r9 (.gclk(mclk_r9), + .clk (mclk), .enable(r9_en), .scan_enable(scan_enable)); +`else +wire mclk_r9 = mclk; +`endif + +always @(posedge mclk_r9 or posedge puc_rst) + if (puc_rst) r9 <= 16'h0000; + else if (r9_wr) r9 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r9 <= reg_incr_val; +`else + else if (r9_inc) r9 <= reg_incr_val; +`endif + +// R10 +//------------ +reg [15:0] r10; +wire r10_wr = inst_dest[10] & reg_dest_wr; +wire r10_inc = inst_src_in[10] & reg_incr; + +`ifdef CLOCK_GATING +wire r10_en = r10_wr | r10_inc; +wire mclk_r10; +omsp_clock_gate clock_gate_r10 (.gclk(mclk_r10), + .clk (mclk), .enable(r10_en), .scan_enable(scan_enable)); +`else +wire mclk_r10 = mclk; +`endif + +always @(posedge mclk_r10 or posedge puc_rst) + if (puc_rst) r10 <= 16'h0000; + else if (r10_wr) r10 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r10 <= reg_incr_val; +`else + else if (r10_inc) r10 <= reg_incr_val; +`endif + +// R11 +//------------ +reg [15:0] r11; +wire r11_wr = inst_dest[11] & reg_dest_wr; +wire r11_inc = inst_src_in[11] & reg_incr; + +`ifdef CLOCK_GATING +wire r11_en = r11_wr | r11_inc; +wire mclk_r11; +omsp_clock_gate clock_gate_r11 (.gclk(mclk_r11), + .clk (mclk), .enable(r11_en), .scan_enable(scan_enable)); +`else +wire mclk_r11 = mclk; +`endif + +always @(posedge mclk_r11 or posedge puc_rst) + if (puc_rst) r11 <= 16'h0000; + else if (r11_wr) r11 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r11 <= reg_incr_val; +`else + else if (r11_inc) r11 <= reg_incr_val; +`endif + +// R12 +//------------ +reg [15:0] r12; +wire r12_wr = inst_dest[12] & reg_dest_wr; +wire r12_inc = inst_src_in[12] & reg_incr; + +`ifdef CLOCK_GATING +wire r12_en = r12_wr | r12_inc; +wire mclk_r12; +omsp_clock_gate clock_gate_r12 (.gclk(mclk_r12), + .clk (mclk), .enable(r12_en), .scan_enable(scan_enable)); +`else +wire mclk_r12 = mclk; +`endif + +always @(posedge mclk_r12 or posedge puc_rst) + if (puc_rst) r12 <= 16'h0000; + else if (r12_wr) r12 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r12 <= reg_incr_val; +`else + else if (r12_inc) r12 <= reg_incr_val; +`endif + +// R13 +//------------ +reg [15:0] r13; +wire r13_wr = inst_dest[13] & reg_dest_wr; +wire r13_inc = inst_src_in[13] & reg_incr; + +`ifdef CLOCK_GATING +wire r13_en = r13_wr | r13_inc; +wire mclk_r13; +omsp_clock_gate clock_gate_r13 (.gclk(mclk_r13), + .clk (mclk), .enable(r13_en), .scan_enable(scan_enable)); +`else +wire mclk_r13 = mclk; +`endif + +always @(posedge mclk_r13 or posedge puc_rst) + if (puc_rst) r13 <= 16'h0000; + else if (r13_wr) r13 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r13 <= reg_incr_val; +`else + else if (r13_inc) r13 <= reg_incr_val; +`endif + +// R14 +//------------ +reg [15:0] r14; +wire r14_wr = inst_dest[14] & reg_dest_wr; +wire r14_inc = inst_src_in[14] & reg_incr; + +`ifdef CLOCK_GATING +wire r14_en = r14_wr | r14_inc; +wire mclk_r14; +omsp_clock_gate clock_gate_r14 (.gclk(mclk_r14), + .clk (mclk), .enable(r14_en), .scan_enable(scan_enable)); +`else +wire mclk_r14 = mclk; +`endif + +always @(posedge mclk_r14 or posedge puc_rst) + if (puc_rst) r14 <= 16'h0000; + else if (r14_wr) r14 <= reg_dest_val_in; +`ifdef CLOCK_GATING + else r14 <= reg_incr_val; +`else + else if (r14_inc) r14 <= reg_incr_val; +`endif + +// R15 +//------------ +reg [15:0] r15; +wire r15_wr = inst_dest[15] & reg_dest_wr; +wire r15_inc = inst_src_in[15] & reg_incr; + +`ifdef CLOCK_GATING +wire r15_en = r15_wr | r15_inc; +wire mclk_r15; +omsp_clock_gate clock_gate_r15 (.gclk(mclk_r15), + .clk (mclk), .enable(r15_en), .scan_enable(scan_enable)); +`else +wire mclk_r15 = mclk; +`endif + +always @(posedge mclk_r15 or posedge puc_rst) + if (puc_rst) r15 <= 16'h0000; + else if (r15_wr) r15 <= reg_dest_val_in; + `ifdef CLOCK_GATING + else r15 <= reg_incr_val; +`else + else if (r15_inc) r15 <= reg_incr_val; +`endif + + +//============================================================================= +// 5) READ MUX +//============================================================================= + +assign reg_src = (r0 & {16{inst_src_in[0]}}) | + (r1 & {16{inst_src_in[1]}}) | + (r2 & {16{inst_src_in[2]}}) | + (r3 & {16{inst_src_in[3]}}) | + (r4 & {16{inst_src_in[4]}}) | + (r5 & {16{inst_src_in[5]}}) | + (r6 & {16{inst_src_in[6]}}) | + (r7 & {16{inst_src_in[7]}}) | + (r8 & {16{inst_src_in[8]}}) | + (r9 & {16{inst_src_in[9]}}) | + (r10 & {16{inst_src_in[10]}}) | + (r11 & {16{inst_src_in[11]}}) | + (r12 & {16{inst_src_in[12]}}) | + (r13 & {16{inst_src_in[13]}}) | + (r14 & {16{inst_src_in[14]}}) | + (r15 & {16{inst_src_in[15]}}); + +assign reg_dest = (r0 & {16{inst_dest[0]}}) | + (r1 & {16{inst_dest[1]}}) | + (r2 & {16{inst_dest[2]}}) | + (r3 & {16{inst_dest[3]}}) | + (r4 & {16{inst_dest[4]}}) | + (r5 & {16{inst_dest[5]}}) | + (r6 & {16{inst_dest[6]}}) | + (r7 & {16{inst_dest[7]}}) | + (r8 & {16{inst_dest[8]}}) | + (r9 & {16{inst_dest[9]}}) | + (r10 & {16{inst_dest[10]}}) | + (r11 & {16{inst_dest[11]}}) | + (r12 & {16{inst_dest[12]}}) | + (r13 & {16{inst_dest[13]}}) | + (r14 & {16{inst_dest[14]}}) | + (r15 & {16{inst_dest[15]}}); + + +endmodule // omsp_register_file + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_scan_mux.v b/tests/openmsp430/rtl/omsp_scan_mux.v new file mode 100644 index 00000000..9a906474 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_scan_mux.v @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------- +// 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_scan_mux.v +// +// *Module Description: +// Generic mux for scan mode +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_scan_mux ( + +// OUTPUTs + data_out, // Scan mux data output + +// INPUTs + data_in_scan, // Selected data input for scan mode + data_in_func, // Selected data input for functional mode + scan_mode // Scan mode +); + +// OUTPUTs +//========= +output data_out; // Scan mux data output + +// INPUTs +//========= +input data_in_scan; // Selected data input for scan mode +input data_in_func; // Selected data input for functional mode +input scan_mode; // Scan mode + + +//============================================================================= +// 1) SCAN MUX +//============================================================================= + +assign data_out = scan_mode ? data_in_scan : data_in_func; + + +endmodule // omsp_scan_mux + + diff --git a/tests/openmsp430/rtl/omsp_sfr.v b/tests/openmsp430/rtl/omsp_sfr.v new file mode 100644 index 00000000..bc8c11a5 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_sfr.v @@ -0,0 +1,353 @@ +//---------------------------------------------------------------------------- +// 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_sfr.v +// +// *Module Description: +// Processor Special function register +// Non-Maskable Interrupt generation +// +// *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_sfr ( + +// OUTPUTs + cpu_id, // CPU ID + nmi_pnd, // NMI Pending + nmi_wkup, // NMI Wakeup + per_dout, // Peripheral data output + wdtie, // Watchdog-timer interrupt enable + wdtifg_sw_clr, // Watchdog-timer interrupt flag software clear + wdtifg_sw_set, // Watchdog-timer interrupt flag software set + +// INPUTs + mclk, // Main system clock + nmi, // Non-maskable interrupt (asynchronous) + nmi_acc, // Non-Maskable interrupt request accepted + per_addr, // Peripheral address + per_din, // Peripheral data input + per_en, // Peripheral enable (high active) + per_we, // Peripheral write enable (high active) + puc_rst, // Main system reset + scan_mode, // Scan mode + wdtifg, // Watchdog-timer interrupt flag + wdtnmies // Watchdog-timer NMI edge selection +); + +// OUTPUTs +//========= +output [31:0] cpu_id; // CPU ID +output nmi_pnd; // NMI Pending +output nmi_wkup; // NMI Wakeup +output [15:0] per_dout; // Peripheral data output +output wdtie; // Watchdog-timer interrupt enable +output wdtifg_sw_clr;// Watchdog-timer interrupt flag software clear +output wdtifg_sw_set;// Watchdog-timer interrupt flag software set + +// INPUTs +//========= +input mclk; // Main system clock +input nmi; // Non-maskable interrupt (asynchronous) +input nmi_acc; // Non-Maskable interrupt request accepted +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 puc_rst; // Main system reset +input scan_mode; // Scan mode +input wdtifg; // Watchdog-timer interrupt flag +input wdtnmies; // Watchdog-timer NMI edge selection + + +//============================================================================= +// 1) PARAMETER DECLARATION +//============================================================================= + +// Register base address (must be aligned to decoder bit width) +parameter [14:0] BASE_ADDR = 15'h0000; + +// Decoder bit width (defines how many bits are considered for address decoding) +parameter DEC_WD = 3; + +// Register addresses offset +parameter [DEC_WD-1:0] IE1 = 'h0, + IFG1 = 'h2, + CPU_ID_LO = 'h4, + CPU_ID_HI = 'h6; + +// 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] IE1_D = (BASE_REG << IE1), + IFG1_D = (BASE_REG << IFG1), + CPU_ID_LO_D = (BASE_REG << CPU_ID_LO), + CPU_ID_HI_D = (BASE_REG << CPU_ID_HI); + + +//============================================================================ +// 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 = {1'b0, per_addr[DEC_WD-2:0]}; + +// Register address decode +wire [DEC_SZ-1:0] reg_dec = (IE1_D & {DEC_SZ{(reg_addr==(IE1 >>1))}}) | + (IFG1_D & {DEC_SZ{(reg_addr==(IFG1 >>1))}}) | + (CPU_ID_LO_D & {DEC_SZ{(reg_addr==(CPU_ID_LO >>1))}}) | + (CPU_ID_HI_D & {DEC_SZ{(reg_addr==(CPU_ID_HI >>1))}}); + +// Read/Write probes +wire reg_lo_write = per_we[0] & reg_sel; +wire reg_hi_write = per_we[1] & reg_sel; +wire reg_read = ~|per_we & reg_sel; + +// Read/Write vectors +wire [DEC_SZ-1:0] reg_hi_wr = reg_dec & {DEC_SZ{reg_hi_write}}; +wire [DEC_SZ-1:0] reg_lo_wr = reg_dec & {DEC_SZ{reg_lo_write}}; +wire [DEC_SZ-1:0] reg_rd = reg_dec & {DEC_SZ{reg_read}}; + + +//============================================================================ +// 3) REGISTERS +//============================================================================ + +// IE1 Register +//-------------- +wire [7:0] ie1; +wire ie1_wr = IE1[0] ? reg_hi_wr[IE1] : reg_lo_wr[IE1]; +wire [7:0] ie1_nxt = IE1[0] ? per_din[15:8] : per_din[7:0]; + +`ifdef NMI +reg nmie; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) nmie <= 1'b0; + else if (nmi_acc) nmie <= 1'b0; + else if (ie1_wr) nmie <= ie1_nxt[4]; +`else +wire nmie = 1'b0; +`endif + +`ifdef WATCHDOG +reg wdtie; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) wdtie <= 1'b0; + else if (ie1_wr) wdtie <= ie1_nxt[0]; +`else +wire wdtie = 1'b0; +`endif + +assign ie1 = {3'b000, nmie, 3'b000, wdtie}; + + +// IFG1 Register +//--------------- +wire [7:0] ifg1; + +wire ifg1_wr = IFG1[0] ? reg_hi_wr[IFG1] : reg_lo_wr[IFG1]; +wire [7:0] ifg1_nxt = IFG1[0] ? per_din[15:8] : per_din[7:0]; + +`ifdef NMI +reg nmiifg; +wire nmi_edge; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) nmiifg <= 1'b0; + else if (nmi_edge) nmiifg <= 1'b1; + else if (ifg1_wr) nmiifg <= ifg1_nxt[4]; +`else +wire nmiifg = 1'b0; +`endif + +`ifdef WATCHDOG +assign wdtifg_sw_clr = ifg1_wr & ~ifg1_nxt[0]; +assign wdtifg_sw_set = ifg1_wr & ifg1_nxt[0]; +`else +assign wdtifg_sw_clr = 1'b0; +assign wdtifg_sw_set = 1'b0; +`endif + +assign ifg1 = {3'b000, nmiifg, 3'b000, wdtifg}; + + +// CPU_ID Register (READ ONLY) +//----------------------------- +// ------------------------------------------------------------------- +// CPU_ID_LO: | 15 14 13 12 11 10 9 | 8 7 6 5 4 | 3 | 2 1 0 | +// |----------------------------+-----------------+------+-------------| +// | PER_SPACE | USER_VERSION | ASIC | CPU_VERSION | +// -------------------------------------------------------------------- +// CPU_ID_HI: | 15 14 13 12 11 10 | 9 8 7 6 5 4 3 2 1 | 0 | +// |----------------------------+-------------------------------+------| +// | PMEM_SIZE | DMEM_SIZE | MPY | +// ------------------------------------------------------------------- + +wire [2:0] cpu_version = `CPU_VERSION; +`ifdef ASIC +wire cpu_asic = 1'b1; +`else +wire cpu_asic = 1'b0; +`endif +wire [4:0] user_version = `USER_VERSION; +wire [6:0] per_space = (`PER_SIZE >> 9); // cpu_id_per * 512 = peripheral space size +`ifdef MULTIPLIER +wire mpy_info = 1'b1; +`else +wire mpy_info = 1'b0; +`endif +wire [8:0] dmem_size = (`DMEM_SIZE >> 7); // cpu_id_dmem * 128 = data memory size +wire [5:0] pmem_size = (`PMEM_SIZE >> 10); // cpu_id_pmem * 1024 = program memory size + +assign cpu_id = {pmem_size, + dmem_size, + mpy_info, + per_space, + user_version, + cpu_asic, + cpu_version}; + + +//============================================================================ +// 4) DATA OUTPUT GENERATION +//============================================================================ + +// Data output mux +wire [15:0] ie1_rd = {8'h00, (ie1 & {8{reg_rd[IE1]}})} << (8 & {4{IE1[0]}}); +wire [15:0] ifg1_rd = {8'h00, (ifg1 & {8{reg_rd[IFG1]}})} << (8 & {4{IFG1[0]}}); +wire [15:0] cpu_id_lo_rd = cpu_id[15:0] & {16{reg_rd[CPU_ID_LO]}}; +wire [15:0] cpu_id_hi_rd = cpu_id[31:16] & {16{reg_rd[CPU_ID_HI]}}; + +wire [15:0] per_dout = ie1_rd | + ifg1_rd | + cpu_id_lo_rd | + cpu_id_hi_rd; + + +//============================================================================= +// 5) NMI GENERATION +//============================================================================= +// NOTE THAT THE NMI INPUT IS ASSUMED TO BE NON-GLITCHY +`ifdef NMI + +//----------------------------------- +// Edge selection +//----------------------------------- +wire nmi_pol = nmi ^ wdtnmies; + +//----------------------------------- +// Pulse capture and synchronization +//----------------------------------- +`ifdef SYNC_NMI + `ifdef ASIC + // Glitch free reset for the event capture + reg nmi_capture_rst; + always @(posedge mclk or posedge puc_rst) + if (puc_rst) nmi_capture_rst <= 1'b1; + else nmi_capture_rst <= ifg1_wr & ~ifg1_nxt[4]; + + // NMI event capture + wire nmi_capture; + omsp_wakeup_cell wakeup_cell_nmi ( + .wkup_out (nmi_capture), // Wakup signal (asynchronous) + .scan_clk (mclk), // Scan clock + .scan_mode (scan_mode), // Scan mode + .scan_rst (puc_rst), // Scan reset + .wkup_clear (nmi_capture_rst), // Glitch free wakeup event clear + .wkup_event (nmi_pol) // Glitch free asynchronous wakeup event + ); + `else + wire nmi_capture = nmi_pol; + `endif + + // Synchronization + wire nmi_s; + omsp_sync_cell sync_cell_nmi ( + .data_out (nmi_s), + .data_in (nmi_capture), + .clk (mclk), + .rst (puc_rst) + ); + +`else + wire nmi_capture = nmi_pol; + wire nmi_s = nmi_pol; +`endif + +//----------------------------------- +// NMI Pending flag +//----------------------------------- + +// Delay +reg nmi_dly; +always @ (posedge mclk or posedge puc_rst) + if (puc_rst) nmi_dly <= 1'b0; + else nmi_dly <= nmi_s; + +// Edge detection +assign nmi_edge = ~nmi_dly & nmi_s; + +// NMI pending +wire nmi_pnd = nmiifg & nmie; + +// NMI wakeup +`ifdef ASIC +wire nmi_wkup; +omsp_and_gate and_nmi_wkup (.y(nmi_wkup), .a(nmi_capture ^ nmi_dly), .b(nmie)); +`else +wire nmi_wkup = 1'b0; +`endif + +`else + +wire nmi_pnd = 1'b0; +wire nmi_wkup = 1'b0; + +`endif + +endmodule // omsp_sfr + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/omsp_sync_cell.v b/tests/openmsp430/rtl/omsp_sync_cell.v new file mode 100644 index 00000000..ece0682a --- /dev/null +++ b/tests/openmsp430/rtl/omsp_sync_cell.v @@ -0,0 +1,80 @@ +//---------------------------------------------------------------------------- +// 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_sync_cell.v +// +// *Module Description: +// Generic synchronizer for the openMSP430 +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_sync_cell ( + +// OUTPUTs + data_out, // Synchronized data output + +// INPUTs + clk, // Receiving clock + data_in, // Asynchronous data input + rst // Receiving reset (active high) +); + +// OUTPUTs +//========= +output data_out; // Synchronized data output + +// INPUTs +//========= +input clk; // Receiving clock +input data_in; // Asynchronous data input +input rst; // Receiving reset (active high) + + +//============================================================================= +// 1) SYNCHRONIZER +//============================================================================= + +reg [1:0] data_sync; + +always @(posedge clk or posedge rst) + if (rst) data_sync <= 2'b00; + else data_sync <= {data_sync[0], data_in}; + +assign data_out = data_sync[1]; + + +endmodule // omsp_sync_cell + diff --git a/tests/openmsp430/rtl/omsp_sync_reset.v b/tests/openmsp430/rtl/omsp_sync_reset.v new file mode 100644 index 00000000..15a158b4 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_sync_reset.v @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------------- +// 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_sync_reset.v +// +// *Module Description: +// Generic reset synchronizer for the openMSP430 +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_sync_reset ( + +// OUTPUTs + rst_s, // Synchronized reset + +// INPUTs + clk, // Receiving clock + rst_a // Asynchronous reset +); + +// OUTPUTs +//========= +output rst_s; // Synchronized reset + +// INPUTs +//========= +input clk; // Receiving clock +input rst_a; // Asynchronous reset + + +//============================================================================= +// 1) SYNCHRONIZER +//============================================================================= + +reg [1:0] data_sync; + +always @(posedge clk or posedge rst_a) + if (rst_a) data_sync <= 2'b11; + else data_sync <= {data_sync[0], 1'b0}; + +assign rst_s = data_sync[1]; + + +endmodule // omsp_sync_reset + diff --git a/tests/openmsp430/rtl/omsp_wakeup_cell.v b/tests/openmsp430/rtl/omsp_wakeup_cell.v new file mode 100644 index 00000000..6e5fcd88 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_wakeup_cell.v @@ -0,0 +1,108 @@ +//---------------------------------------------------------------------------- +// 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_wakeup_cell.v +// +// *Module Description: +// Generic Wakeup cell +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 103 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $ +//---------------------------------------------------------------------------- + +module omsp_wakeup_cell ( + +// OUTPUTs + wkup_out, // Wakup signal (asynchronous) + +// INPUTs + scan_clk, // Scan clock + scan_mode, // Scan mode + scan_rst, // Scan reset + wkup_clear, // Glitch free wakeup event clear + wkup_event // Glitch free asynchronous wakeup event +); + +// OUTPUTs +//========= +output wkup_out; // Wakup signal (asynchronous) + +// INPUTs +//========= +input scan_clk; // Scan clock +input scan_mode; // Scan mode +input scan_rst; // Scan reset +input wkup_clear; // Glitch free wakeup event clear +input wkup_event; // Glitch free asynchronous wakeup event + + +//============================================================================= +// 1) AND GATE +//============================================================================= + +// Scan stuff for the ASIC mode +`ifdef ASIC + wire wkup_rst; + omsp_scan_mux scan_mux_rst ( + .scan_mode (scan_mode), + .data_in_scan (scan_rst), + .data_in_func (wkup_clear), + .data_out (wkup_rst) + ); + + wire wkup_clk; + omsp_scan_mux scan_mux_clk ( + .scan_mode (scan_mode), + .data_in_scan (scan_clk), + .data_in_func (wkup_event), + .data_out (wkup_clk) + ); + +`else + wire wkup_rst = wkup_clear; + wire wkup_clk = wkup_event; +`endif + +// Wakeup capture +reg wkup_out; +always @(posedge wkup_clk or posedge wkup_rst) + if (wkup_rst) wkup_out <= 1'b0; + else wkup_out <= 1'b1; + + +endmodule // omsp_wakeup_cell + + + + 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 diff --git a/tests/openmsp430/rtl/openMSP430.v b/tests/openmsp430/rtl/openMSP430.v new file mode 100644 index 00000000..938548aa --- /dev/null +++ b/tests/openmsp430/rtl/openMSP430.v @@ -0,0 +1,584 @@ +//---------------------------------------------------------------------------- +// 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: openMSP430.v +// +// *Module Description: +// openMSP430 Top level file +// +// *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 openMSP430 ( + +// OUTPUTs + aclk, // ASIC ONLY: ACLK + aclk_en, // FPGA ONLY: ACLK enable + dbg_freeze, // Freeze peripherals + dbg_uart_txd, // Debug interface: UART TXD + dco_enable, // ASIC ONLY: Fast oscillator enable + dco_wkup, // ASIC ONLY: Fast oscillator wake-up (asynchronous) + dmem_addr, // Data Memory address + dmem_cen, // Data Memory chip enable (low active) + dmem_din, // Data Memory data input + dmem_wen, // Data Memory write enable (low active) + irq_acc, // Interrupt request accepted (one-hot signal) + lfxt_enable, // ASIC ONLY: Low frequency oscillator enable + lfxt_wkup, // ASIC ONLY: Low frequency oscillator wake-up (asynchronous) + mclk, // Main system clock + per_addr, // Peripheral address + per_din, // Peripheral data input + per_we, // Peripheral write enable (high active) + per_en, // Peripheral enable (high active) + pmem_addr, // Program Memory address + pmem_cen, // Program Memory chip enable (low active) + pmem_din, // Program Memory data input (optional) + pmem_wen, // Program Memory write enable (low active) (optional) + puc_rst, // Main system reset + smclk, // ASIC ONLY: SMCLK + smclk_en, // FPGA ONLY: SMCLK enable + +// INPUTs + cpu_en, // Enable CPU code execution (asynchronous and non-glitchy) + dbg_en, // Debug interface enable (asynchronous and non-glitchy) + dbg_uart_rxd, // Debug interface: UART RXD (asynchronous) + dco_clk, // Fast oscillator (fast clock) + dmem_dout, // Data Memory data output + irq, // Maskable interrupts + lfxt_clk, // Low frequency oscillator (typ 32kHz) + nmi, // Non-maskable interrupt (asynchronous) + per_dout, // Peripheral data output + pmem_dout, // Program Memory data output + reset_n, // Reset Pin (low active, asynchronous and non-glitchy) + scan_enable, // ASIC ONLY: Scan enable (active during scan shifting) + scan_mode, // ASIC ONLY: Scan mode + wkup // ASIC ONLY: System Wake-up (asynchronous and non-glitchy) +); + +// OUTPUTs +//========= +output aclk; // ASIC ONLY: ACLK +output aclk_en; // FPGA ONLY: ACLK enable +output dbg_freeze; // Freeze peripherals +output dbg_uart_txd; // Debug interface: UART TXD +output dco_enable; // ASIC ONLY: Fast oscillator enable +output dco_wkup; // ASIC ONLY: Fast oscillator wake-up (asynchronous) +output [`DMEM_MSB:0] dmem_addr; // Data Memory address +output dmem_cen; // Data Memory chip enable (low active) +output [15:0] dmem_din; // Data Memory data input +output [1:0] dmem_wen; // Data Memory write enable (low active) +output [13:0] irq_acc; // Interrupt request accepted (one-hot signal) +output lfxt_enable; // ASIC ONLY: Low frequency oscillator enable +output lfxt_wkup; // ASIC ONLY: Low frequency oscillator wake-up (asynchronous) +output mclk; // Main system clock +output [13:0] per_addr; // Peripheral address +output [15:0] per_din; // Peripheral data input +output [1:0] per_we; // Peripheral write enable (high active) +output per_en; // Peripheral enable (high active) +output [`PMEM_MSB:0] pmem_addr; // Program Memory address +output pmem_cen; // Program Memory chip enable (low active) +output [15:0] pmem_din; // Program Memory data input (optional) +output [1:0] pmem_wen; // Program Memory write enable (low active) (optional) +output puc_rst; // Main system reset +output smclk; // ASIC ONLY: SMCLK +output smclk_en; // FPGA ONLY: SMCLK enable + + +// INPUTs +//========= +input cpu_en; // Enable CPU code execution (asynchronous and non-glitchy) +input dbg_en; // Debug interface enable (asynchronous and non-glitchy) +input dbg_uart_rxd; // Debug interface: UART RXD (asynchronous) +input dco_clk; // Fast oscillator (fast clock) +input [15:0] dmem_dout; // Data Memory data output +input [13:0] irq; // Maskable interrupts +input lfxt_clk; // Low frequency oscillator (typ 32kHz) +input nmi; // Non-maskable interrupt (asynchronous and non-glitchy) +input [15:0] per_dout; // Peripheral data output +input [15:0] pmem_dout; // Program Memory data output +input reset_n; // Reset Pin (active low, asynchronous and non-glitchy) +input scan_enable; // ASIC ONLY: Scan enable (active during scan shifting) +input scan_mode; // ASIC ONLY: Scan mode +input wkup; // ASIC ONLY: System Wake-up (asynchronous and non-glitchy) + + + +//============================================================================= +// 1) INTERNAL WIRES/REGISTERS/PARAMETERS DECLARATION +//============================================================================= + +wire [7:0] inst_ad; +wire [7:0] inst_as; +wire [11:0] inst_alu; +wire inst_bw; +wire inst_irq_rst; +wire inst_mov; +wire [15:0] inst_dest; +wire [15:0] inst_dext; +wire [15:0] inst_sext; +wire [7:0] inst_so; +wire [15:0] inst_src; +wire [2:0] inst_type; +wire [7:0] inst_jmp; +wire [3:0] e_state; +wire exec_done; +wire decode_noirq; +wire cpu_en_s; +wire cpuoff; +wire oscoff; +wire scg0; +wire scg1; +wire por; +wire gie; +wire mclk_enable; +wire mclk_wkup; +wire [31:0] cpu_id; + +wire [15:0] eu_mab; +wire [15:0] eu_mdb_in; +wire [15:0] eu_mdb_out; +wire [1:0] eu_mb_wr; +wire eu_mb_en; +wire [15:0] fe_mab; +wire [15:0] fe_mdb_in; +wire fe_mb_en; +wire fe_pmem_wait; + +wire pc_sw_wr; +wire [15:0] pc_sw; +wire [15:0] pc; +wire [15:0] pc_nxt; + +wire nmi_acc; +wire nmi_pnd; +wire nmi_wkup; + +wire wdtie; +wire wdtnmies; +wire wdtifg; +wire wdt_irq; +wire wdt_wkup; +wire wdt_reset; +wire wdtifg_sw_clr; +wire wdtifg_sw_set; + +wire dbg_clk; +wire dbg_rst; +wire dbg_en_s; +wire dbg_halt_st; +wire dbg_halt_cmd; +wire dbg_mem_en; +wire dbg_reg_wr; +wire dbg_cpu_reset; +wire [15:0] dbg_mem_addr; +wire [15:0] dbg_mem_dout; +wire [15:0] dbg_mem_din; +wire [15:0] dbg_reg_din; +wire [1:0] dbg_mem_wr; +wire puc_pnd_set; + +wire [15:0] per_dout_or; +wire [15:0] per_dout_sfr; +wire [15:0] per_dout_wdog; +wire [15:0] per_dout_mpy; +wire [15:0] per_dout_clk; + + +//============================================================================= +// 2) GLOBAL CLOCK & RESET MANAGEMENT +//============================================================================= + +omsp_clock_module clock_module_0 ( + +// OUTPUTs + .aclk (aclk), // ACLK + .aclk_en (aclk_en), // ACLK enablex + .cpu_en_s (cpu_en_s), // Enable CPU code execution (synchronous) + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_en_s (dbg_en_s), // Debug interface enable (synchronous) + .dbg_rst (dbg_rst), // Debug unit reset + .dco_enable (dco_enable), // Fast oscillator enable + .dco_wkup (dco_wkup), // Fast oscillator wake-up (asynchronous) + .lfxt_enable (lfxt_enable), // Low frequency oscillator enable + .lfxt_wkup (lfxt_wkup), // Low frequency oscillator wake-up (asynchronous) + .mclk (mclk), // Main system clock + .per_dout (per_dout_clk), // Peripheral data output + .por (por), // Power-on reset + .puc_pnd_set (puc_pnd_set), // PUC pending set for the serial debug interface + .puc_rst (puc_rst), // Main system reset + .smclk (smclk), // SMCLK + .smclk_en (smclk_en), // SMCLK enable + +// INPUTs + .cpu_en (cpu_en), // Enable CPU code execution (asynchronous) + .cpuoff (cpuoff), // Turns off the CPU + .dbg_cpu_reset(dbg_cpu_reset), // Reset CPU from debug interface + .dbg_en (dbg_en), // Debug interface enable (asynchronous) + .dco_clk (dco_clk), // Fast oscillator (fast clock) + .lfxt_clk (lfxt_clk), // Low frequency oscillator (typ 32kHz) + .mclk_enable (mclk_enable), // Main System Clock enable + .mclk_wkup (mclk_wkup), // Main System Clock wake-up (asynchronous) + .oscoff (oscoff), // Turns off LFXT1 clock input + .per_addr (per_addr), // Peripheral address + .per_din (per_din), // Peripheral data input + .per_en (per_en), // Peripheral enable (high active) + .per_we (per_we), // Peripheral write enable (high active) + .reset_n (reset_n), // Reset Pin (low active, asynchronous) + .scan_enable (scan_enable), // Scan enable (active during scan shifting) + .scan_mode (scan_mode), // Scan mode + .scg0 (scg0), // System clock generator 1. Turns off the DCO + .scg1 (scg1), // System clock generator 1. Turns off the SMCLK + .wdt_reset (wdt_reset) // Watchdog-timer reset +); + + +//============================================================================= +// 3) FRONTEND (<=> FETCH & DECODE) +//============================================================================= + +omsp_frontend frontend_0 ( + +// OUTPUTs + .dbg_halt_st (dbg_halt_st), // Halt/Run status from CPU + .decode_noirq (decode_noirq), // Frontend decode instruction + .e_state (e_state), // Execution state + .exec_done (exec_done), // Execution completed + .inst_ad (inst_ad), // Decoded Inst: destination addressing mode + .inst_as (inst_as), // Decoded Inst: source addressing mode + .inst_alu (inst_alu), // ALU control signals + .inst_bw (inst_bw), // Decoded Inst: byte width + .inst_dest (inst_dest), // Decoded Inst: destination (one hot) + .inst_dext (inst_dext), // Decoded Inst: destination extended instruction word + .inst_irq_rst (inst_irq_rst), // Decoded Inst: Reset interrupt + .inst_jmp (inst_jmp), // Decoded Inst: Conditional jump + .inst_mov (inst_mov), // Decoded Inst: mov instruction + .inst_sext (inst_sext), // Decoded Inst: source extended instruction word + .inst_so (inst_so), // Decoded Inst: Single-operand arithmetic + .inst_src (inst_src), // Decoded Inst: source (one hot) + .inst_type (inst_type), // Decoded Instruction type + .irq_acc (irq_acc), // Interrupt request accepted + .mab (fe_mab), // Frontend Memory address bus + .mb_en (fe_mb_en), // Frontend Memory bus enable + .mclk_enable (mclk_enable), // Main System Clock enable + .mclk_wkup (mclk_wkup), // Main System Clock wake-up (asynchronous) + .nmi_acc (nmi_acc), // Non-Maskable interrupt request accepted + .pc (pc), // Program counter + .pc_nxt (pc_nxt), // Next PC value (for CALL & IRQ) + +// INPUTs + .cpu_en_s (cpu_en_s), // Enable CPU code execution (synchronous) + .cpuoff (cpuoff), // Turns off the CPU + .dbg_halt_cmd (dbg_halt_cmd), // Halt CPU command + .dbg_reg_sel (dbg_mem_addr[3:0]), // Debug selected register for rd/wr access + .fe_pmem_wait (fe_pmem_wait), // Frontend wait for Instruction fetch + .gie (gie), // General interrupt enable + .irq (irq), // Maskable interrupts + .mclk (mclk), // Main system clock + .mdb_in (fe_mdb_in), // Frontend Memory data bus input + .nmi_pnd (nmi_pnd), // Non-maskable interrupt pending + .nmi_wkup (nmi_wkup), // NMI Wakeup + .pc_sw (pc_sw), // Program counter software value + .pc_sw_wr (pc_sw_wr), // Program counter software write + .puc_rst (puc_rst), // Main system reset + .scan_enable (scan_enable), // Scan enable (active during scan shifting) + .wdt_irq (wdt_irq), // Watchdog-timer interrupt + .wdt_wkup (wdt_wkup), // Watchdog Wakeup + .wkup (wkup) // System Wake-up (asynchronous) +); + + +//============================================================================= +// 4) EXECUTION UNIT +//============================================================================= + +omsp_execution_unit execution_unit_0 ( + +// OUTPUTs + .cpuoff (cpuoff), // Turns off the CPU + .dbg_reg_din (dbg_reg_din), // Debug unit CPU register data input + .mab (eu_mab), // Memory address bus + .mb_en (eu_mb_en), // Memory bus enable + .mb_wr (eu_mb_wr), // Memory bus write transfer + .mdb_out (eu_mdb_out), // Memory data bus output + .oscoff (oscoff), // Turns off LFXT1 clock input + .pc_sw (pc_sw), // Program counter software value + .pc_sw_wr (pc_sw_wr), // Program counter software write + .scg0 (scg0), // System clock generator 1. Turns off the DCO + .scg1 (scg1), // System clock generator 1. Turns off the SMCLK + +// INPUTs + .dbg_halt_st (dbg_halt_st), // Halt/Run status from CPU + .dbg_mem_dout (dbg_mem_dout), // Debug unit data output + .dbg_reg_wr (dbg_reg_wr), // Debug unit CPU register write + .e_state (e_state), // Execution state + .exec_done (exec_done), // Execution completed + .gie (gie), // General interrupt enable + .inst_ad (inst_ad), // Decoded Inst: destination addressing mode + .inst_as (inst_as), // Decoded Inst: source addressing mode + .inst_alu (inst_alu), // ALU control signals + .inst_bw (inst_bw), // Decoded Inst: byte width + .inst_dest (inst_dest), // Decoded Inst: destination (one hot) + .inst_dext (inst_dext), // Decoded Inst: destination extended instruction word + .inst_irq_rst (inst_irq_rst), // Decoded Inst: reset interrupt + .inst_jmp (inst_jmp), // Decoded Inst: Conditional jump + .inst_mov (inst_mov), // Decoded Inst: mov instruction + .inst_sext (inst_sext), // Decoded Inst: source extended instruction word + .inst_so (inst_so), // Decoded Inst: Single-operand arithmetic + .inst_src (inst_src), // Decoded Inst: source (one hot) + .inst_type (inst_type), // Decoded Instruction type + .mclk (mclk), // Main system clock + .mdb_in (eu_mdb_in), // Memory data bus input + .pc (pc), // Program counter + .pc_nxt (pc_nxt), // Next PC value (for CALL & IRQ) + .puc_rst (puc_rst), // Main system reset + .scan_enable (scan_enable) // Scan enable (active during scan shifting) +); + + +//============================================================================= +// 5) MEMORY BACKBONE +//============================================================================= + +omsp_mem_backbone mem_backbone_0 ( + +// OUTPUTs + .dbg_mem_din (dbg_mem_din), // Debug unit Memory data input + .dmem_addr (dmem_addr), // Data Memory address + .dmem_cen (dmem_cen), // Data Memory chip enable (low active) + .dmem_din (dmem_din), // Data Memory data input + .dmem_wen (dmem_wen), // Data Memory write enable (low active) + .eu_mdb_in (eu_mdb_in), // Execution Unit Memory data bus input + .fe_mdb_in (fe_mdb_in), // Frontend Memory data bus input + .fe_pmem_wait (fe_pmem_wait), // Frontend wait for Instruction fetch + .per_addr (per_addr), // Peripheral address + .per_din (per_din), // Peripheral data input + .per_we (per_we), // Peripheral write enable (high active) + .per_en (per_en), // Peripheral enable (high active) + .pmem_addr (pmem_addr), // Program Memory address + .pmem_cen (pmem_cen), // Program Memory chip enable (low active) + .pmem_din (pmem_din), // Program Memory data input (optional) + .pmem_wen (pmem_wen), // Program Memory write enable (low active) (optional) + +// INPUTs + .dbg_halt_st (dbg_halt_st), // Halt/Run status from CPU + .dbg_mem_addr (dbg_mem_addr), // Debug address for rd/wr access + .dbg_mem_dout (dbg_mem_dout), // Debug unit data output + .dbg_mem_en (dbg_mem_en), // Debug unit memory enable + .dbg_mem_wr (dbg_mem_wr), // Debug unit memory write + .dmem_dout (dmem_dout), // Data Memory data output + .eu_mab (eu_mab[15:1]), // Execution Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution Unit Memory bus write transfer + .eu_mdb_out (eu_mdb_out), // Execution Unit Memory data bus output + .fe_mab (fe_mab[15:1]), // Frontend Memory address bus + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .mclk (mclk), // Main system clock + .per_dout (per_dout_or), // Peripheral data output + .pmem_dout (pmem_dout), // Program Memory data output + .puc_rst (puc_rst), // Main system reset + .scan_enable (scan_enable) // Scan enable (active during scan shifting) +); + + +//============================================================================= +// 6) SPECIAL FUNCTION REGISTERS +//============================================================================= +omsp_sfr sfr_0 ( + +// OUTPUTs + .cpu_id (cpu_id), // CPU ID + .nmi_pnd (nmi_pnd), // NMI Pending + .nmi_wkup (nmi_wkup), // NMI Wakeup + .per_dout (per_dout_sfr), // Peripheral data output + .wdtie (wdtie), // Watchdog-timer interrupt enable + .wdtifg_sw_clr(wdtifg_sw_clr), // Watchdog-timer interrupt flag software clear + .wdtifg_sw_set(wdtifg_sw_set), // Watchdog-timer interrupt flag software set + +// INPUTs + .mclk (mclk), // Main system clock + .nmi (nmi), // Non-maskable interrupt (asynchronous) + .nmi_acc (nmi_acc), // Non-Maskable interrupt request accepted + .per_addr (per_addr), // Peripheral address + .per_din (per_din), // Peripheral data input + .per_en (per_en), // Peripheral enable (high active) + .per_we (per_we), // Peripheral write enable (high active) + .puc_rst (puc_rst), // Main system reset + .scan_mode (scan_mode), // Scan mode + .wdtifg (wdtifg), // Watchdog-timer interrupt flag + .wdtnmies (wdtnmies) // Watchdog-timer NMI edge selection +); + + +//============================================================================= +// 7) WATCHDOG TIMER +//============================================================================= +`ifdef WATCHDOG +omsp_watchdog watchdog_0 ( + +// OUTPUTs + .per_dout (per_dout_wdog), // Peripheral data output + .wdt_irq (wdt_irq), // Watchdog-timer interrupt + .wdt_reset (wdt_reset), // Watchdog-timer reset + .wdt_wkup (wdt_wkup), // Watchdog Wakeup + .wdtifg (wdtifg), // Watchdog-timer interrupt flag + .wdtnmies (wdtnmies), // Watchdog-timer NMI edge selection + +// INPUTs + .aclk (aclk), // ACLK + .aclk_en (aclk_en), // ACLK enable + .dbg_freeze (dbg_freeze), // Freeze Watchdog counter + .mclk (mclk), // Main system clock + .per_addr (per_addr), // Peripheral address + .per_din (per_din), // Peripheral data input + .per_en (per_en), // Peripheral enable (high active) + .per_we (per_we), // Peripheral write enable (high active) + .por (por), // Power-on reset + .puc_rst (puc_rst), // Main system reset + .scan_enable (scan_enable), // Scan enable (active during scan shifting) + .scan_mode (scan_mode), // Scan mode + .smclk (smclk), // SMCLK + .smclk_en (smclk_en), // SMCLK enable + .wdtie (wdtie), // Watchdog-timer interrupt enable + .wdtifg_irq_clr (irq_acc[10]), // Clear Watchdog-timer interrupt flag + .wdtifg_sw_clr (wdtifg_sw_clr), // Watchdog-timer interrupt flag software clear + .wdtifg_sw_set (wdtifg_sw_set) // Watchdog-timer interrupt flag software set +); +`else +assign per_dout_wdog = 16'h0000; +assign wdt_irq = 1'b0; +assign wdt_reset = 1'b0; +assign wdt_wkup = 1'b0; +assign wdtifg = 1'b0; +assign wdtnmies = 1'b0; +`endif + + +//============================================================================= +// 8) HARDWARE MULTIPLIER +//============================================================================= +`ifdef MULTIPLIER +omsp_multiplier multiplier_0 ( + +// OUTPUTs + .per_dout (per_dout_mpy), // Peripheral data output + +// INPUTs + .mclk (mclk), // Main system clock + .per_addr (per_addr), // Peripheral address + .per_din (per_din), // Peripheral data input + .per_en (per_en), // Peripheral enable (high active) + .per_we (per_we), // Peripheral write enable (high active) + .puc_rst (puc_rst), // Main system reset + .scan_enable (scan_enable) // Scan enable (active during scan shifting) +); +`else +assign per_dout_mpy = 16'h0000; +`endif + +//============================================================================= +// 9) PERIPHERALS' OUTPUT BUS +//============================================================================= + +assign per_dout_or = per_dout | + per_dout_clk | + per_dout_sfr | + per_dout_wdog | + per_dout_mpy; + + +//============================================================================= +// 10) DEBUG INTERFACE +//============================================================================= + +`ifdef DBG_EN +omsp_dbg dbg_0 ( + +// OUTPUTs + .dbg_freeze (dbg_freeze), // Freeze peripherals + .dbg_halt_cmd (dbg_halt_cmd), // Halt CPU command + .dbg_mem_addr (dbg_mem_addr), // Debug address for rd/wr access + .dbg_mem_dout (dbg_mem_dout), // Debug unit data output + .dbg_mem_en (dbg_mem_en), // Debug unit memory enable + .dbg_mem_wr (dbg_mem_wr), // Debug unit memory write + .dbg_reg_wr (dbg_reg_wr), // Debug unit CPU register write + .dbg_cpu_reset(dbg_cpu_reset), // Reset CPU from debug interface + .dbg_uart_txd (dbg_uart_txd), // Debug interface: UART TXD + +// INPUTs + .cpu_en_s (cpu_en_s), // Enable CPU code execution (synchronous) + .cpu_id (cpu_id), // CPU ID + .dbg_clk (dbg_clk), // Debug unit clock + .dbg_en_s (dbg_en_s), // Debug interface enable (synchronous) + .dbg_halt_st (dbg_halt_st), // Halt/Run status from CPU + .dbg_mem_din (dbg_mem_din), // Debug unit Memory data input + .dbg_reg_din (dbg_reg_din), // Debug unit CPU register data input + .dbg_rst (dbg_rst), // Debug unit reset + .dbg_uart_rxd (dbg_uart_rxd), // Debug interface: UART RXD (asynchronous) + .decode_noirq (decode_noirq), // Frontend decode instruction + .eu_mab (eu_mab), // Execution-Unit Memory address bus + .eu_mb_en (eu_mb_en), // Execution-Unit Memory bus enable + .eu_mb_wr (eu_mb_wr), // Execution-Unit Memory bus write transfer + .eu_mdb_in (eu_mdb_in), // Memory data bus input + .eu_mdb_out (eu_mdb_out), // Memory data bus output + .exec_done (exec_done), // Execution completed + .fe_mb_en (fe_mb_en), // Frontend Memory bus enable + .fe_mdb_in (fe_mdb_in), // Frontend Memory data bus input + .pc (pc), // Program counter + .puc_pnd_set (puc_pnd_set) // PUC pending set for the serial debug interface +); + +`else +assign dbg_freeze = ~cpu_en_s; +assign dbg_halt_cmd = 1'b0; +assign dbg_mem_addr = 16'h0000; +assign dbg_mem_dout = 16'h0000; +assign dbg_mem_en = 1'b0; +assign dbg_mem_wr = 2'b00; +assign dbg_reg_wr = 1'b0; +assign dbg_cpu_reset = 1'b0; +assign dbg_uart_txd = 1'b0; +`endif + + +endmodule // openMSP430 + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif diff --git a/tests/openmsp430/rtl/openMSP430_defines.v b/tests/openmsp430/rtl/openMSP430_defines.v new file mode 100644 index 00000000..368f7a5b --- /dev/null +++ b/tests/openmsp430/rtl/openMSP430_defines.v @@ -0,0 +1,843 @@ +//---------------------------------------------------------------------------- +// 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: openMSP430_defines.v +// +// *Module Description: +// openMSP430 Configuration file +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 151 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2012-07-23 00:24:11 +0200 (Mon, 23 Jul 2012) $ +//---------------------------------------------------------------------------- +//`define OMSP_NO_INCLUDE +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif + +//============================================================================ +//============================================================================ +// BASIC SYSTEM CONFIGURATION +//============================================================================ +//============================================================================ +// +// Note: the sum of program, data and peripheral memory spaces must not +// exceed 64 kB +// + +// Program Memory Size: +// Uncomment the required memory size +//------------------------------------------------------- +//`define PMEM_SIZE_CUSTOM +//`define PMEM_SIZE_59_KB +//`define PMEM_SIZE_55_KB +//`define PMEM_SIZE_54_KB +//`define PMEM_SIZE_51_KB +//`define PMEM_SIZE_48_KB +//`define PMEM_SIZE_41_KB +//`define PMEM_SIZE_32_KB +//`define PMEM_SIZE_24_KB +//`define PMEM_SIZE_16_KB +//`define PMEM_SIZE_12_KB +//`define PMEM_SIZE_8_KB +//`define PMEM_SIZE_4_KB +`define PMEM_SIZE_2_KB +//`define PMEM_SIZE_1_KB + + +// Data Memory Size: +// Uncomment the required memory size +//------------------------------------------------------- +//`define DMEM_SIZE_CUSTOM +//`define DMEM_SIZE_32_KB +//`define DMEM_SIZE_24_KB +//`define DMEM_SIZE_16_KB +//`define DMEM_SIZE_10_KB +//`define DMEM_SIZE_8_KB +//`define DMEM_SIZE_5_KB +//`define DMEM_SIZE_4_KB +//`define DMEM_SIZE_2p5_KB +//`define DMEM_SIZE_2_KB +//`define DMEM_SIZE_1_KB +//`define DMEM_SIZE_512_B +//`define DMEM_SIZE_256_B +`define DMEM_SIZE_128_B + + +// Include/Exclude Hardware Multiplier +`define MULTIPLIER + + +// Include/Exclude Serial Debug interface +`define DBG_EN + + +//============================================================================ +//============================================================================ +// ADVANCED SYSTEM CONFIGURATION (FOR EXPERIENCED USERS) +//============================================================================ +//============================================================================ + +//------------------------------------------------------- +// Custom user version number +//------------------------------------------------------- +// This 5 bit field can be freely used in order to allow +// custom identification of the system through the debug +// interface. +// (see CPU_ID.USER_VERSION field in the documentation) +//------------------------------------------------------- +`define USER_VERSION 5'b00000 + + +//------------------------------------------------------- +// Include/Exclude Watchdog timer +//------------------------------------------------------- +// When excluded, the following functionality will be +// lost: +// - Watchog (both interval and watchdog modes) +// - NMI interrupt edge selection +// - Possibility to generate a software PUC reset +//------------------------------------------------------- +`define WATCHDOG + + +///------------------------------------------------------- +// Include/Exclude Non-Maskable-Interrupt support +//------------------------------------------------------- +`define NMI + + +//------------------------------------------------------- +// Input synchronizers +//------------------------------------------------------- +// In some cases, the asynchronous input ports might +// already be synchronized externally. +// If an extensive CDC design review showed that this +// is really the case, the individual synchronizers +// can be disabled with the following defines. +// +// Notes: +// - all three signals are all sampled in the MCLK domain +// +// - the dbg_en signal reset the debug interface +// when 0. Therefore make sure it is glitch free. +// +//------------------------------------------------------- +`define SYNC_NMI +//`define SYNC_CPU_EN +//`define SYNC_DBG_EN + + +//------------------------------------------------------- +// Peripheral Memory Space: +//------------------------------------------------------- +// The original MSP430 architecture map the peripherals +// from 0x0000 to 0x01FF (i.e. 512B of the memory space). +// The following defines allow you to expand this space +// up to 32 kB (i.e. from 0x0000 to 0x7fff). +// As a consequence, the data memory mapping will be +// shifted up and a custom linker script will therefore +// be required by the GCC compiler. +//------------------------------------------------------- +//`define PER_SIZE_CUSTOM +//`define PER_SIZE_32_KB +//`define PER_SIZE_16_KB +//`define PER_SIZE_8_KB +//`define PER_SIZE_4_KB +//`define PER_SIZE_2_KB +//`define PER_SIZE_1_KB +`define PER_SIZE_512_B + + +//------------------------------------------------------- +// Defines the debugger CPU_CTL.RST_BRK_EN reset value +// (CPU break on PUC reset) +//------------------------------------------------------- +// When defined, the CPU will automatically break after +// a PUC occurrence by default. This is typically useful +// when the program memory can only be initialized through +// the serial debug interface. +//------------------------------------------------------- +`define DBG_RST_BRK_EN + + +//============================================================================ +//============================================================================ +// EXPERT SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! ) +//============================================================================ +//============================================================================ +// +// IMPORTANT NOTE: Please update following configuration options ONLY if +// you have a good reason to do so... and if you know what +// you are doing :-P +// +//============================================================================ + +//------------------------------------------------------- +// Number of hardware breakpoint/watchpoint units +// (each unit contains two hardware addresses available +// for breakpoints or watchpoints): +// - DBG_HWBRK_0 -> Include hardware breakpoints unit 0 +// - DBG_HWBRK_1 -> Include hardware breakpoints unit 1 +// - DBG_HWBRK_2 -> Include hardware breakpoints unit 2 +// - DBG_HWBRK_3 -> Include hardware breakpoints unit 3 +//------------------------------------------------------- +// Please keep in mind that hardware breakpoints only +// make sense whenever the program memory is not an SRAM +// (i.e. Flash/OTP/ROM/...) or when you are interested +// in data breakpoints. +//------------------------------------------------------- +//`define DBG_HWBRK_0 +//`define DBG_HWBRK_1 +//`define DBG_HWBRK_2 +//`define DBG_HWBRK_3 + + +//------------------------------------------------------- +// Enable/Disable the hardware breakpoint RANGE mode +//------------------------------------------------------- +// When enabled this feature allows the hardware breakpoint +// units to stop the cpu whenever an instruction or data +// access lays within an address range. +// Note that this feature is not supported by GDB. +//------------------------------------------------------- +//`define DBG_HWBRK_RANGE + + +//------------------------------------------------------- +// Custom Program/Data and Peripheral Memory Spaces +//------------------------------------------------------- +// The following values are valid only if the +// corresponding *_SIZE_CUSTOM defines are uncommented: +// +// - *_SIZE : size of the section in bytes. +// - *_AWIDTH : address port width, this value must allow +// to address all WORDS of the section +// (i.e. the *_SIZE divided by 2) +//------------------------------------------------------- + +// Custom Program memory (enabled with PMEM_SIZE_CUSTOM) +`define PMEM_CUSTOM_AWIDTH 10 +`define PMEM_CUSTOM_SIZE 2028 + +// Custom Data memory (enabled with DMEM_SIZE_CUSTOM) +`define DMEM_CUSTOM_AWIDTH 6 +`define DMEM_CUSTOM_SIZE 128 + +// Custom Peripheral memory (enabled with PER_SIZE_CUSTOM) +`define PER_CUSTOM_AWIDTH 8 +`define PER_CUSTOM_SIZE 512 + + +//------------------------------------------------------- +// ASIC version +//------------------------------------------------------- +// When uncommented, this define will enable the +// ASIC system configuration section (see below) and +// will activate scan support for production test. +// +// WARNING: if you target an FPGA, leave this define +// commented. +//------------------------------------------------------- +//`define ASIC + + +//============================================================================ +//============================================================================ +// ASIC SYSTEM CONFIGURATION ( !!!! EXPERTS/PROFESSIONALS ONLY !!!! ) +//============================================================================ +//============================================================================ +`ifdef ASIC + +//=============================================================== +// FINE GRAINED CLOCK GATING +//=============================================================== + +//------------------------------------------------------- +// When uncommented, this define will enable the fine +// grained clock gating of all registers in the core. +//------------------------------------------------------- +`define CLOCK_GATING + + +//=============================================================== +// LFXT CLOCK DOMAIN +//=============================================================== + +//------------------------------------------------------- +// When uncommented, this define will enable the lfxt_clk +// clock domain. +// When commented out, the whole chip is clocked with dco_clk. +//------------------------------------------------------- +`define LFXT_DOMAIN + + +//=============================================================== +// CLOCK MUXES +//=============================================================== + +//------------------------------------------------------- +// MCLK: Clock Mux +//------------------------------------------------------- +// When uncommented, this define will enable the +// MCLK clock MUX allowing the selection between +// DCO_CLK and LFXT_CLK with the BCSCTL2.SELMx register. +// When commented, DCO_CLK is selected. +//------------------------------------------------------- +`define MCLK_MUX + +//------------------------------------------------------- +// SMCLK: Clock Mux +//------------------------------------------------------- +// When uncommented, this define will enable the +// SMCLK clock MUX allowing the selection between +// DCO_CLK and LFXT_CLK with the BCSCTL2.SELS register. +// When commented, DCO_CLK is selected. +//------------------------------------------------------- +`define SMCLK_MUX + +//------------------------------------------------------- +// WATCHDOG: Clock Mux +//------------------------------------------------------- +// When uncommented, this define will enable the +// Watchdog clock MUX allowing the selection between +// ACLK and SMCLK with the WDTCTL.WDTSSEL register. +// When commented out, ACLK is selected if the +// WATCHDOG_NOMUX_ACLK define is uncommented, SMCLK is +// selected otherwise. +//------------------------------------------------------- +`define WATCHDOG_MUX +//`define WATCHDOG_NOMUX_ACLK + + +//=============================================================== +// CLOCK DIVIDERS +//=============================================================== + +//------------------------------------------------------- +// MCLK: Clock divider +//------------------------------------------------------- +// When uncommented, this define will enable the +// MCLK clock divider (/1/2/4/8) +//------------------------------------------------------- +`define MCLK_DIVIDER + +//------------------------------------------------------- +// SMCLK: Clock divider (/1/2/4/8) +//------------------------------------------------------- +// When uncommented, this define will enable the +// SMCLK clock divider +//------------------------------------------------------- +`define SMCLK_DIVIDER + +//------------------------------------------------------- +// ACLK: Clock divider (/1/2/4/8) +//------------------------------------------------------- +// When uncommented, this define will enable the +// ACLK clock divider +//------------------------------------------------------- +`define ACLK_DIVIDER + + +//=============================================================== +// LOW POWER MODES +//=============================================================== + +//------------------------------------------------------- +// LOW POWER MODE: CPUOFF +//------------------------------------------------------- +// When uncommented, this define will include the +// clock gate allowing to switch off MCLK in +// all low power modes: LPM0, LPM1, LPM2, LPM3, LPM4 +//------------------------------------------------------- +`define CPUOFF_EN + +//------------------------------------------------------- +// LOW POWER MODE: SCG0 +//------------------------------------------------------- +// When uncommented, this define will enable the +// DCO_ENABLE/WKUP port control (always 1 when commented). +// This allows to switch off the DCO oscillator in the +// following low power modes: LPM1, LPM3, LPM4 +//------------------------------------------------------- +`define SCG0_EN + +//------------------------------------------------------- +// LOW POWER MODE: SCG1 +//------------------------------------------------------- +// When uncommented, this define will include the +// clock gate allowing to switch off SMCLK in +// the following low power modes: LPM2, LPM3, LPM4 +//------------------------------------------------------- +`define SCG1_EN + +//------------------------------------------------------- +// LOW POWER MODE: OSCOFF +//------------------------------------------------------- +// When uncommented, this define will include the +// LFXT_CLK clock gate and enable the LFXT_ENABLE/WKUP +// port control (always 1 when commented). +// This allows to switch off the low frequency oscillator +// in the following low power modes: LPM4 +//------------------------------------------------------- +`define OSCOFF_EN + + + +`endif + +//==========================================================================// +//==========================================================================// +//==========================================================================// +//==========================================================================// +//===== SYSTEM CONSTANTS --- !!!!!!!! DO NOT EDIT !!!!!!!! =====// +//==========================================================================// +//==========================================================================// +//==========================================================================// +//==========================================================================// + +// +// PROGRAM, DATA & PERIPHERAL MEMORY CONFIGURATION +//================================================== + +// Program Memory Size +`ifdef PMEM_SIZE_59_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 60416 +`endif +`ifdef PMEM_SIZE_55_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 56320 +`endif +`ifdef PMEM_SIZE_54_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 55296 +`endif +`ifdef PMEM_SIZE_51_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 52224 +`endif +`ifdef PMEM_SIZE_48_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 49152 +`endif +`ifdef PMEM_SIZE_41_KB + `define PMEM_AWIDTH 15 + `define PMEM_SIZE 41984 +`endif +`ifdef PMEM_SIZE_32_KB + `define PMEM_AWIDTH 14 + `define PMEM_SIZE 32768 +`endif +`ifdef PMEM_SIZE_24_KB + `define PMEM_AWIDTH 14 + `define PMEM_SIZE 24576 +`endif +`ifdef PMEM_SIZE_16_KB + `define PMEM_AWIDTH 13 + `define PMEM_SIZE 16384 +`endif +`ifdef PMEM_SIZE_12_KB + `define PMEM_AWIDTH 13 + `define PMEM_SIZE 12288 +`endif +`ifdef PMEM_SIZE_8_KB + `define PMEM_AWIDTH 12 + `define PMEM_SIZE 8192 +`endif +`ifdef PMEM_SIZE_4_KB + `define PMEM_AWIDTH 11 + `define PMEM_SIZE 4096 +`endif +`ifdef PMEM_SIZE_2_KB + `define PMEM_AWIDTH 10 + `define PMEM_SIZE 2048 +`endif +`ifdef PMEM_SIZE_1_KB + `define PMEM_AWIDTH 9 + `define PMEM_SIZE 1024 +`endif +`ifdef PMEM_SIZE_CUSTOM + `define PMEM_AWIDTH `PMEM_CUSTOM_AWIDTH + `define PMEM_SIZE `PMEM_CUSTOM_SIZE +`endif + +// Data Memory Size +`ifdef DMEM_SIZE_32_KB + `define DMEM_AWIDTH 14 + `define DMEM_SIZE 32768 +`endif +`ifdef DMEM_SIZE_24_KB + `define DMEM_AWIDTH 14 + `define DMEM_SIZE 24576 +`endif +`ifdef DMEM_SIZE_16_KB + `define DMEM_AWIDTH 13 + `define DMEM_SIZE 16384 +`endif +`ifdef DMEM_SIZE_10_KB + `define DMEM_AWIDTH 13 + `define DMEM_SIZE 10240 +`endif +`ifdef DMEM_SIZE_8_KB + `define DMEM_AWIDTH 12 + `define DMEM_SIZE 8192 +`endif +`ifdef DMEM_SIZE_5_KB + `define DMEM_AWIDTH 12 + `define DMEM_SIZE 5120 +`endif +`ifdef DMEM_SIZE_4_KB + `define DMEM_AWIDTH 11 + `define DMEM_SIZE 4096 +`endif +`ifdef DMEM_SIZE_2p5_KB + `define DMEM_AWIDTH 11 + `define DMEM_SIZE 2560 +`endif +`ifdef DMEM_SIZE_2_KB + `define DMEM_AWIDTH 10 + `define DMEM_SIZE 2048 +`endif +`ifdef DMEM_SIZE_1_KB + `define DMEM_AWIDTH 9 + `define DMEM_SIZE 1024 +`endif +`ifdef DMEM_SIZE_512_B + `define DMEM_AWIDTH 8 + `define DMEM_SIZE 512 +`endif +`ifdef DMEM_SIZE_256_B + `define DMEM_AWIDTH 7 + `define DMEM_SIZE 256 +`endif +`ifdef DMEM_SIZE_128_B + `define DMEM_AWIDTH 6 + `define DMEM_SIZE 128 +`endif +`ifdef DMEM_SIZE_CUSTOM + `define DMEM_AWIDTH `DMEM_CUSTOM_AWIDTH + `define DMEM_SIZE `DMEM_CUSTOM_SIZE +`endif + +// Peripheral Memory Size +`ifdef PER_SIZE_32_KB + `define PER_AWIDTH 14 + `define PER_SIZE 32768 +`endif +`ifdef PER_SIZE_16_KB + `define PER_AWIDTH 13 + `define PER_SIZE 16384 +`endif +`ifdef PER_SIZE_8_KB + `define PER_AWIDTH 12 + `define PER_SIZE 8192 +`endif +`ifdef PER_SIZE_4_KB + `define PER_AWIDTH 11 + `define PER_SIZE 4096 +`endif +`ifdef PER_SIZE_2_KB + `define PER_AWIDTH 10 + `define PER_SIZE 2048 +`endif +`ifdef PER_SIZE_1_KB + `define PER_AWIDTH 9 + `define PER_SIZE 1024 +`endif +`ifdef PER_SIZE_512_B + `define PER_AWIDTH 8 + `define PER_SIZE 512 +`endif +`ifdef PER_SIZE_CUSTOM + `define PER_AWIDTH `PER_CUSTOM_AWIDTH + `define PER_SIZE `PER_CUSTOM_SIZE +`endif + +// Data Memory Base Adresses +`define DMEM_BASE `PER_SIZE + +// Program & Data Memory most significant address bit (for 16 bit words) +`define PMEM_MSB `PMEM_AWIDTH-1 +`define DMEM_MSB `DMEM_AWIDTH-1 +`define PER_MSB `PER_AWIDTH-1 + +// +// STATES, REGISTER FIELDS, ... +//====================================== + +// Instructions type +`define INST_SO 0 +`define INST_JMP 1 +`define INST_TO 2 + +// Single-operand arithmetic +`define RRC 0 +`define SWPB 1 +`define RRA 2 +`define SXT 3 +`define PUSH 4 +`define CALL 5 +`define RETI 6 +`define IRQ 7 + +// Conditional jump +`define JNE 0 +`define JEQ 1 +`define JNC 2 +`define JC 3 +`define JN 4 +`define JGE 5 +`define JL 6 +`define JMP 7 + +// Two-operand arithmetic +`define MOV 0 +`define ADD 1 +`define ADDC 2 +`define SUBC 3 +`define SUB 4 +`define CMP 5 +`define DADD 6 +`define BIT 7 +`define BIC 8 +`define BIS 9 +`define XOR 10 +`define AND 11 + +// Addressing modes +`define DIR 0 +`define IDX 1 +`define INDIR 2 +`define INDIR_I 3 +`define SYMB 4 +`define IMM 5 +`define ABS 6 +`define CONST 7 + +// Instruction state machine +`define I_IRQ_FETCH 3'h0 +`define I_IRQ_DONE 3'h1 +`define I_DEC 3'h2 +`define I_EXT1 3'h3 +`define I_EXT2 3'h4 +`define I_IDLE 3'h5 + +// Execution state machine +// (swapped E_IRQ_0 and E_IRQ_2 values to suppress glitch generation warning from lint tool) +`define E_IRQ_0 4'h2 +`define E_IRQ_1 4'h1 +`define E_IRQ_2 4'h0 +`define E_IRQ_3 4'h3 +`define E_IRQ_4 4'h4 +`define E_SRC_AD 4'h5 +`define E_SRC_RD 4'h6 +`define E_SRC_WR 4'h7 +`define E_DST_AD 4'h8 +`define E_DST_RD 4'h9 +`define E_DST_WR 4'hA +`define E_EXEC 4'hB +`define E_JUMP 4'hC +`define E_IDLE 4'hD + +// ALU control signals +`define ALU_SRC_INV 0 +`define ALU_INC 1 +`define ALU_INC_C 2 +`define ALU_ADD 3 +`define ALU_AND 4 +`define ALU_OR 5 +`define ALU_XOR 6 +`define ALU_DADD 7 +`define ALU_STAT_7 8 +`define ALU_STAT_F 9 +`define ALU_SHIFT 10 +`define EXEC_NO_WR 11 + +// Debug interface +`define DBG_UART_WR 18 +`define DBG_UART_BW 17 +`define DBG_UART_ADDR 16:11 + +// Debug interface CPU_CTL register +`define HALT 0 +`define RUN 1 +`define ISTEP 2 +`define SW_BRK_EN 3 +`define FRZ_BRK_EN 4 +`define RST_BRK_EN 5 +`define CPU_RST 6 + +// Debug interface CPU_STAT register +`define HALT_RUN 0 +`define PUC_PND 1 +`define SWBRK_PND 3 +`define HWBRK0_PND 4 +`define HWBRK1_PND 5 + +// Debug interface BRKx_CTL register +`define BRK_MODE_RD 0 +`define BRK_MODE_WR 1 +`define BRK_MODE 1:0 +`define BRK_EN 2 +`define BRK_I_EN 3 +`define BRK_RANGE 4 + +// Basic clock module: BCSCTL1 Control Register +`define DIVAx 5:4 + +// Basic clock module: BCSCTL2 Control Register +`define SELMx 7 +`define DIVMx 5:4 +`define SELS 3 +`define DIVSx 2:1 + +// MCLK Clock gate +`ifdef CPUOFF_EN + `define MCLK_CGATE +`else +`ifdef MCLK_DIVIDER + `define MCLK_CGATE +`endif +`endif + +// SMCLK Clock gate +`ifdef SCG1_EN + `define SMCLK_CGATE +`else +`ifdef SMCLK_DIVIDER + `define SMCLK_CGATE +`endif +`endif + +// +// DEBUG INTERFACE EXTRA CONFIGURATION +//====================================== + +// Debug interface: CPU version +`define CPU_VERSION 3'h2 + +// Debug interface: Software breakpoint opcode +`define DBG_SWBRK_OP 16'h4343 + +// Debug UART interface auto data synchronization +// If the following define is commented out, then +// the DBG_UART_BAUD and DBG_DCO_FREQ need to be properly +// defined. +`define DBG_UART_AUTO_SYNC + +// Debug UART interface data rate +// In order to properly setup the UART debug interface, you +// need to specify the DCO_CLK frequency (DBG_DCO_FREQ) and +// the chosen BAUD rate from the UART interface. +// +//`define DBG_UART_BAUD 9600 +//`define DBG_UART_BAUD 19200 +//`define DBG_UART_BAUD 38400 +//`define DBG_UART_BAUD 57600 +//`define DBG_UART_BAUD 115200 +//`define DBG_UART_BAUD 230400 +//`define DBG_UART_BAUD 460800 +//`define DBG_UART_BAUD 576000 +//`define DBG_UART_BAUD 921600 +`define DBG_UART_BAUD 2000000 +`define DBG_DCO_FREQ 20000000 +`define DBG_UART_CNT ((`DBG_DCO_FREQ/`DBG_UART_BAUD)-1) + +// Debug interface selection +// `define DBG_UART -> Enable UART (8N1) debug interface +// `define DBG_JTAG -> DON'T UNCOMMENT, NOT SUPPORTED +// +`define DBG_UART +//`define DBG_JTAG + +// Debug interface input synchronizer +`define SYNC_DBG_UART_RXD + +// Enable/Disable the hardware breakpoint RANGE mode +`ifdef DBG_HWBRK_RANGE + `define HWBRK_RANGE 1'b1 +`else + `define HWBRK_RANGE 1'b0 +`endif + +// Counter width for the debug interface UART +`define DBG_UART_XFER_CNT_W 16 + +// Check configuration +`ifdef DBG_EN + `ifdef DBG_UART + `ifdef DBG_JTAG +CONFIGURATION ERROR: JTAG AND UART DEBUG INTERFACE ARE BOTH ENABLED + `endif + `else + `ifdef DBG_JTAG +CONFIGURATION ERROR: JTAG INTERFACE NOT SUPPORTED + `else +CONFIGURATION ERROR: JTAG OR UART DEBUG INTERFACE SHOULD BE ENABLED + `endif + `endif +`endif + +// +// MULTIPLIER CONFIGURATION +//====================================== + +// If uncommented, the following define selects +// the 16x16 multiplier (1 cycle) instead of the +// default 16x8 multplier (2 cycles) +//`define MPY_16x16 + +//====================================== +// CONFIGURATION CHECKS +//====================================== +`ifdef LFXT_DOMAIN +`else + `ifdef MCLK_MUX +CONFIGURATION ERROR: THE MCLK_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL + `endif + `ifdef SMCLK_MUX +CONFIGURATION ERROR: THE SMCLK_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL + `endif + `ifdef WATCHDOG_MUX +CONFIGURATION ERROR: THE WATCHDOG_MUX CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL + `else + `ifdef WATCHDOG_NOMUX_ACLK +CONFIGURATION ERROR: THE WATCHDOG_NOMUX_ACLK CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL + `endif + `endif + `ifdef OSCOFF_EN +CONFIGURATION ERROR: THE OSCOFF LOW POWER MODE CAN ONLY BE ENABLED IF THE LFXT_DOMAIN IS ENABLED AS WELL + `endif +`endif diff --git a/tests/openmsp430/rtl/openMSP430_undefines.v b/tests/openmsp430/rtl/openMSP430_undefines.v new file mode 100644 index 00000000..a399ae77 --- /dev/null +++ b/tests/openmsp430/rtl/openMSP430_undefines.v @@ -0,0 +1,732 @@ +//---------------------------------------------------------------------------- +// 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: openMSP430_undefines.v +// +// *Module Description: +// openMSP430 Verilog `undef file +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 23 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2009-08-30 18:39:26 +0200 (Sun, 30 Aug 2009) $ +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// BASIC SYSTEM CONFIGURATION +//---------------------------------------------------------------------------- + +// Program Memory sizes +`ifdef PMEM_SIZE_59_KB +`undef PMEM_SIZE_59_KB +`endif +`ifdef PMEM_SIZE_55_KB +`undef PMEM_SIZE_55_KB +`endif +`ifdef PMEM_SIZE_54_KB +`undef PMEM_SIZE_54_KB +`endif +`ifdef PMEM_SIZE_51_KB +`undef PMEM_SIZE_51_KB +`endif +`ifdef PMEM_SIZE_48_KB +`undef PMEM_SIZE_48_KB +`endif +`ifdef PMEM_SIZE_41_KB +`undef PMEM_SIZE_41_KB +`endif +`ifdef PMEM_SIZE_32_KB +`undef PMEM_SIZE_32_KB +`endif +`ifdef PMEM_SIZE_24_KB +`undef PMEM_SIZE_24_KB +`endif +`ifdef PMEM_SIZE_16_KB +`undef PMEM_SIZE_16_KB +`endif +`ifdef PMEM_SIZE_12_KB +`undef PMEM_SIZE_12_KB +`endif +`ifdef PMEM_SIZE_8_KB +`undef PMEM_SIZE_8_KB +`endif +`ifdef PMEM_SIZE_4_KB +`undef PMEM_SIZE_4_KB +`endif +`ifdef PMEM_SIZE_2_KB +`undef PMEM_SIZE_2_KB +`endif +`ifdef PMEM_SIZE_1_KB +`undef PMEM_SIZE_1_KB +`endif + +// Data Memory sizes +`ifdef DMEM_SIZE_32_KB +`undef DMEM_SIZE_32_KB +`endif +`ifdef DMEM_SIZE_24_KB +`undef DMEM_SIZE_24_KB +`endif +`ifdef DMEM_SIZE_16_KB +`undef DMEM_SIZE_16_KB +`endif +`ifdef DMEM_SIZE_10_KB +`undef DMEM_SIZE_10_KB +`endif +`ifdef DMEM_SIZE_8_KB +`undef DMEM_SIZE_8_KB +`endif +`ifdef DMEM_SIZE_5_KB +`undef DMEM_SIZE_5_KB +`endif +`ifdef DMEM_SIZE_4_KB +`undef DMEM_SIZE_4_KB +`endif +`ifdef DMEM_SIZE_2p5_KB +`undef DMEM_SIZE_2p5_KB +`endif +`ifdef DMEM_SIZE_2_KB +`undef DMEM_SIZE_2_KB +`endif +`ifdef DMEM_SIZE_1_KB +`undef DMEM_SIZE_1_KB +`endif +`ifdef DMEM_SIZE_512_B +`undef DMEM_SIZE_512_B +`endif +`ifdef DMEM_SIZE_256_B +`undef DMEM_SIZE_256_B +`endif +`ifdef DMEM_SIZE_128_B +`undef DMEM_SIZE_128_B +`endif + +// Include/Exclude Hardware Multiplier +`ifdef MULTIPLIER +`undef MULTIPLIER +`endif + +// Include Debug interface +`ifdef DBG_EN +`undef DBG_EN +`endif + + +//---------------------------------------------------------------------------- +// ADVANCED SYSTEM CONFIGURATION (FOR EXPERIENCED USERS) +//---------------------------------------------------------------------------- + +// Peripheral Memory Space: +`ifdef PER_SIZE_32_KB +`undef PER_SIZE_32_KB +`endif +`ifdef PER_SIZE_16_KB +`undef PER_SIZE_16_KB +`endif +`ifdef PER_SIZE_8_KB +`undef PER_SIZE_8_KB +`endif +`ifdef PER_SIZE_4_KB +`undef PER_SIZE_4_KB +`endif +`ifdef PER_SIZE_2_KB +`undef PER_SIZE_2_KB +`endif +`ifdef PER_SIZE_1_KB +`undef PER_SIZE_1_KB +`endif +`ifdef PER_SIZE_512_B +`undef PER_SIZE_512_B +`endif + +// Let the CPU break after a PUC occurrence by default +`ifdef DBG_RST_BRK_EN +`undef DBG_RST_BRK_EN +`endif + +// Custom user version number +`ifdef USER_VERSION +`undef USER_VERSION +`endif + +// Include/Exclude Watchdog timer +`ifdef WATCHDOG +`undef WATCHDOG +`endif + +// Include/Exclude Non-Maskable-Interrupt support +`ifdef NMI +`undef NMI +`endif + +//---------------------------------------------------------------------------- +// EXPERT SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! ) +//---------------------------------------------------------------------------- + +// Number of hardware breakpoint units +`ifdef DBG_HWBRK_0 +`undef DBG_HWBRK_0 +`endif +`ifdef DBG_HWBRK_1 +`undef DBG_HWBRK_1 +`endif +`ifdef DBG_HWBRK_2 +`undef DBG_HWBRK_2 +`endif +`ifdef DBG_HWBRK_3 +`undef DBG_HWBRK_3 +`endif + +// Enable/Disable the hardware breakpoint RANGE mode +`ifdef DBG_HWBRK_RANGE +`undef DBG_HWBRK_RANGE +`endif + +// Input synchronizers +`ifdef SYNC_CPU_EN +`undef SYNC_CPU_EN +`endif +`ifdef SYNC_DBG_EN +`undef SYNC_DBG_EN +`endif +`ifdef SYNC_DBG_UART_RXD +`undef SYNC_DBG_UART_RXD +`endif +`ifdef SYNC_NMI +`undef SYNC_NMI +`endif + +// ASIC version +`ifdef ASIC +`undef ASIC +`endif + + +//---------------------------------------------------------------------------- +// ASIC SYSTEM CONFIGURATION ( !!!! EXPERTS ONLY !!!! ) +//---------------------------------------------------------------------------- + +// Fine grained clock gating +`ifdef CLOCK_GATING +`undef CLOCK_GATING +`endif + +// LFXT clock domain +`ifdef LFXT_DOMAIN +`undef LFXT_DOMAIN +`endif + +// MCLK: Clock Mux +`ifdef MCLK_MUX +`undef MCLK_MUX +`endif + +// SMCLK: Clock Mux +`ifdef SMCLK_MUX +`undef SMCLK_MUX +`endif + +// WATCHDOG: Clock Mux +`ifdef WATCHDOG_MUX +`undef WATCHDOG_MUX +`endif + +// MCLK: Clock divider +`ifdef MCLK_DIVIDER +`undef MCLK_DIVIDER +`endif + +// SMCLK: Clock divider (/1/2/4/8) +`ifdef SMCLK_DIVIDER +`undef SMCLK_DIVIDER +`endif + +// ACLK: Clock divider (/1/2/4/8) +`ifdef ACLK_DIVIDER +`undef ACLK_DIVIDER +`endif + +// LOW POWER MODE: CPUOFF +`ifdef CPUOFF_EN +`undef CPUOFF_EN +`endif + +// LOW POWER MODE: OSCOFF +`ifdef OSCOFF_EN +`undef OSCOFF_EN +`endif + +// LOW POWER MODE: SCG0 +`ifdef SCG0_EN +`undef SCG0_EN +`endif + +// LOW POWER MODE: SCG1 +`ifdef SCG1_EN +`undef SCG1_EN +`endif + + +//==========================================================================// +//==========================================================================// +//==========================================================================// +//==========================================================================// +//===== SYSTEM CONSTANTS --- !!!!!!!! DO NOT EDIT !!!!!!!! =====// +//==========================================================================// +//==========================================================================// +//==========================================================================// +//==========================================================================// + +// Program Memory Size +`ifdef PMEM_AWIDTH +`undef PMEM_AWIDTH +`endif +`ifdef PMEM_SIZE +`undef PMEM_SIZE +`endif + +// Data Memory Size +`ifdef DMEM_AWIDTH +`undef DMEM_AWIDTH +`endif +`ifdef DMEM_SIZE +`undef DMEM_SIZE +`endif + +// Peripheral Memory Size +`ifdef PER_AWIDTH +`undef PER_AWIDTH +`endif +`ifdef PER_SIZE +`undef PER_SIZE +`endif + +// Data Memory Base Adresses +`ifdef DMEM_BASE +`undef DMEM_BASE +`endif + +// Program & Data Memory most significant address bit (for 16 bit words) +`ifdef PMEM_MSB +`undef PMEM_MSB +`endif +`ifdef DMEM_MSB +`undef DMEM_MSB +`endif +`ifdef PER_MSB +`undef PER_MSB +`endif + +// Instructions type +`ifdef INST_SO +`undef INST_SO +`endif +`ifdef INST_JMP +`undef INST_JMP +`endif +`ifdef INST_TO +`undef INST_TO +`endif + +// Single-operand arithmetic +`ifdef RRC +`undef RRC +`endif +`ifdef SWPB +`undef SWPB +`endif +`ifdef RRA +`undef RRA +`endif +`ifdef SXT +`undef SXT +`endif +`ifdef PUSH +`undef PUSH +`endif +`ifdef CALL +`undef CALL +`endif +`ifdef RETI +`undef RETI +`endif +`ifdef IRQ +`undef IRQ +`endif + +// Conditional jump +`ifdef JNE +`undef JNE +`endif +`ifdef JEQ +`undef JEQ +`endif +`ifdef JNC +`undef JNC +`endif +`ifdef JC +`undef JC +`endif +`ifdef JN +`undef JN +`endif +`ifdef JGE +`undef JGE +`endif +`ifdef JL +`undef JL +`endif +`ifdef JMP +`undef JMP +`endif + +// Two-operand arithmetic +`ifdef MOV +`undef MOV +`endif +`ifdef ADD +`undef ADD +`endif +`ifdef ADDC +`undef ADDC +`endif +`ifdef SUBC +`undef SUBC +`endif +`ifdef SUB +`undef SUB +`endif +`ifdef CMP +`undef CMP +`endif +`ifdef DADD +`undef DADD +`endif +`ifdef BIT +`undef BIT +`endif +`ifdef BIC +`undef BIC +`endif +`ifdef BIS +`undef BIS +`endif +`ifdef XOR +`undef XOR +`endif +`ifdef AND +`undef AND +`endif + +// Addressing modes +`ifdef DIR +`undef DIR +`endif +`ifdef IDX +`undef IDX +`endif +`ifdef INDIR +`undef INDIR +`endif +`ifdef INDIR_I +`undef INDIR_I +`endif +`ifdef SYMB +`undef SYMB +`endif +`ifdef IMM +`undef IMM +`endif +`ifdef ABS +`undef ABS +`endif +`ifdef CONST +`undef CONST +`endif + +// Instruction state machine +`ifdef I_IRQ_FETCH +`undef I_IRQ_FETCH +`endif +`ifdef I_IRQ_DONE +`undef I_IRQ_DONE +`endif +`ifdef I_DEC +`undef I_DEC +`endif +`ifdef I_EXT1 +`undef I_EXT1 +`endif +`ifdef I_EXT2 +`undef I_EXT2 +`endif +`ifdef I_IDLE +`undef I_IDLE +`endif + +// Execution state machine +`ifdef E_IRQ_0 +`undef E_IRQ_0 +`endif +`ifdef E_IRQ_1 +`undef E_IRQ_1 +`endif +`ifdef E_IRQ_2 +`undef E_IRQ_2 +`endif +`ifdef E_IRQ_3 +`undef E_IRQ_3 +`endif +`ifdef E_IRQ_4 +`undef E_IRQ_4 +`endif +`ifdef E_SRC_AD +`undef E_SRC_AD +`endif +`ifdef E_SRC_RD +`undef E_SRC_RD +`endif +`ifdef E_SRC_WR +`undef E_SRC_WR +`endif +`ifdef E_DST_AD +`undef E_DST_AD +`endif +`ifdef E_DST_RD +`undef E_DST_RD +`endif +`ifdef E_DST_WR +`undef E_DST_WR +`endif +`ifdef E_EXEC +`undef E_EXEC +`endif +`ifdef E_JUMP +`undef E_JUMP +`endif +`ifdef E_IDLE +`undef E_IDLE +`endif + +// ALU control signals +`ifdef ALU_SRC_INV +`undef ALU_SRC_INV +`endif +`ifdef ALU_INC +`undef ALU_INC +`endif +`ifdef ALU_INC_C +`undef ALU_INC_C +`endif +`ifdef ALU_ADD +`undef ALU_ADD +`endif +`ifdef ALU_AND +`undef ALU_AND +`endif +`ifdef ALU_OR +`undef ALU_OR +`endif +`ifdef ALU_XOR +`undef ALU_XOR +`endif +`ifdef ALU_DADD +`undef ALU_DADD +`endif +`ifdef ALU_STAT_7 +`undef ALU_STAT_7 +`endif +`ifdef ALU_STAT_F +`undef ALU_STAT_F +`endif +`ifdef ALU_SHIFT +`undef ALU_SHIFT +`endif +`ifdef EXEC_NO_WR +`undef EXEC_NO_WR +`endif + +// Debug interface +`ifdef DBG_UART_WR +`undef DBG_UART_WR +`endif +`ifdef DBG_UART_BW +`undef DBG_UART_BW +`endif +`ifdef DBG_UART_ADDR +`undef DBG_UART_ADDR +`endif + +// Debug interface CPU_CTL register +`ifdef HALT +`undef HALT +`endif +`ifdef RUN +`undef RUN +`endif +`ifdef ISTEP +`undef ISTEP +`endif +`ifdef SW_BRK_EN +`undef SW_BRK_EN +`endif +`ifdef FRZ_BRK_EN +`undef FRZ_BRK_EN +`endif +`ifdef RST_BRK_EN +`undef RST_BRK_EN +`endif +`ifdef CPU_RST +`undef CPU_RST +`endif + +// Debug interface CPU_STAT register +`ifdef HALT_RUN +`undef HALT_RUN +`endif +`ifdef PUC_PND +`undef PUC_PND +`endif +`ifdef SWBRK_PND +`undef SWBRK_PND +`endif +`ifdef HWBRK0_PND +`undef HWBRK0_PND +`endif +`ifdef HWBRK1_PND +`undef HWBRK1_PND +`endif + +// Debug interface BRKx_CTL register +`ifdef BRK_MODE_RD +`undef BRK_MODE_RD +`endif +`ifdef BRK_MODE_WR +`undef BRK_MODE_WR +`endif +`ifdef BRK_MODE +`undef BRK_MODE +`endif +`ifdef BRK_EN +`undef BRK_EN +`endif +`ifdef BRK_I_EN +`undef BRK_I_EN +`endif +`ifdef BRK_RANGE +`undef BRK_RANGE +`endif + +// Basic clock module: BCSCTL1 Control Register +`ifdef DIVAx +`undef DIVAx +`endif + +// Basic clock module: BCSCTL2 Control Register +`ifdef SELMx +`undef SELMx +`endif +`ifdef DIVMx +`undef DIVMx +`endif +`ifdef SELS +`undef SELS +`endif +`ifdef DIVSx +`undef DIVSx +`endif + +// MCLK Clock gate +`ifdef MCLK_CGATE +`undef MCLK_CGATE +`endif + +// SMCLK Clock gate +`ifdef SMCLK_CGATE +`undef SMCLK_CGATE +`endif + +// +// DEBUG INTERFACE EXTRA CONFIGURATION +//====================================== + +// Debug interface: CPU version +`ifdef CPU_VERSION +`undef CPU_VERSION +`endif + +// Debug interface: Software breakpoint opcode +`ifdef DBG_SWBRK_OP +`undef DBG_SWBRK_OP +`endif + +// Debug UART interface auto data synchronization +`ifdef DBG_UART_AUTO_SYNC +`undef DBG_UART_AUTO_SYNC +`endif + +// Debug UART interface data rate +`ifdef DBG_UART_BAUD +`undef DBG_UART_BAUD +`endif +`ifdef DBG_DCO_FREQ +`undef DBG_DCO_FREQ +`endif +`ifdef DBG_UART_CNT +`undef DBG_UART_CNT +`endif + +// Debug interface selection +`ifdef DBG_UART +`undef DBG_UART +`endif +`ifdef DBG_JTAG +`undef DBG_JTAG +`endif + +// Enable/Disable the hardware breakpoint RANGE mode +`ifdef HWBRK_RANGE +`undef HWBRK_RANGE +`endif + +// Counter width for the debug interface UART +`ifdef DBG_UART_XFER_CNT_W +`undef DBG_UART_XFER_CNT_W +`endif + +// +// MULTIPLIER CONFIGURATION +//====================================== + +`ifdef MPY_16x16 +`undef MPY_16x16 +`endif -- cgit v1.2.3