| // ================================================================== |
| // >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< |
| // ------------------------------------------------------------------ |
| // Copyright (c) 2006-2011 by Lattice Semiconductor Corporation |
| // ALL RIGHTS RESERVED |
| // ------------------------------------------------------------------ |
| // |
| // IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM. |
| // |
| // Permission: |
| // |
| // Lattice Semiconductor grants permission to use this code |
| // pursuant to the terms of the Lattice Semiconductor Corporation |
| // Open Source License Agreement. |
| // |
| // Disclaimer: |
| // |
| // Lattice Semiconductor provides no warranty regarding the use or |
| // functionality of this code. It is the user's responsibility to |
| // verify the user's design for consistency and functionality through |
| // the use of formal verification methods. |
| // |
| // -------------------------------------------------------------------- |
| // |
| // Lattice Semiconductor Corporation |
| // 5555 NE Moore Court |
| // Hillsboro, OR 97214 |
| // U.S.A |
| // |
| // TEL: 1-800-Lattice (USA and Canada) |
| // 503-286-8001 (other locations) |
| // |
| // web: http://www.latticesemi.com/ |
| // email: techsupport@latticesemi.com |
| // |
| // -------------------------------------------------------------------- |
| // FILE DETAILS |
| // Project : LatticeMico32 |
| // File : lm32_debug.v |
| // Title : Hardware debug registers and associated logic. |
| // Dependencies : lm32_include.v |
| // Version : 6.1.17 |
| // : Initial Release |
| // Version : 7.0SP2, 3.0 |
| // : No Change |
| // Version : 3.1 |
| // : No Change |
| // Version : 3.2 |
| // : Fixed simulation bug which flares up when number of |
| // : watchpoints is zero. |
| // ============================================================================= |
| |
| `include "lm32_include.v" |
| |
| `ifdef CFG_DEBUG_ENABLED |
| |
| // States for single-step FSM |
| `define LM32_DEBUG_SS_STATE_RNG 2:0 |
| `define LM32_DEBUG_SS_STATE_IDLE 3'b000 |
| `define LM32_DEBUG_SS_STATE_WAIT_FOR_RET 3'b001 |
| `define LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN 3'b010 |
| `define LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT 3'b011 |
| `define LM32_DEBUG_SS_STATE_RESTART 3'b100 |
| |
| ///////////////////////////////////////////////////// |
| // Module interface |
| ///////////////////////////////////////////////////// |
| |
| module lm32_debug ( |
| // ----- Inputs ------- |
| clk_i, |
| rst_i, |
| pc_x, |
| load_x, |
| store_x, |
| load_store_address_x, |
| csr_write_enable_x, |
| csr_write_data, |
| csr_x, |
| `ifdef CFG_HW_DEBUG_ENABLED |
| jtag_csr_write_enable, |
| jtag_csr_write_data, |
| jtag_csr, |
| `endif |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| eret_q_x, |
| bret_q_x, |
| stall_x, |
| exception_x, |
| q_x, |
| `ifdef CFG_DCACHE_ENABLED |
| dcache_refill_request, |
| `endif |
| `endif |
| // ----- Outputs ------- |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| dc_ss, |
| `endif |
| dc_re, |
| bp_match, |
| wp_match |
| ); |
| |
| ///////////////////////////////////////////////////// |
| // Parameters |
| ///////////////////////////////////////////////////// |
| |
| parameter breakpoints = 0; // Number of breakpoint CSRs |
| parameter watchpoints = 0; // Number of watchpoint CSRs |
| |
| ///////////////////////////////////////////////////// |
| // Inputs |
| ///////////////////////////////////////////////////// |
| |
| input clk_i; // Clock |
| input rst_i; // Reset |
| |
| input [`LM32_PC_RNG] pc_x; // X stage PC |
| input load_x; // Load instruction in X stage |
| input store_x; // Store instruction in X stage |
| input [`LM32_WORD_RNG] load_store_address_x; // Load or store effective address |
| input csr_write_enable_x; // wcsr instruction in X stage |
| input [`LM32_WORD_RNG] csr_write_data; // Data to write to CSR |
| input [`LM32_CSR_RNG] csr_x; // Which CSR to write |
| `ifdef CFG_HW_DEBUG_ENABLED |
| input jtag_csr_write_enable; // JTAG interface CSR write enable |
| input [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to CSR |
| input [`LM32_CSR_RNG] jtag_csr; // Which CSR to write |
| `endif |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| input eret_q_x; // eret instruction in X stage |
| input bret_q_x; // bret instruction in X stage |
| input stall_x; // Instruction in X stage is stalled |
| input exception_x; // An exception has occured in X stage |
| input q_x; // Indicates the instruction in the X stage is qualified |
| `ifdef CFG_DCACHE_ENABLED |
| input dcache_refill_request; // Indicates data cache wants to be refilled |
| `endif |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Outputs |
| ///////////////////////////////////////////////////// |
| |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| output dc_ss; // Single-step enable |
| reg dc_ss; |
| `endif |
| output dc_re; // Remap exceptions |
| reg dc_re; |
| output bp_match; // Indicates a breakpoint has matched |
| wire bp_match; |
| output wp_match; // Indicates a watchpoint has matched |
| wire wp_match; |
| |
| ///////////////////////////////////////////////////// |
| // Internal nets and registers |
| ///////////////////////////////////////////////////// |
| |
| genvar i; // Loop index for generate statements |
| |
| // Debug CSRs |
| |
| reg [`LM32_PC_RNG] bp_a[0:breakpoints-1]; // Instruction breakpoint address |
| reg bp_e[0:breakpoints-1]; // Instruction breakpoint enable |
| wire [0:breakpoints-1]bp_match_n; // Indicates if a h/w instruction breakpoint matched |
| |
| reg [`LM32_WPC_C_RNG] wpc_c[0:watchpoints-1]; // Watchpoint enable |
| reg [`LM32_WORD_RNG] wp[0:watchpoints-1]; // Watchpoint address |
| wire [0:watchpoints-1]wp_match_n; // Indicates if a h/w data watchpoint matched |
| |
| wire debug_csr_write_enable; // Debug CSR write enable (from either a wcsr instruction of external debugger) |
| wire [`LM32_WORD_RNG] debug_csr_write_data; // Data to write to debug CSR |
| wire [`LM32_CSR_RNG] debug_csr; // Debug CSR to write to |
| |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| // FIXME: Declaring this as a reg causes ModelSim 6.1.15b to crash, so use integer for now |
| //reg [`LM32_DEBUG_SS_STATE_RNG] state; // State of single-step FSM |
| integer state; // State of single-step FSM |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Functions |
| ///////////////////////////////////////////////////// |
| |
| ///////////////////////////////////////////////////// |
| // Combinational Logic |
| ///////////////////////////////////////////////////// |
| |
| // Check for breakpoints |
| generate |
| for (i = 0; i < breakpoints; i = i + 1) |
| begin : bp_comb |
| assign bp_match_n[i] = ((bp_a[i] == pc_x) && (bp_e[i] == `TRUE)); |
| end |
| endgenerate |
| generate |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| if (breakpoints > 0) |
| assign bp_match = (|bp_match_n) || (state == `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT); |
| else |
| assign bp_match = state == `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT; |
| `else |
| if (breakpoints > 0) |
| assign bp_match = |bp_match_n; |
| else |
| assign bp_match = `FALSE; |
| `endif |
| endgenerate |
| |
| // Check for watchpoints |
| generate |
| for (i = 0; i < watchpoints; i = i + 1) |
| begin : wp_comb |
| assign wp_match_n[i] = (wp[i] == load_store_address_x) && ((load_x & wpc_c[i][0]) | (store_x & wpc_c[i][1])); |
| end |
| endgenerate |
| generate |
| if (watchpoints > 0) |
| assign wp_match = |wp_match_n; |
| else |
| assign wp_match = `FALSE; |
| endgenerate |
| |
| `ifdef CFG_HW_DEBUG_ENABLED |
| // Multiplex between wcsr instruction writes and debugger writes to the debug CSRs |
| assign debug_csr_write_enable = (csr_write_enable_x == `TRUE) || (jtag_csr_write_enable == `TRUE); |
| assign debug_csr_write_data = jtag_csr_write_enable == `TRUE ? jtag_csr_write_data : csr_write_data; |
| assign debug_csr = jtag_csr_write_enable == `TRUE ? jtag_csr : csr_x; |
| `else |
| assign debug_csr_write_enable = csr_write_enable_x; |
| assign debug_csr_write_data = csr_write_data; |
| assign debug_csr = csr_x; |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Sequential Logic |
| ///////////////////////////////////////////////////// |
| |
| // Breakpoint address and enable CSRs |
| generate |
| for (i = 0; i < breakpoints; i = i + 1) |
| begin : bp_seq |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| bp_a[i] <= {`LM32_PC_WIDTH{1'bx}}; |
| bp_e[i] <= `FALSE; |
| end |
| else |
| begin |
| if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_BP0 + i)) |
| begin |
| bp_a[i] <= debug_csr_write_data[`LM32_PC_RNG]; |
| bp_e[i] <= debug_csr_write_data[0]; |
| end |
| end |
| end |
| end |
| endgenerate |
| |
| // Watchpoint address and control flags CSRs |
| generate |
| for (i = 0; i < watchpoints; i = i + 1) |
| begin : wp_seq |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| wp[i] <= {`LM32_WORD_WIDTH{1'bx}}; |
| wpc_c[i] <= `LM32_WPC_C_DISABLED; |
| end |
| else |
| begin |
| if (debug_csr_write_enable == `TRUE) |
| begin |
| if (debug_csr == `LM32_CSR_DC) |
| wpc_c[i] <= debug_csr_write_data[3+i*2:2+i*2]; |
| if (debug_csr == `LM32_CSR_WP0 + i) |
| wp[i] <= debug_csr_write_data; |
| end |
| end |
| end |
| end |
| endgenerate |
| |
| // Remap exceptions control bit |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| dc_re <= `FALSE; |
| else |
| begin |
| if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_DC)) |
| dc_re <= debug_csr_write_data[1]; |
| end |
| end |
| |
| `ifdef LM32_SINGLE_STEP_ENABLED |
| // Single-step control flag |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| state <= `LM32_DEBUG_SS_STATE_IDLE; |
| dc_ss <= `FALSE; |
| end |
| else |
| begin |
| if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_DC)) |
| begin |
| dc_ss <= debug_csr_write_data[0]; |
| if (debug_csr_write_data[0] == `FALSE) |
| state <= `LM32_DEBUG_SS_STATE_IDLE; |
| else |
| state <= `LM32_DEBUG_SS_STATE_WAIT_FOR_RET; |
| end |
| case (state) |
| `LM32_DEBUG_SS_STATE_WAIT_FOR_RET: |
| begin |
| // Wait for eret or bret instruction to be executed |
| if ( ( (eret_q_x == `TRUE) |
| || (bret_q_x == `TRUE) |
| ) |
| && (stall_x == `FALSE) |
| ) |
| state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN; |
| end |
| `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN: |
| begin |
| // Wait for an instruction to be executed |
| if ((q_x == `TRUE) && (stall_x == `FALSE)) |
| state <= `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT; |
| end |
| `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT: |
| begin |
| // Wait for exception to be raised |
| `ifdef CFG_DCACHE_ENABLED |
| if (dcache_refill_request == `TRUE) |
| state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN; |
| else |
| `endif |
| if ((exception_x == `TRUE) && (q_x == `TRUE) && (stall_x == `FALSE)) |
| begin |
| dc_ss <= `FALSE; |
| state <= `LM32_DEBUG_SS_STATE_RESTART; |
| end |
| end |
| `LM32_DEBUG_SS_STATE_RESTART: |
| begin |
| // Watch to see if stepped instruction is restarted due to a cache miss |
| `ifdef CFG_DCACHE_ENABLED |
| if (dcache_refill_request == `TRUE) |
| state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN; |
| else |
| `endif |
| state <= `LM32_DEBUG_SS_STATE_IDLE; |
| end |
| endcase |
| end |
| end |
| `endif |
| |
| endmodule |
| |
| `endif |