//   ==================================================================
//   >>>>>>>>>>>>>>>>>>>>>>> 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
