/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details /// @file /// @brief HART Debug Unit (HDU) /// //------------------------------------------------------------------------------ // // // Functionality: // - Controls HART state (RUN, Debug RUN, Debug HALTED) // - Setups Debug Mode execution // - Provides status information about Debug Mode execution // - Provides Program Buffer functionality (a few instructions execution while // in Debug Mode) // - Provides access to Debug CSRs // // Structure: // - Debug state FSM // - HART Control logic // - HART Status logic // - Program Buffer // - Debug CSRs // - HDU <-> DM interface // - HDU <-> EXU interface // - HDU <-> IFU interface // - HDU <-> CSR interface // - HDU <-> TDU interface // //------------------------------------------------------------------------------ `include "scr1_arch_description.svh" `ifdef SCR1_DBG_EN `include "scr1_arch_types.svh" `include "scr1_riscv_isa_decoding.svh" `include "scr1_hdu.svh" module scr1_pipe_hdu #(parameter HART_PBUF_INSTR_REGOUT_EN = 1'b1) ( // Common signals input logic rst_n, // HDU reset input logic clk, // HDU clock input logic clk_en, // HDU clock enable `ifdef SCR1_CLKCTRL_EN input logic clk_pipe_en, // Pipeline clock enable `endif // SCR1_CLKCTRL_EN input logic pipe2hdu_rdc_qlfy_i, // Pipeline RDC qualifier // HDU <-> CSR i/f input logic csr2hdu_req_i, // CSR i/f request input type_scr1_csr_cmd_sel_e csr2hdu_cmd_i, // CSR i/f command input logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr_i, // CSR i/f address input logic [`SCR1_XLEN-1:0] csr2hdu_wdata_i, // CSR i/f write data output type_scr1_csr_resp_e hdu2csr_resp_o, // CSR i/f response output logic [`SCR1_XLEN-1:0] hdu2csr_rdata_o, // CSR i/f read data // HDU <-> DM i/f // HART Run Control i/f input logic dm2hdu_cmd_req_i, // DM-HART Command request input type_scr1_hdu_dbgstates_e dm2hdu_cmd_i, // DM-HART Command output logic hdu2dm_cmd_resp_o, // DM-HART Command response output logic hdu2dm_cmd_rcode_o, // DM-HART Command return code: 0 - Ok; 1 - Error output logic hdu2dm_hart_event_o, // DM-HART Event: 1 if HART debug state changed output type_scr1_hdu_hartstatus_s hdu2dm_hart_status_o, // DM-HART Status // Program Buffer i/f output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] hdu2dm_pbuf_addr_o, // Program Buffer address - so far request only for 1 instruction input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2hdu_pbuf_instr_i, // Program Buffer instruction // HART Abstract Data regs i/f output logic hdu2dm_dreg_req_o, // Abstract Data Register request output logic hdu2dm_dreg_wr_o, // Abstract Data Register write output logic [`SCR1_XLEN-1:0] hdu2dm_dreg_wdata_o, // Abstract Data Register write data input logic dm2hdu_dreg_resp_i, // Abstract Data Register response input logic dm2hdu_dreg_fail_i, // Abstract Data Register fail input logic [`SCR1_XLEN-1:0] dm2hdu_dreg_rdata_i, // Abstract Data Register read data `ifdef SCR1_TDU_EN // HDU <-> TDU interface output logic hdu2tdu_hwbrk_dsbl_o, // Disables BRKM input logic tdu2hdu_dmode_req_i, // Trigger Module requests transition to debug mode input logic exu2hdu_ibrkpt_hw_i, // Hardware breakpoint on current instruction `endif // SCR1_TDU_EN // HART Run Status input logic pipe2hdu_exu_busy_i, // EXU busy input logic pipe2hdu_instret_i, // Instruction retired (with or without exception) input logic pipe2hdu_init_pc_i, // Reset exit // HART Halt Status input logic pipe2hdu_exu_exc_req_i, // Exception request input logic pipe2hdu_brkpt_i, // Software Breakpoint (EBREAK) // HDU <-> EXU i/f // HART Run Control output logic hdu2exu_pbuf_fetch_o, // Fetch instruction from Program Buffer output logic hdu2exu_no_commit_o, // Forbid instruction commitment output logic hdu2exu_irq_dsbl_o, // Disable IRQ output logic hdu2exu_pc_advmt_dsbl_o, // Forbid PC advancement output logic hdu2exu_dmode_sstep_en_o, // Enable single-step // HART state output logic hdu2exu_dbg_halted_o, // Debug halted state output logic hdu2exu_dbg_run2halt_o, // Transition to debug halted state output logic hdu2exu_dbg_halt2run_o, // Transition to run state output logic hdu2exu_dbg_run_start_o, // First cycle of run state // PC interface input logic [`SCR1_XLEN-1:0] pipe2hdu_pc_curr_i, // Current PC output logic [`SCR1_XLEN-1:0] hdu2exu_dbg_new_pc_o, // New PC for resume // HDU <-> IFU i/f // Program Buffer Instruction interface input logic ifu2hdu_pbuf_instr_rdy_i, // Program Buffer Instruction i/f ready output logic hdu2ifu_pbuf_instr_vd_o, // Program Buffer Instruction valid output logic hdu2ifu_pbuf_instr_err_o, // Program Buffer Instruction i/f error output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_o // Program Buffer Instruction itself ); //------------------------------------------------------------------------------ // Local Parameters //------------------------------------------------------------------------------ localparam int unsigned SCR1_HDU_TIMEOUT = 64; // must be power of 2 localparam int unsigned SCR1_HDU_TIMEOUT_WIDTH = $clog2(SCR1_HDU_TIMEOUT); //------------------------------------------------------------------------------ // Local Signals //------------------------------------------------------------------------------ // Debug FSM //------------------------------------------------------------------------------ // FSM control signals logic dm_dhalt_req; logic dm_run_req; logic dm_cmd_run; logic dm_cmd_dhalted; logic dm_cmd_drun; // Debug state FSM signals type_scr1_hdu_dbgstates_e dbg_state; type_scr1_hdu_dbgstates_e dbg_state_next; logic dbg_state_dhalted; logic dbg_state_drun; logic dbg_state_run; logic dbg_state_reset; // FSM transition, update and event registers logic dfsm_trans; logic dfsm_trans_next; logic dfsm_update; logic dfsm_update_next; logic dfsm_event; logic dfsm_event_next; // HART Control signals //------------------------------------------------------------------------------ logic hart_resume_req; logic hart_halt_req; logic hart_cmd_req; // HART Run Control register logic hart_runctrl_upd; logic hart_runctrl_clr; type_scr1_hdu_runctrl_s hart_runctrl; // HART halt request timeout counter signals logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt; logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt_next; logic halt_req_timeout_cnt_en; logic halt_req_timeout_flag; // HART Status signals //------------------------------------------------------------------------------ type_scr1_hdu_haltstatus_s hart_haltstatus; type_scr1_hdu_haltcause_e hart_haltcause; logic hart_halt_pnd; logic hart_halt_ack; // Debug mode cause decoder signals logic dmode_cause_sstep; logic dmode_cause_except; logic dmode_cause_ebreak; logic dmode_cause_any; `ifdef SCR1_TDU_EN logic dmode_cause_tmreq; `endif // SCR1_TDU_EN // Program Buffer FSM //------------------------------------------------------------------------------ // PBUF FSM control signals logic ifu_handshake_done; logic pbuf_exc_inj_req; logic pbuf_exc_inj_end; logic pbuf_start_fetch; // PBUF FSM signals type_scr1_hdu_pbufstates_e pbuf_fsm_curr; type_scr1_hdu_pbufstates_e pbuf_fsm_next; logic pbuf_fsm_idle; logic pbuf_fsm_fetch; logic pbuf_fsm_excinj; // PBUF address signals logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_ff; logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_next; logic pbuf_addr_end; logic pbuf_addr_next_vd; logic pbuf_instr_wait_latching; // Debugs CSRs //------------------------------------------------------------------------------ // CSRs write/read interface signals logic csr_upd_on_halt; logic csr_wr; logic [`SCR1_XLEN-1:0] csr_wr_data; logic [`SCR1_XLEN-1:0] csr_rd_data; // Debug Control and Status register (DCSR) logic csr_dcsr_sel; logic csr_dcsr_wr; type_scr1_hdu_dcsr_s csr_dcsr_in; type_scr1_hdu_dcsr_s csr_dcsr_out; logic csr_dcsr_ebreakm; logic csr_dcsr_stepie; logic csr_dcsr_step; logic [SCR1_HDU_DCSR_CAUSE_BIT_L- SCR1_HDU_DCSR_CAUSE_BIT_R:0] csr_dcsr_cause; // Debug Program Counter register (DPC) logic csr_dpc_sel; logic csr_dpc_wr; logic [`SCR1_XLEN-1:0] csr_dpc_ff; logic [`SCR1_XLEN-1:0] csr_dpc_next; logic [`SCR1_XLEN-1:0] csr_dpc_out; // Debug Scratch register 0 (DSCRATCH0) logic csr_addr_dscratch0; logic csr_dscratch0_sel; logic csr_dscratch0_wr; logic [`SCR1_XLEN-1:0] csr_dscratch0_out; type_scr1_csr_resp_e csr_dscratch0_resp; //------------------------------------------------------------------------------ // Debug state FSM logic //------------------------------------------------------------------------------ // // Debug state FSM logic consists of the following functional units: // - FSM control logic // - Debug state FSM // - FSM transition, update and event registers // // FSM control logic //------------------------------------------------------------------------------ assign dm_cmd_dhalted = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DHALTED); assign dm_cmd_run = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_RUN); assign dm_cmd_drun = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DRUN); assign dm_dhalt_req = dm2hdu_cmd_req_i & dm_cmd_dhalted; assign dm_run_req = dm2hdu_cmd_req_i & (dm_cmd_run | dm_cmd_drun); // Debug state FSM //------------------------------------------------------------------------------ always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin dbg_state <= SCR1_HDU_DBGSTATE_RESET; end else begin dbg_state <= dbg_state_next; end end always_comb begin if (~pipe2hdu_rdc_qlfy_i) begin dbg_state_next = SCR1_HDU_DBGSTATE_RESET; end else begin case (dbg_state) SCR1_HDU_DBGSTATE_RESET: begin dbg_state_next = ~pipe2hdu_init_pc_i ? SCR1_HDU_DBGSTATE_RESET : dm_dhalt_req ? SCR1_HDU_DBGSTATE_DHALTED : SCR1_HDU_DBGSTATE_RUN; end SCR1_HDU_DBGSTATE_RUN: begin dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED : SCR1_HDU_DBGSTATE_RUN; end SCR1_HDU_DBGSTATE_DHALTED: begin dbg_state_next = ~dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED : dm_cmd_drun ? SCR1_HDU_DBGSTATE_DRUN : SCR1_HDU_DBGSTATE_RUN; end SCR1_HDU_DBGSTATE_DRUN: begin dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED : SCR1_HDU_DBGSTATE_DRUN; end default: begin `ifdef SCR1_XPROP_EN dbg_state_next = SCR1_HDU_DBGSTATE_XXX; `else // SCR1_XPROP_EN dbg_state_next = dbg_state; `endif // SCR1_XPROP_EN end endcase end end assign dbg_state_dhalted = (dbg_state == SCR1_HDU_DBGSTATE_DHALTED); assign dbg_state_drun = (dbg_state == SCR1_HDU_DBGSTATE_DRUN); assign dbg_state_run = (dbg_state == SCR1_HDU_DBGSTATE_RUN); assign dbg_state_reset = (dbg_state == SCR1_HDU_DBGSTATE_RESET); // FSM transition, update and event registers //------------------------------------------------------------------------------ always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin dfsm_trans <= 1'b0; dfsm_update <= 1'b0; dfsm_event <= 1'b0; end else begin dfsm_trans <= dfsm_trans_next; dfsm_update <= dfsm_update_next; dfsm_event <= dfsm_event_next; end end always_comb begin dfsm_trans_next = 1'b0; dfsm_update_next = 1'b0; dfsm_event_next = 1'b0; if (~pipe2hdu_rdc_qlfy_i) begin dfsm_trans_next = 1'b0; dfsm_update_next = 1'b0; dfsm_event_next = 1'b1; end else begin case (dbg_state) SCR1_HDU_DBGSTATE_RESET: begin dfsm_trans_next = 1'b0; dfsm_update_next = 1'b0; dfsm_event_next = pipe2hdu_init_pc_i & ~dm2hdu_cmd_req_i; end SCR1_HDU_DBGSTATE_RUN, SCR1_HDU_DBGSTATE_DRUN: begin dfsm_trans_next = ~dfsm_update ? hart_halt_pnd : dfsm_trans; dfsm_update_next = ~dfsm_update & hart_halt_ack; dfsm_event_next = dfsm_update; end SCR1_HDU_DBGSTATE_DHALTED: begin dfsm_trans_next = ~dfsm_update ? ~dfsm_trans & dm_run_req : dfsm_trans; dfsm_update_next = ~dfsm_update & dfsm_trans; dfsm_event_next = dfsm_update; end default : begin dfsm_trans_next = 'X; dfsm_update_next = 'X; dfsm_event_next = 'X; end endcase end end //------------------------------------------------------------------------------ // HART Control logic //------------------------------------------------------------------------------ // // HART Control logic consists of the following functional units: // - Control signals // - HART Run Control register // - HART Halt Request Time-Out counter // // Control logic always_comb begin hart_cmd_req = 1'b0; if (~pipe2hdu_rdc_qlfy_i) begin hart_cmd_req = 1'b0; end else begin case (dbg_state) SCR1_HDU_DBGSTATE_RESET : hart_cmd_req = dm2hdu_cmd_req_i; SCR1_HDU_DBGSTATE_DHALTED: hart_cmd_req = (dfsm_update | dfsm_trans); SCR1_HDU_DBGSTATE_RUN, SCR1_HDU_DBGSTATE_DRUN : hart_cmd_req = ~dfsm_update & dfsm_trans; default : hart_cmd_req = 'X; endcase end end assign hart_halt_req = dm_cmd_dhalted & hart_cmd_req; assign hart_resume_req = (dm_cmd_run | dm_cmd_drun) & hart_cmd_req; // HART Run Control register //------------------------------------------------------------------------------ assign hart_runctrl_clr = (dbg_state_run | dbg_state_drun) & (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED); assign hart_runctrl_upd = dbg_state_dhalted & dfsm_trans_next; always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin hart_runctrl.irq_dsbl <= 1'b0; hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL; hart_runctrl.pc_advmt_dsbl <= 1'b0; hart_runctrl.hwbrkpt_dsbl <= 1'b0; hart_runctrl.redirect <= '0; end else if(clk_en) begin if (hart_runctrl_clr) begin hart_runctrl <= '0; end else begin if (hart_runctrl_upd) begin if (~dm_cmd_drun) begin // Case : resume to RUN state hart_runctrl.irq_dsbl <= csr_dcsr_step ? ~csr_dcsr_stepie : 1'b0; hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL; hart_runctrl.pc_advmt_dsbl <= 1'b0; hart_runctrl.hwbrkpt_dsbl <= 1'b0; hart_runctrl.redirect.sstep <= csr_dcsr_step; hart_runctrl.redirect.ebreak <= csr_dcsr_ebreakm; end else begin // Case : resume to DRUN state hart_runctrl.irq_dsbl <= 1'b1; hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_PBUF; hart_runctrl.pc_advmt_dsbl <= 1'b1; hart_runctrl.hwbrkpt_dsbl <= 1'b1; hart_runctrl.redirect.sstep <= 1'b0; hart_runctrl.redirect.ebreak <= 1'b1; end end end end end // HART Halt Request Time-Out counter //------------------------------------------------------------------------------ // HART goes into halt state only if the halt request is present for timeout period // of time assign halt_req_timeout_cnt_en = hdu2exu_dbg_halt2run_o | (hart_halt_req & ~hdu2exu_dbg_run2halt_o); always_ff @(posedge clk, negedge rst_n) begin if (~rst_n) begin halt_req_timeout_cnt <= '1; end else if (halt_req_timeout_cnt_en) begin halt_req_timeout_cnt <= halt_req_timeout_cnt_next; end end assign halt_req_timeout_cnt_next = hdu2exu_dbg_halt2run_o ? '1 : (hart_halt_req & ~hdu2exu_dbg_run2halt_o) ? halt_req_timeout_cnt - 1'b1 : halt_req_timeout_cnt; assign halt_req_timeout_flag = ~|halt_req_timeout_cnt; //------------------------------------------------------------------------------ // HART Status logic //------------------------------------------------------------------------------ // // HART Status logic consists of the following functional units: // - Debug mode cause decoder // - Hart halt status cause encoder // - Hart halt status register // // Debug mode cause decoder //------------------------------------------------------------------------------ assign dmode_cause_sstep = hart_runctrl.redirect.sstep & pipe2hdu_instret_i; assign dmode_cause_except = dbg_state_drun & pipe2hdu_exu_exc_req_i & ~pipe2hdu_brkpt_i `ifdef SCR1_TDU_EN & ~exu2hdu_ibrkpt_hw_i `endif // SCR1_TDU_EN ; assign dmode_cause_ebreak = hart_runctrl.redirect.ebreak & pipe2hdu_brkpt_i; `ifdef SCR1_TDU_EN assign dmode_cause_tmreq = tdu2hdu_dmode_req_i & exu2hdu_ibrkpt_hw_i; `endif // SCR1_TDU_EN assign dmode_cause_any = dmode_cause_sstep | dmode_cause_ebreak | dmode_cause_except | hart_halt_req `ifdef SCR1_TDU_EN | dmode_cause_tmreq `endif // SCR1_TDU_EN ; // HART halt cause encoder //------------------------------------------------------------------------------ always_comb begin case (1'b1) `ifdef SCR1_TDU_EN dmode_cause_tmreq : hart_haltcause = SCR1_HDU_HALTCAUSE_TMREQ; `endif // SCR1_TDU_EN dmode_cause_ebreak : hart_haltcause = SCR1_HDU_HALTCAUSE_EBREAK; hart_halt_req : hart_haltcause = SCR1_HDU_HALTCAUSE_DMREQ; dmode_cause_sstep : hart_haltcause = SCR1_HDU_HALTCAUSE_SSTEP; default : hart_haltcause = SCR1_HDU_HALTCAUSE_NONE; endcase end // HART halt status register //------------------------------------------------------------------------------ always_ff @(posedge clk, negedge rst_n) begin if (~rst_n) begin hart_haltstatus <= '0; end else if (hart_halt_ack) begin hart_haltstatus.except <= dmode_cause_except; hart_haltstatus.cause <= hart_haltcause; end end assign hart_halt_pnd = (dfsm_trans | dm_dhalt_req) & ~hart_halt_ack; assign hart_halt_ack = ~hdu2exu_dbg_halted_o & (halt_req_timeout_flag | (~pipe2hdu_exu_busy_i & dmode_cause_any)); //------------------------------------------------------------------------------ // Program Buffer (PBUF) logic //------------------------------------------------------------------------------ // // Program Buffer allows to execute small programs in debug mode // // To terminate Program Buffer execution exception should be raised. There are 2 // cases: // - One of PBUF instructions raise an exception // - No PBUF instruction raise an exception before the last PBUF instruction has // been issued. In this case FSM goes into EXCINJECT state and an "Instruction // fetch access fault" exception is injected // PBUF FSM //------------------------------------------------------------------------------ assign ifu_handshake_done = hdu2ifu_pbuf_instr_vd_o & ifu2hdu_pbuf_instr_rdy_i; assign pbuf_addr_end = (pbuf_addr_ff == (SCR1_HDU_PBUF_ADDR_SPAN-1)); assign pbuf_start_fetch = dbg_state_dhalted & (dbg_state_next == SCR1_HDU_DBGSTATE_DRUN); assign pbuf_exc_inj_req = ifu_handshake_done & pbuf_addr_end; assign pbuf_exc_inj_end = pipe2hdu_exu_exc_req_i | ifu_handshake_done; always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin pbuf_fsm_curr <= SCR1_HDU_PBUFSTATE_IDLE; end else if(clk_en) begin pbuf_fsm_curr <= pbuf_fsm_next; end end always_comb begin case (pbuf_fsm_curr) SCR1_HDU_PBUFSTATE_IDLE: begin pbuf_fsm_next = pbuf_start_fetch ? SCR1_HDU_PBUFSTATE_FETCH : SCR1_HDU_PBUFSTATE_IDLE; end SCR1_HDU_PBUFSTATE_FETCH: begin pbuf_fsm_next = pipe2hdu_exu_exc_req_i ? SCR1_HDU_PBUFSTATE_WAIT4END : pbuf_exc_inj_req ? SCR1_HDU_PBUFSTATE_EXCINJECT : SCR1_HDU_PBUFSTATE_FETCH; end SCR1_HDU_PBUFSTATE_EXCINJECT: begin pbuf_fsm_next = pbuf_exc_inj_end ? SCR1_HDU_PBUFSTATE_WAIT4END : SCR1_HDU_PBUFSTATE_EXCINJECT; end SCR1_HDU_PBUFSTATE_WAIT4END: begin pbuf_fsm_next = hdu2exu_dbg_halted_o ? SCR1_HDU_PBUFSTATE_IDLE : SCR1_HDU_PBUFSTATE_WAIT4END; end endcase end assign pbuf_fsm_idle = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_IDLE); assign pbuf_fsm_fetch = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_FETCH); assign pbuf_fsm_excinj = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_EXCINJECT); // Program Buffer address register //------------------------------------------------------------------------------ assign pbuf_addr_next_vd = pbuf_fsm_fetch & ifu_handshake_done & ~pipe2hdu_exu_exc_req_i & ~pbuf_addr_end; always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin pbuf_addr_ff <= '0; end else if(clk_en) begin pbuf_addr_ff <= pbuf_addr_next; end end assign pbuf_addr_next = pbuf_fsm_idle ? '0 : pbuf_addr_next_vd ? pbuf_addr_ff + 1'b1 : pbuf_addr_ff; // Pass instruction from debug program buffer to cpu pipeline with two options: // - through register, better for frequency // - through wires, better for area generate if (HART_PBUF_INSTR_REGOUT_EN) begin always_ff @(posedge clk, negedge rst_n) begin if (~rst_n) begin pbuf_instr_wait_latching <= 1'b0; end else begin pbuf_instr_wait_latching <= ifu_handshake_done; end end end else begin assign pbuf_instr_wait_latching = 1'b0; end endgenerate //------------------------------------------------------------------------------ // Debug CSRs //------------------------------------------------------------------------------ assign csr_upd_on_halt = (dbg_state_reset | dbg_state_run) & (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED); // CSRs select logic //------------------------------------------------------------------------------ always_comb begin : csr_if_regsel csr_dcsr_sel = 1'b0; csr_dpc_sel = 1'b0; csr_dscratch0_sel = 1'b0; //csr_dscratch1_sel = 1'b0; if (csr2hdu_req_i) begin case (csr2hdu_addr_i) SCR1_HDU_DBGCSR_OFFS_DCSR : csr_dcsr_sel = 1'b1; SCR1_HDU_DBGCSR_OFFS_DPC : csr_dpc_sel = 1'b1; SCR1_HDU_DBGCSR_OFFS_DSCRATCH0: csr_dscratch0_sel = 1'b1; default : begin csr_dcsr_sel = 1'bX; csr_dpc_sel = 1'bX; csr_dscratch0_sel = 1'bX; end endcase end end : csr_if_regsel // CSRs read interface //------------------------------------------------------------------------------ assign csr_rd_data = csr_dcsr_out | csr_dpc_out | csr_dscratch0_out; // CSRs write interface //------------------------------------------------------------------------------ assign csr_wr = csr2hdu_req_i; always_comb begin : csr_if_write csr_wr_data = '0; if (csr2hdu_req_i) begin case (csr2hdu_cmd_i) SCR1_CSR_CMD_WRITE : csr_wr_data = csr2hdu_wdata_i; SCR1_CSR_CMD_SET : csr_wr_data = csr_rd_data | csr2hdu_wdata_i; SCR1_CSR_CMD_CLEAR : csr_wr_data = csr_rd_data & (~csr2hdu_wdata_i); default : csr_wr_data = 'X; endcase end end : csr_if_write // Debug Control and Status register //------------------------------------------------------------------------------ // Setups the HART behaviour in Debug Mode and holds Debug status information always_comb begin csr_dcsr_in = csr_wr_data; csr_dcsr_wr = csr_wr & csr_dcsr_sel; csr_dcsr_out = '0; if (csr_dcsr_sel) begin csr_dcsr_out.xdebugver = SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER; csr_dcsr_out.ebreakm = csr_dcsr_ebreakm; csr_dcsr_out.stepie = csr_dcsr_stepie; csr_dcsr_out.step = csr_dcsr_step; csr_dcsr_out.prv = 2'b11; csr_dcsr_out.cause = csr_dcsr_cause; end end always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin csr_dcsr_ebreakm <= 1'b0; csr_dcsr_stepie <= 1'b0; csr_dcsr_step <= 1'b0; end else if(clk_en) begin if (csr_dcsr_wr) begin csr_dcsr_ebreakm <= csr_dcsr_in.ebreakm; csr_dcsr_stepie <= csr_dcsr_in.stepie; csr_dcsr_step <= csr_dcsr_in.step; end end end always_ff @(negedge rst_n, posedge clk) begin if (~rst_n) begin csr_dcsr_cause <= 1'b0; end else if(clk_en) begin if(csr_upd_on_halt) begin csr_dcsr_cause <= hart_haltstatus.cause; end end end // Debug PC register //------------------------------------------------------------------------------ // Saves the virtual address of the next instruction to be executed when Debug // Mode is entered. Could be changed by debugger assign csr_dpc_wr = csr_wr & csr_dpc_sel; always_ff @(posedge clk, negedge rst_n) begin if (~rst_n) begin csr_dpc_ff <= '0; end else if(clk_en) begin csr_dpc_ff <= csr_dpc_next; end end assign csr_dpc_next = csr_upd_on_halt ? pipe2hdu_pc_curr_i : csr_dpc_wr ? csr_wr_data : csr_dpc_ff; assign csr_dpc_out = csr_dpc_sel ? csr_dpc_ff : '0; // Debug Scratch 0 register //------------------------------------------------------------------------------ assign csr_dscratch0_resp = (~dm2hdu_dreg_resp_i | dm2hdu_dreg_fail_i) ? SCR1_CSR_RESP_ER : SCR1_CSR_RESP_OK; assign csr_dscratch0_out = csr_dscratch0_sel ? dm2hdu_dreg_rdata_i : '0; //------------------------------------------------------------------------------ // HDU <-> DM interface //------------------------------------------------------------------------------ assign hdu2dm_hart_event_o = dfsm_event; // HART status always_comb begin hdu2dm_hart_status_o = '0; hdu2dm_hart_status_o.dbg_state = dbg_state; hdu2dm_hart_status_o.except = dbg_state_dhalted & hart_haltstatus.except; hdu2dm_hart_status_o.ebreak = dbg_state_dhalted & (hart_haltstatus.cause == SCR1_HDU_HALTCAUSE_EBREAK); end assign hdu2dm_cmd_rcode_o = dbg_state_reset ? ~pipe2hdu_rdc_qlfy_i | ~pipe2hdu_init_pc_i | ~dm2hdu_cmd_req_i : ~pipe2hdu_rdc_qlfy_i | ~dfsm_update; always_comb begin hdu2dm_cmd_resp_o = 1'b0; case (dbg_state) SCR1_HDU_DBGSTATE_RESET: begin hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & pipe2hdu_init_pc_i & dm2hdu_cmd_req_i; end SCR1_HDU_DBGSTATE_RUN: begin hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & dfsm_update & dm2hdu_cmd_req_i; end SCR1_HDU_DBGSTATE_DHALTED: begin hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i ? dfsm_update : dm2hdu_cmd_req_i; end SCR1_HDU_DBGSTATE_DRUN: begin hdu2dm_cmd_resp_o = (~pipe2hdu_rdc_qlfy_i | dfsm_update) & dm2hdu_cmd_req_i; end default: begin hdu2dm_cmd_resp_o = 'X; end endcase end assign hdu2dm_pbuf_addr_o = pbuf_addr_ff; assign hdu2dm_dreg_req_o = csr_dscratch0_sel; assign hdu2dm_dreg_wr_o = csr_wr & csr_dscratch0_sel; assign hdu2dm_dreg_wdata_o = csr_wr_data; //------------------------------------------------------------------------------ // HDU <-> EXU interface //------------------------------------------------------------------------------ assign hdu2exu_dbg_halted_o = (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED) | (~pipe2hdu_rdc_qlfy_i & ~dbg_state_run); assign hdu2exu_dbg_run_start_o = dbg_state_dhalted & pipe2hdu_rdc_qlfy_i & dfsm_update; assign hdu2exu_dbg_halt2run_o = hdu2exu_dbg_halted_o & hart_resume_req `ifdef SCR1_CLKCTRL_EN & clk_pipe_en `endif // SCR1_CLKCTRL_EN ; assign hdu2exu_dbg_run2halt_o = hart_halt_ack; assign hdu2exu_pbuf_fetch_o = hart_runctrl.fetch_src; assign hdu2exu_irq_dsbl_o = hart_runctrl.irq_dsbl; assign hdu2exu_pc_advmt_dsbl_o = hart_runctrl.pc_advmt_dsbl; // No change in arch. state if dmode caused by breakpoint assign hdu2exu_no_commit_o = dmode_cause_ebreak `ifdef SCR1_TDU_EN | dmode_cause_tmreq `endif // SCR1_TDU_EN ; assign hdu2exu_dmode_sstep_en_o = hart_runctrl.redirect.sstep; assign hdu2exu_dbg_new_pc_o = csr_dpc_ff; //------------------------------------------------------------------------------ // HDU <-> IFU interface //------------------------------------------------------------------------------ assign hdu2ifu_pbuf_instr_vd_o = (pbuf_fsm_fetch | pbuf_fsm_excinj) & ~pbuf_instr_wait_latching; assign hdu2ifu_pbuf_instr_err_o = pbuf_fsm_excinj; generate if (HART_PBUF_INSTR_REGOUT_EN) begin always_ff @(posedge clk) begin hdu2ifu_pbuf_instr_o <= dm2hdu_pbuf_instr_i; end end else begin assign hdu2ifu_pbuf_instr_o = dm2hdu_pbuf_instr_i; end endgenerate //------------------------------------------------------------------------------ // HDU <-> CSR interface //------------------------------------------------------------------------------ assign csr_addr_dscratch0 = (csr2hdu_addr_i == SCR1_HDU_DBGCSR_OFFS_DSCRATCH0); assign hdu2csr_resp_o = ~dbg_state_drun ? SCR1_CSR_RESP_ER : csr_addr_dscratch0 ? csr_dscratch0_resp : csr2hdu_req_i ? SCR1_CSR_RESP_OK : SCR1_CSR_RESP_ER; assign hdu2csr_rdata_o = csr_rd_data; `ifdef SCR1_TDU_EN //------------------------------------------------------------------------------ // HDU <-> TDU interface //------------------------------------------------------------------------------ assign hdu2tdu_hwbrk_dsbl_o = hart_runctrl.hwbrkpt_dsbl; `endif // SCR1_TDU_EN `ifdef SCR1_TRGT_SIMULATION //------------------------------------------------------------------------------- // Assertion //------------------------------------------------------------------------------- SVA_HDU_XCHECK_COMMON : assert property ( @(negedge clk) disable iff (~rst_n) !$isunknown( {rst_n,clk,clk_en,csr2hdu_req_i,pipe2hdu_rdc_qlfy_i} ) ) else $error("HDU Error: common signals are in X state"); SVA_HDU_XCHECK_CSR_INTF : assert property ( @(negedge clk) disable iff (~rst_n) csr2hdu_req_i |-> !$isunknown( {csr2hdu_cmd_i,csr2hdu_addr_i,csr2hdu_wdata_i} ) ) else $error("HDU Error: CSR i/f is in X state"); SVA_HDU_XCHECK_DM_INTF : assert property ( @(negedge clk) disable iff (~rst_n) !$isunknown( {dm2hdu_cmd_req_i,dm2hdu_cmd_i,dm2hdu_dreg_resp_i, dm2hdu_dreg_fail_i} ) ) else $error("HDU Error: DM i/f is in X state"); SVA_HDU_XCHECK_TDU_INTF : assert property ( @(negedge clk) disable iff (~rst_n) !$isunknown( {tdu2hdu_dmode_req_i,exu2hdu_ibrkpt_hw_i} ) ) else $error("HDU Error: TDU i/f is in X state"); SVA_HDU_XCHECK_HART_INTF : assert property ( @(negedge clk) disable iff (~rst_n) !$isunknown( {pipe2hdu_exu_busy_i,pipe2hdu_instret_i,pipe2hdu_init_pc_i,pipe2hdu_exu_exc_req_i,pipe2hdu_brkpt_i, pipe2hdu_pc_curr_i,ifu2hdu_pbuf_instr_rdy_i} ) ) else $error("HDU Error: HART i/f is in X state"); `endif // SCR1_TRGT_SIMULATION endmodule : scr1_pipe_hdu `endif // SCR1_DBG_EN