blob: febeaeec1ed9759e2d70d4a952243e6cc8c3cb92 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Syntacore LLC © 2016-2021
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Syntacore LLC
// //////////////////////////////////////////////////////////////////////////
/// @file <scr1_dm.sv>
/// @brief Debug Module (DM)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Allows debugger to perform a system reset (ndm_rst)
// - Allows debugger to control the HART's state
// - Provides debugger with information about the current HART's state
// - Provides debugger with Abstract Command interface that allows to:
// - Access MPRF registers
// - Access CSR registers
// - Access memory with the same view and permission as the hart has
// - Provides debugger with Abstract Command status information (busy flag and error code)
// - Provides debugger with Program Buffer functionality that allows to execute
// small programs on a halted HART
//
// Structure:
// - DM <-> DMI interface
// - DM registers:
// - DMCONTROL
// - DMSTATUS
// - Abstract Command Control logic
// - Abstract Command FSM
// - Abstract Command Status logic
// - Abstract Instruction logic
// - Abstract registers:
// - COMMAND
// - ABSTRACTAUTO
// - PROGBUF0..5
// - DATA0..1
// - DHI FSM
// - HART command registers
// - DHI interface
//
//
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_csr.svh"
`include "scr1_dm.svh"
module scr1_dm (
// System
input logic rst_n, // DM reset
input logic clk, // DM clock
// DM internal interface
input logic dmi2dm_req_i, // DMI request
input logic dmi2dm_wr_i, // DMI write
input logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi2dm_addr_i, // DMI address
input logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi2dm_wdata_i, // DMI write data
output logic dm2dmi_resp_o, // DMI response
output logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm2dmi_rdata_o, // DMI read data
// DM <-> Pipeline: HART Run Control i/f
output logic ndm_rst_n_o, // Non-DM Reset output
output logic hart_rst_n_o, // HART reset output
output logic dm2pipe_active_o, // Debug Module active flag
output logic dm2pipe_cmd_req_o, // Request to pipe
output type_scr1_hdu_dbgstates_e dm2pipe_cmd_o, // Command to pipe
input logic pipe2dm_cmd_resp_i, // Response to Debug Module
input logic pipe2dm_cmd_rcode_i, // HART Command return code: 0 - Ok; 1 - Error
input logic pipe2dm_hart_event_i, // HART event flag
input type_scr1_hdu_hartstatus_s pipe2dm_hart_status_i, // HART Status
input logic [`SCR1_XLEN-1:0] soc2dm_fuse_mhartid_i, // RO MHARTID value
input logic [`SCR1_XLEN-1:0] pipe2dm_pc_sample_i, // RO PC value for sampling
// HART Abstract Command / Program Buffer i/f
input logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pipe2dm_pbuf_addr_i, // Program Buffer address
output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2pipe_pbuf_instr_o, // Program Buffer instruction
// HART Abstract Data regs i/f
input logic pipe2dm_dreg_req_i, // Abstract Data Register request
input logic pipe2dm_dreg_wr_i, // Abstract Data Register write
input logic [`SCR1_XLEN-1:0] pipe2dm_dreg_wdata_i, // Abstract Data Register write data
output logic dm2pipe_dreg_resp_o, // Abstract Data Register response
output logic dm2pipe_dreg_fail_o, // Abstract Data Register fail - possibly not needed ?
output logic [`SCR1_XLEN-1:0] dm2pipe_dreg_rdata_o // Abstract Data Register read data
);
//------------------------------------------------------------------------------
// Local types declaration
//------------------------------------------------------------------------------
typedef enum logic [3:0] {
ABS_STATE_IDLE,
ABS_STATE_ERR,
ABS_STATE_EXEC,
ABS_STATE_XREG_RW,
ABS_STATE_MEM_SAVE_XREG,
ABS_STATE_MEM_SAVE_XREG_FORADDR,
ABS_STATE_MEM_RW,
ABS_STATE_MEM_RETURN_XREG,
ABS_STATE_MEM_RETURN_XREG_FORADDR,
ABS_STATE_CSR_RO,
ABS_STATE_CSR_SAVE_XREG,
ABS_STATE_CSR_RW,
ABS_STATE_CSR_RETURN_XREG
} type_scr1_abs_fsm_e;
typedef enum logic [2:0] {
DHI_STATE_IDLE,
DHI_STATE_EXEC,
DHI_STATE_EXEC_RUN,
DHI_STATE_EXEC_HALT,
DHI_STATE_HALT_REQ,
DHI_STATE_RESUME_REQ,
DHI_STATE_RESUME_RUN
} type_scr1_dhi_fsm_e;
//typedef enum logic [SCR1_DBG_ABSTRACTCS_CMDERR_WDTH:0] {
parameter ABS_ERR_NONE = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d0);
parameter ABS_ERR_BUSY = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d1);
parameter ABS_ERR_CMD = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d2);
parameter ABS_ERR_EXCEPTION = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d3);
parameter ABS_ERR_NOHALT = (SCR1_DBG_ABSTRACTCS_CMDERR_WDTH+1)'('d4);
//} type_scr1_abs_err_e;
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
// Abstract instruction opcode parameters
localparam SCR1_OP_SYSTEM = 7'b111_0011;
localparam SCR1_OP_LOAD = 7'b000_0011;
localparam SCR1_OP_STORE = 7'b010_0011;
// Abstract instruction funct3 parameters
localparam SCR1_FUNCT3_CSRRW = 3'b001;
localparam SCR1_FUNCT3_CSRRS = 3'b010;
localparam SCR1_FUNCT3_SB = 3'b000;
localparam SCR1_FUNCT3_SH = 3'b001;
localparam SCR1_FUNCT3_SW = 3'b010;
localparam SCR1_FUNCT3_LW = 3'b010;
localparam SCR1_FUNCT3_LBU = 3'b100;
localparam SCR1_FUNCT3_LHU = 3'b101;
// DMCONTROL parameters
//------------------------------------------------------------------------------
localparam DMCONTROL_HARTRESET = 1'd0;
localparam DMCONTROL_RESERVEDB = 1'd0;
localparam DMCONTROL_HASEL = 1'd0;
localparam DMCONTROL_HARTSELLO = 1'd0;
localparam DMCONTROL_HARTSELHI = 1'd0;
localparam DMCONTROL_RESERVEDA = 1'd0;
// DMSTATUS parameters
//------------------------------------------------------------------------------
localparam DMSTATUS_RESERVEDC = 1'd0;
localparam DMSTATUS_IMPEBREAK = 1'd1;
localparam DMSTATUS_RESERVEDB = 1'd0;
localparam DMSTATUS_ALLUNAVAIL = 1'd0;
localparam DMSTATUS_ANYUNAVAIL = 1'd0;
localparam DMSTATUS_ALLANYUNAVAIL = 1'd0;
localparam DMSTATUS_ALLANYNONEXIST = 1'b0;
localparam DMSTATUS_AUTHENTICATED = 1'd1;
localparam DMSTATUS_AUTHBUSY = 1'd0;
localparam DMSTATUS_RESERVEDA = 1'd0;
localparam DMSTATUS_DEVTREEVALID = 1'd0;
localparam DMSTATUS_VERSION = 2'd2;
// HARTINFO parameters
//------------------------------------------------------------------------------
localparam HARTINFO_RESERVEDB = 1'd0;
localparam HARTINFO_NSCRATCH = 4'd1;
localparam HARTINFO_RESERVEDA = 1'd0;
localparam HARTINFO_DATAACCESS = 1'd0;
localparam HARTINFO_DATASIZE = 4'd1;
localparam HARTINFO_DATAADDR = 12'h7b2;
// ABSTRACTCS parameters
//------------------------------------------------------------------------------
localparam ABSTRACTCS_RESERVEDD = 1'd0;
localparam ABSTRACTCS_PROGBUFSIZE = 5'd6;
localparam ABSTRACTCS_RESERVEDC = 1'd0;
localparam ABSTRACTCS_RESERVEDB = 1'd0;
localparam ABSTRACTCS_RESERVEDA = 1'd0;
localparam ABSTRACTCS_DATACOUNT = 4'd2;
localparam ABS_CMD_HARTREG = 1'd0;
localparam ABS_CMD_HARTMEM = 2'd2;
localparam ABS_CMD_HARTREG_CSR = 4'b0000;
localparam ABS_CMD_HARTREG_INTFPU = 4'b0001;
localparam ABS_CMD_HARTREG_INT = 7'b000_0000;
localparam ABS_CMD_HARTREG_FPU = 7'b000_0001;
localparam ABS_EXEC_EBREAK = 32'b000000000001_00000_000_00000_1110011;
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// DM <-> DMI interface internal signals
//------------------------------------------------------------------------------
// Register selection signals
logic dmi_req_dmcontrol;
logic dmi_req_abstractcs;
logic dmi_req_abstractauto;
logic dmi_req_command;
logic dmi_rpt_command;
logic dmi_req_data0;
logic dmi_req_data1;
logic dmi_req_progbuf0;
logic dmi_req_progbuf1;
logic dmi_req_progbuf2;
logic dmi_req_progbuf3;
logic dmi_req_progbuf4;
logic dmi_req_progbuf5;
logic dmi_req_any;
// Registers write request signals
logic dmcontrol_wr_req;
logic abstractcs_wr_req;
logic data0_wr_req;
logic data1_wr_req;
logic dreg_wr_req;
logic command_wr_req;
logic autoexec_wr_req;
logic progbuf0_wr_req;
logic progbuf1_wr_req;
logic progbuf2_wr_req;
logic progbuf3_wr_req;
logic progbuf4_wr_req;
logic progbuf5_wr_req;
// DM registers
//------------------------------------------------------------------------------
// DM clock enable signals
logic clk_en_dm;
logic clk_en_dm_ff;
// DMCONTROL register signals
logic dmcontrol_haltreq_ff;
logic dmcontrol_haltreq_next;
logic dmcontrol_resumereq_ff;
logic dmcontrol_resumereq_next;
logic dmcontrol_ackhavereset_ff;
logic dmcontrol_ackhavereset_next;
logic dmcontrol_ndmreset_ff;
logic dmcontrol_ndmreset_next;
logic dmcontrol_dmactive_ff;
logic dmcontrol_dmactive_next;
// Auxilary Skip Reset On Powerup register
logic havereset_skip_pwrup_ff;
logic havereset_skip_pwrup_next;
// DMSTATUS register signals
logic dmstatus_allany_havereset_ff;
logic dmstatus_allany_havereset_next;
logic dmstatus_allany_resumeack_ff;
logic dmstatus_allany_resumeack_next;
logic dmstatus_allany_halted_ff;
logic dmstatus_allany_halted_next;
// Abstract command control logic signals
//------------------------------------------------------------------------------
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] abs_cmd;
logic abs_cmd_csr_ro;
logic [SCR1_DBG_COMMAND_TYPE_WDTH:0] abs_cmd_type;
logic abs_cmd_regacs;
logic [SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI-12:0] abs_cmd_regtype;
logic [6:0] abs_cmd_regfile;
logic abs_cmd_regwr;
logic [SCR1_DBG_COMMAND_ACCESSREG_SIZE_WDTH:0] abs_cmd_regsize;
logic abs_cmd_execprogbuf;
logic abs_cmd_regvalid;
logic [2:0] abs_cmd_memsize;
logic abs_cmd_memwr;
logic abs_cmd_memvalid;
logic abs_cmd_regsize_vd;
logic abs_cmd_memsize_vd;
logic abs_cmd_wr_ff;
logic abs_cmd_wr_next;
logic abs_cmd_postexec_ff;
logic abs_cmd_postexec_next;
logic [11:0] abs_cmd_regno;
logic [11:0] abs_cmd_regno_ff;
logic [1:0] abs_cmd_size_ff;
logic [1:0] abs_cmd_size_next;
logic abs_reg_access_csr;
logic abs_reg_access_mprf;
logic abs_cmd_hartreg_vd;
logic abs_cmd_hartmem_vd;
logic abs_cmd_reg_access_req;
logic abs_cmd_csr_access_req;
logic abs_cmd_mprf_access_req;
logic abs_cmd_execprogbuf_req;
logic abs_cmd_csr_ro_access_vd;
logic abs_cmd_csr_rw_access_vd;
logic abs_cmd_mprf_access_vd;
logic abs_cmd_mem_access_vd;
// Abstract FSM signals
//------------------------------------------------------------------------------
type_scr1_abs_fsm_e abs_fsm_ff;
type_scr1_abs_fsm_e abs_fsm_next;
logic abs_fsm_idle;
logic abs_fsm_exec;
logic abs_fsm_csr_ro;
logic abs_fsm_err;
logic abs_fsm_use_addr;
// Abstract registers
//------------------------------------------------------------------------------
logic clk_en_abs;
// ABSTRACTCS register signals
logic abstractcs_busy;
logic abstractcs_ro_en;
// COMMAND register signals
logic [`SCR1_XLEN-1:0] abs_command_ff;
logic [`SCR1_XLEN-1:0] abs_command_next;
// ABSTRACTAUTO register signals
logic abs_autoexec_ff;
logic abs_autoexec_next;
// Program buffer registers
logic [`SCR1_XLEN-1:0] abs_progbuf0_ff;
logic [`SCR1_XLEN-1:0] abs_progbuf1_ff;
logic [`SCR1_XLEN-1:0] abs_progbuf2_ff;
logic [`SCR1_XLEN-1:0] abs_progbuf3_ff;
logic [`SCR1_XLEN-1:0] abs_progbuf4_ff;
logic [`SCR1_XLEN-1:0] abs_progbuf5_ff;
// Data 0/1 registers
logic data0_xreg_save;
logic [`SCR1_XLEN-1:0] abs_data0_ff;
logic [`SCR1_XLEN-1:0] abs_data0_next;
logic [`SCR1_XLEN-1:0] abs_data1_ff;
logic [`SCR1_XLEN-1:0] abs_data1_next;
// Abstract command status logic signals
//------------------------------------------------------------------------------
// Abstract error exception flag register
logic abs_err_exc_upd;
logic abs_err_exc_ff;
logic abs_err_exc_next;
logic abs_err_acc_busy_upd;
logic abs_err_acc_busy_ff;
logic abs_err_acc_busy_next;
logic [SCR1_DBG_ABSTRACTCS_CMDERR_WDTH:0] abstractcs_cmderr_ff;
logic [SCR1_DBG_ABSTRACTCS_CMDERR_WDTH:0] abstractcs_cmderr_next;
// Abstract instruction signals
//------------------------------------------------------------------------------
// Abstract instruction execution request register
logic abs_exec_req_next;
logic abs_exec_req_ff;
// Abstract instruction register
logic [4:0] abs_instr_rd;
logic [4:0] abs_instr_rs1;
logic [4:0] abs_instr_rs2;
logic [2:0] abs_instr_mem_funct3;
logic [`SCR1_XLEN-1:0] abs_exec_instr_next;
logic [`SCR1_XLEN-1:0] abs_exec_instr_ff;
// DHI FSM signals
//------------------------------------------------------------------------------
type_scr1_dhi_fsm_e dhi_fsm_next;
type_scr1_dhi_fsm_e dhi_fsm_ff;
type_scr1_dhi_fsm_e dhi_req;
logic dhi_fsm_idle;
logic dhi_fsm_exec;
logic dhi_fsm_exec_halt;
logic dhi_fsm_halt_req;
logic dhi_fsm_resume_req;
// DHI interface signals
//------------------------------------------------------------------------------
logic cmd_resp_ok;
logic hart_rst_unexp;
logic halt_req_vd;
logic resume_req_vd;
logic dhi_resp;
logic dhi_resp_exc;
logic hart_pbuf_ebreak_ff;
logic hart_pbuf_ebreak_next;
// HART command registers
//------------------------------------------------------------------------------
logic hart_cmd_req_ff;
logic hart_cmd_req_next;
type_scr1_hdu_dbgstates_e hart_cmd_ff;
type_scr1_hdu_dbgstates_e hart_cmd_next;
// HART state signals
//------------------------------------------------------------------------------
logic hart_state_reset;
logic hart_state_run;
logic hart_state_drun;
logic hart_state_dhalt;
//------------------------------------------------------------------------------
// DM <-> DMI interface
//------------------------------------------------------------------------------
// Register selection logic
//------------------------------------------------------------------------------
always_comb begin
dmi_req_dmcontrol = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DMCONTROL);
dmi_req_abstractcs = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_ABSTRACTCS);
dmi_req_abstractauto = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_ABSTRACTAUTO);
dmi_req_data0 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DATA0);
dmi_req_data1 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_DATA1);
dmi_req_command = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_COMMAND);
dmi_rpt_command = (abs_autoexec_ff & dmi_req_data0);
dmi_req_progbuf0 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF0);
dmi_req_progbuf1 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF1);
dmi_req_progbuf2 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF2);
dmi_req_progbuf3 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF3);
dmi_req_progbuf4 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF4);
dmi_req_progbuf5 = dmi2dm_req_i & (dmi2dm_addr_i == SCR1_DBG_PROGBUF5);
end
assign dmi_req_any = dmi_req_command | dmi_rpt_command | dmi_req_abstractauto
| dmi_req_data0 | dmi_req_data1 | dmi_req_progbuf0
| dmi_req_progbuf1 | dmi_req_progbuf2 | dmi_req_progbuf3
| dmi_req_progbuf4 | dmi_req_progbuf5;
// Read data multiplexer
//------------------------------------------------------------------------------
always_comb begin
dm2dmi_rdata_o = '0;
case (dmi2dm_addr_i)
SCR1_DBG_DMSTATUS: begin
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDC_HI:
SCR1_DBG_DMSTATUS_RESERVEDC_LO] = DMSTATUS_RESERVEDC;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_IMPEBREAK] = DMSTATUS_IMPEBREAK;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDB_HI:
SCR1_DBG_DMSTATUS_RESERVEDB_LO] = DMSTATUS_RESERVEDB;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLHAVERESET] = dmstatus_allany_havereset_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYHAVERESET] = dmstatus_allany_havereset_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLRESUMEACK] = dmstatus_allany_resumeack_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYRESUMEACK] = dmstatus_allany_resumeack_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLNONEXISTENT] = DMSTATUS_ALLANYNONEXIST;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYNONEXISTENT] = DMSTATUS_ALLANYNONEXIST;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLUNAVAIL] = DMSTATUS_ALLANYUNAVAIL;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYUNAVAIL] = DMSTATUS_ALLANYUNAVAIL;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLRUNNING] = ~dmstatus_allany_halted_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYRUNNING] = ~dmstatus_allany_halted_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ALLHALTED] = dmstatus_allany_halted_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_ANYHALTED] = dmstatus_allany_halted_ff;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_AUTHENTICATED] = DMSTATUS_AUTHENTICATED;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_AUTHBUSY] = DMSTATUS_AUTHBUSY;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_RESERVEDA] = DMSTATUS_RESERVEDA;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_DEVTREEVALID] = DMSTATUS_DEVTREEVALID;
dm2dmi_rdata_o[SCR1_DBG_DMSTATUS_VERSION_HI:
SCR1_DBG_DMSTATUS_VERSION_LO] = DMSTATUS_VERSION;;
end
SCR1_DBG_DMCONTROL: begin
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HALTREQ] = dmcontrol_haltreq_ff;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESUMEREQ] = dmcontrol_resumereq_ff;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTRESET] = DMCONTROL_HARTRESET;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_ACKHAVERESET] = dmcontrol_ackhavereset_ff;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESERVEDB] = DMCONTROL_RESERVEDB;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HASEL] = DMCONTROL_HASEL;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTSELLO_HI:
SCR1_DBG_DMCONTROL_HARTSELLO_LO] = DMCONTROL_HARTSELLO;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_HARTSELHI_HI:
SCR1_DBG_DMCONTROL_HARTSELHI_LO] = DMCONTROL_HARTSELHI;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_RESERVEDA_HI:
SCR1_DBG_DMCONTROL_RESERVEDA_LO] = DMCONTROL_RESERVEDA;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_NDMRESET] = dmcontrol_ndmreset_ff;
dm2dmi_rdata_o[SCR1_DBG_DMCONTROL_DMACTIVE] = dmcontrol_dmactive_ff;
end
SCR1_DBG_ABSTRACTCS: begin
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDD_HI:
SCR1_DBG_ABSTRACTCS_RESERVEDD_LO] = ABSTRACTCS_RESERVEDD;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_HI:
SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_LO] = ABSTRACTCS_PROGBUFSIZE;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDC_HI:
SCR1_DBG_ABSTRACTCS_RESERVEDC_LO] = ABSTRACTCS_RESERVEDC;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_BUSY] = abstractcs_busy;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDB] = ABSTRACTCS_RESERVEDB;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_CMDERR_HI:
SCR1_DBG_ABSTRACTCS_CMDERR_LO] = abstractcs_cmderr_ff;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_RESERVEDA_HI:
SCR1_DBG_ABSTRACTCS_RESERVEDA_LO] = ABSTRACTCS_RESERVEDA;
dm2dmi_rdata_o[SCR1_DBG_ABSTRACTCS_DATACOUNT_HI:
SCR1_DBG_ABSTRACTCS_DATACOUNT_LO] = ABSTRACTCS_DATACOUNT;
end
SCR1_DBG_HARTINFO: begin
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_RESERVEDB_HI:
SCR1_DBG_HARTINFO_RESERVEDB_LO] = HARTINFO_RESERVEDB;
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_NSCRATCH_HI:
SCR1_DBG_HARTINFO_NSCRATCH_LO] = HARTINFO_NSCRATCH;
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_RESERVEDA_HI:
SCR1_DBG_HARTINFO_RESERVEDA_LO] = HARTINFO_RESERVEDA;
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATAACCESS] = HARTINFO_DATAACCESS;
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATASIZE_HI:
SCR1_DBG_HARTINFO_DATASIZE_LO] = HARTINFO_DATASIZE;
dm2dmi_rdata_o[SCR1_DBG_HARTINFO_DATAADDR_HI:
SCR1_DBG_HARTINFO_DATAADDR_LO] = HARTINFO_DATAADDR;
end
SCR1_DBG_ABSTRACTAUTO: dm2dmi_rdata_o[0] = abs_autoexec_ff;
SCR1_DBG_DATA0 : dm2dmi_rdata_o = abs_data0_ff;
SCR1_DBG_DATA1 : dm2dmi_rdata_o = abs_data1_ff;
SCR1_DBG_PROGBUF0 : dm2dmi_rdata_o = abs_progbuf0_ff;
SCR1_DBG_PROGBUF1 : dm2dmi_rdata_o = abs_progbuf1_ff;
SCR1_DBG_PROGBUF2 : dm2dmi_rdata_o = abs_progbuf2_ff;
SCR1_DBG_PROGBUF3 : dm2dmi_rdata_o = abs_progbuf3_ff;
SCR1_DBG_PROGBUF4 : dm2dmi_rdata_o = abs_progbuf4_ff;
SCR1_DBG_PROGBUF5 : dm2dmi_rdata_o = abs_progbuf5_ff;
SCR1_DBG_HALTSUM0 : dm2dmi_rdata_o[0] = dmstatus_allany_halted_ff;
default: begin
dm2dmi_rdata_o = '0;
end
endcase
end
// Response
assign dm2dmi_resp_o = 1'b1;
// Write requests signals
//------------------------------------------------------------------------------
assign dmcontrol_wr_req = dmi_req_dmcontrol & dmi2dm_wr_i;
assign data0_wr_req = dmi_req_data0 & dmi2dm_wr_i;
assign data1_wr_req = dmi_req_data1 & dmi2dm_wr_i;
assign dreg_wr_req = pipe2dm_dreg_req_i & pipe2dm_dreg_wr_i;
assign command_wr_req = dmi_req_command & dmi2dm_wr_i;
assign autoexec_wr_req = dmi_req_abstractauto & dmi2dm_wr_i;
assign progbuf0_wr_req = dmi_req_progbuf0 & dmi2dm_wr_i;
assign progbuf1_wr_req = dmi_req_progbuf1 & dmi2dm_wr_i;
assign progbuf2_wr_req = dmi_req_progbuf2 & dmi2dm_wr_i;
assign progbuf3_wr_req = dmi_req_progbuf3 & dmi2dm_wr_i;
assign progbuf4_wr_req = dmi_req_progbuf4 & dmi2dm_wr_i;
assign progbuf5_wr_req = dmi_req_progbuf5 & dmi2dm_wr_i;
assign abstractcs_wr_req = dmi_req_abstractcs & dmi2dm_wr_i;
// HART state signals
//------------------------------------------------------------------------------
assign hart_state_reset = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_RESET);
assign hart_state_run = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_RUN);
assign hart_state_dhalt = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_DHALTED);
assign hart_state_drun = (pipe2dm_hart_status_i.dbg_state == SCR1_HDU_DBGSTATE_DRUN);
//------------------------------------------------------------------------------
// DM registers
//------------------------------------------------------------------------------
//
// Registers:
// - DM clock enable register
// - Auxilary Skip Reset On Powerup register
// - DMCONTROL register
// - DMSTATUS register
// DM clock enable logic
//------------------------------------------------------------------------------
assign clk_en_dm = dmcontrol_wr_req | dmcontrol_dmactive_ff | clk_en_dm_ff;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
clk_en_dm_ff <= 1'b0;
end else if (clk_en_dm) begin
clk_en_dm_ff <= dmcontrol_dmactive_ff;
end
end
assign dm2pipe_active_o = clk_en_dm_ff;
// DMCONTROL register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
dmcontrol_dmactive_ff <= 1'b0;
dmcontrol_ndmreset_ff <= 1'b0;
dmcontrol_ackhavereset_ff <= 1'b0;
dmcontrol_haltreq_ff <= 1'b0;
dmcontrol_resumereq_ff <= 1'b0;
end else if (clk_en_dm) begin
dmcontrol_dmactive_ff <= dmcontrol_dmactive_next;
dmcontrol_ndmreset_ff <= dmcontrol_ndmreset_next;
dmcontrol_ackhavereset_ff <= dmcontrol_ackhavereset_next;
dmcontrol_haltreq_ff <= dmcontrol_haltreq_next;
dmcontrol_resumereq_ff <= dmcontrol_resumereq_next;
end
end
assign dmcontrol_dmactive_next = dmcontrol_wr_req
? dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_DMACTIVE]
: dmcontrol_dmactive_ff;
always_comb begin
dmcontrol_ndmreset_next = dmcontrol_ndmreset_ff;
dmcontrol_ackhavereset_next = dmcontrol_ackhavereset_ff;
dmcontrol_haltreq_next = dmcontrol_haltreq_ff;
dmcontrol_resumereq_next = dmcontrol_resumereq_ff;
if (~dmcontrol_dmactive_ff) begin
dmcontrol_ndmreset_next = 1'b0;
dmcontrol_ackhavereset_next = 1'b0;
dmcontrol_haltreq_next = 1'b0;
dmcontrol_resumereq_next = 1'b0;
end else if (dmcontrol_wr_req) begin
dmcontrol_ndmreset_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_NDMRESET];
dmcontrol_ackhavereset_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_ACKHAVERESET];
dmcontrol_haltreq_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_HALTREQ];
dmcontrol_resumereq_next = dmi2dm_wdata_i[SCR1_DBG_DMCONTROL_RESUMEREQ];
end
end
// Reset signal for system controlled by Debug Module
assign hart_rst_n_o = ~dmcontrol_ndmreset_ff;
assign ndm_rst_n_o = ~dmcontrol_ndmreset_ff;
// Skip reset on powerup register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
havereset_skip_pwrup_ff <= 1'b1;
end else if (clk_en_dm) begin
havereset_skip_pwrup_ff <= havereset_skip_pwrup_next;
end
end
assign havereset_skip_pwrup_next = ~dmcontrol_dmactive_ff ? 1'b1
: havereset_skip_pwrup_ff ? hart_state_reset & ndm_rst_n_o & hart_rst_n_o
: havereset_skip_pwrup_ff;
// DMSTATUS register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
dmstatus_allany_havereset_ff <= 1'b0;
dmstatus_allany_resumeack_ff <= 1'b0;
dmstatus_allany_halted_ff <= 1'b0;
end else if (clk_en_dm) begin
dmstatus_allany_havereset_ff <= dmstatus_allany_havereset_next;
dmstatus_allany_resumeack_ff <= dmstatus_allany_resumeack_next;
dmstatus_allany_halted_ff <= dmstatus_allany_halted_next;
end
end
assign dmstatus_allany_havereset_next = ~dmcontrol_dmactive_ff ? 1'b0
: ~havereset_skip_pwrup_ff & hart_state_reset ? 1'b1
: dmcontrol_ackhavereset_ff ? 1'b0
: dmstatus_allany_havereset_ff;
assign dmstatus_allany_resumeack_next = ~dmcontrol_dmactive_ff ? 1'b0
: ~dmcontrol_resumereq_ff ? 1'b0
: hart_state_run ? 1'b1
: dmstatus_allany_resumeack_ff;
assign dmstatus_allany_halted_next = ~dmcontrol_dmactive_ff ? 1'b0
: hart_state_dhalt ? 1'b1
: hart_state_run ? 1'b0
: dmstatus_allany_halted_ff;
//------------------------------------------------------------------------------
// Abstract Command control logic
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - Abstract command decoder
// - Abstract command access valid flags
// - Abstract command control registers
assign clk_en_abs = clk_en_dm & dmcontrol_dmactive_ff;
// Abstract command decoder
//------------------------------------------------------------------------------
assign abs_cmd = dmi_req_command ? dmi2dm_wdata_i : abs_command_ff;
always_comb begin
abs_cmd_regno = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_REGNO_LO +: 12];
abs_cmd_csr_ro = (abs_cmd_regno == SCR1_CSR_ADDR_MISA)
| (abs_cmd_regno == SCR1_CSR_ADDR_MVENDORID)
| (abs_cmd_regno == SCR1_CSR_ADDR_MARCHID)
| (abs_cmd_regno == SCR1_CSR_ADDR_MIMPID)
| (abs_cmd_regno == SCR1_CSR_ADDR_MHARTID)
| (abs_cmd_regno == SCR1_HDU_DBGCSR_ADDR_DPC);
abs_cmd_type = abs_cmd[SCR1_DBG_COMMAND_TYPE_HI:SCR1_DBG_COMMAND_TYPE_LO];
abs_cmd_regacs = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_TRANSFER];
abs_cmd_regtype = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI:12];
abs_cmd_regfile = abs_cmd[11:5];
abs_cmd_regsize = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI:
SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO];
abs_cmd_regwr = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_WRITE];
abs_cmd_execprogbuf = abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_POSTEXEC];
abs_cmd_regvalid = ~(|{abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_RESERVEDB],
abs_cmd[SCR1_DBG_COMMAND_ACCESSREG_RESERVEDA]});
abs_cmd_memsize = abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_HI:
SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_LO];
abs_cmd_memwr = abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_WRITE];
abs_cmd_memvalid = ~(|{abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMVIRTUAL],
abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_AAMPOSTINC],
abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI:
SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI],
abs_cmd[SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI:
SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI]});
end
assign abs_reg_access_csr = (abs_cmd_regtype == ABS_CMD_HARTREG_CSR);
assign abs_reg_access_mprf = (abs_cmd_regtype == ABS_CMD_HARTREG_INTFPU)
& (abs_cmd_regfile == ABS_CMD_HARTREG_INT);
// Abstract command access request and valid flags
//------------------------------------------------------------------------------
assign abs_cmd_regsize_vd = (abs_cmd_regsize == 3'h2);
assign abs_cmd_memsize_vd = (abs_cmd_memsize < 3'h3);
assign abs_cmd_hartreg_vd = (abs_cmd_type == ABS_CMD_HARTREG) & abs_cmd_regvalid;
assign abs_cmd_hartmem_vd = (abs_cmd_type == ABS_CMD_HARTMEM) & abs_cmd_memvalid;
// Abstract command requests
assign abs_cmd_reg_access_req = abs_cmd_hartreg_vd & abs_cmd_regacs;
assign abs_cmd_csr_access_req = abs_cmd_reg_access_req & abs_reg_access_csr;
assign abs_cmd_mprf_access_req = abs_cmd_reg_access_req & abs_reg_access_mprf;
assign abs_cmd_execprogbuf_req = abs_cmd_hartreg_vd & abs_cmd_execprogbuf;
// Abstract command access valid flags
assign abs_cmd_csr_ro_access_vd = abs_cmd_csr_access_req & abs_cmd_regsize_vd & ~abs_cmd_regwr
& ~abs_cmd_execprogbuf & abs_cmd_csr_ro & hart_state_run;
assign abs_cmd_csr_rw_access_vd = abs_cmd_csr_access_req & abs_cmd_regsize_vd
& (abs_cmd_regwr | ~abs_cmd_csr_ro_access_vd);
assign abs_cmd_mprf_access_vd = abs_cmd_mprf_access_req & abs_cmd_regsize_vd;
assign abs_cmd_mem_access_vd = abs_cmd_hartmem_vd & abs_cmd_memsize_vd;
// Abstract command control registers
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_abs & abs_fsm_idle) begin
abs_cmd_postexec_ff <= abs_cmd_postexec_next;
abs_cmd_wr_ff <= abs_cmd_wr_next;
abs_cmd_regno_ff <= abs_cmd_regno;
abs_cmd_size_ff <= abs_cmd_size_next;
end
end
always_comb begin
abs_cmd_wr_next = 1'b0;
abs_cmd_postexec_next = 1'b0;
abs_cmd_size_next = abs_cmd_size_ff;
if ((command_wr_req | dmi_rpt_command) & hart_state_dhalt & abs_fsm_idle) begin
if (abs_cmd_csr_rw_access_vd) begin
abs_cmd_wr_next = abs_cmd_regwr;
abs_cmd_postexec_next = abs_cmd_execprogbuf;
end else if (abs_cmd_mprf_access_vd) begin
abs_cmd_wr_next = abs_cmd_regwr;
abs_cmd_size_next = abs_cmd_regsize[1:0];
abs_cmd_postexec_next = abs_cmd_execprogbuf;
end else if (abs_cmd_mem_access_vd) begin
abs_cmd_wr_next = abs_cmd_memwr;
abs_cmd_size_next = abs_cmd_memsize[1:0];
end
end
end
//------------------------------------------------------------------------------
// Abstract command FSM
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_dm) begin
if (~dmcontrol_dmactive_ff) begin
abs_fsm_ff <= ABS_STATE_IDLE;
end else begin
abs_fsm_ff <= abs_fsm_next;
end
end
end
always_comb begin
abs_fsm_next = abs_fsm_ff;
case (abs_fsm_ff)
ABS_STATE_IDLE: begin
if (command_wr_req | dmi_rpt_command) begin
case (1'b1)
abs_cmd_csr_ro_access_vd: abs_fsm_next = ABS_STATE_CSR_RO;
abs_cmd_csr_rw_access_vd: abs_fsm_next = hart_state_dhalt ? ABS_STATE_CSR_SAVE_XREG : ABS_STATE_ERR;
abs_cmd_mprf_access_vd : abs_fsm_next = hart_state_dhalt ? ABS_STATE_XREG_RW : ABS_STATE_ERR;
abs_cmd_execprogbuf_req : abs_fsm_next = ABS_STATE_EXEC;
abs_cmd_mem_access_vd : abs_fsm_next = hart_state_dhalt ? ABS_STATE_MEM_SAVE_XREG : ABS_STATE_ERR;
default : abs_fsm_next = ABS_STATE_ERR;
endcase
end
end
ABS_STATE_EXEC: begin
if (dhi_resp) begin
if (dhi_resp_exc | abs_err_acc_busy_ff) begin
abs_fsm_next = ABS_STATE_ERR;
end else begin
abs_fsm_next = ABS_STATE_IDLE;
end
end
end
ABS_STATE_XREG_RW: begin
if (dhi_resp) begin
case (1'b1)
abs_err_acc_busy_ff: abs_fsm_next = ABS_STATE_ERR;
abs_cmd_postexec_ff: abs_fsm_next = ABS_STATE_EXEC;
default : abs_fsm_next = ABS_STATE_IDLE;
endcase
end
end
ABS_STATE_CSR_RO : abs_fsm_next = abs_err_acc_busy_ff ? ABS_STATE_ERR : ABS_STATE_IDLE;
ABS_STATE_CSR_SAVE_XREG: abs_fsm_next = dhi_resp ? ABS_STATE_CSR_RW : ABS_STATE_CSR_SAVE_XREG;
ABS_STATE_CSR_RW : abs_fsm_next = dhi_resp ? ABS_STATE_CSR_RETURN_XREG : ABS_STATE_CSR_RW;
ABS_STATE_CSR_RETURN_XREG: begin
if (dhi_resp) begin
case (1'b1)
abs_err_exc_ff : abs_fsm_next = ABS_STATE_ERR;
abs_err_acc_busy_ff : abs_fsm_next = ABS_STATE_ERR;
abs_cmd_postexec_ff : abs_fsm_next = ABS_STATE_EXEC;
default : abs_fsm_next = ABS_STATE_IDLE;
endcase
end
end
ABS_STATE_MEM_SAVE_XREG : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_SAVE_XREG_FORADDR : ABS_STATE_MEM_SAVE_XREG;
ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RW : ABS_STATE_MEM_SAVE_XREG_FORADDR;
ABS_STATE_MEM_RW : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RETURN_XREG : ABS_STATE_MEM_RW;
ABS_STATE_MEM_RETURN_XREG : abs_fsm_next = dhi_resp ? ABS_STATE_MEM_RETURN_XREG_FORADDR : ABS_STATE_MEM_RETURN_XREG;
ABS_STATE_MEM_RETURN_XREG_FORADDR: begin
if (dhi_resp) begin
case (1'b1)
abs_err_exc_ff: abs_fsm_next = ABS_STATE_ERR;
abs_err_acc_busy_ff : abs_fsm_next = ABS_STATE_ERR;
abs_cmd_postexec_ff : abs_fsm_next = ABS_STATE_EXEC;
default : abs_fsm_next = ABS_STATE_IDLE;
endcase
end
end
ABS_STATE_ERR: begin
if (abstractcs_wr_req & (abstractcs_cmderr_next == 3'b0)) begin
abs_fsm_next = ABS_STATE_IDLE;
end
end
endcase
if (~abs_fsm_idle & hart_state_reset) begin
abs_fsm_next = ABS_STATE_ERR;
end
end
assign abs_fsm_idle = (abs_fsm_ff == ABS_STATE_IDLE);
assign abs_fsm_exec = (abs_fsm_ff == ABS_STATE_EXEC);
assign abs_fsm_csr_ro = (abs_fsm_ff == ABS_STATE_CSR_RO);
assign abs_fsm_err = (abs_fsm_ff == ABS_STATE_ERR);
assign abs_fsm_use_addr = (abs_fsm_ff == ABS_STATE_MEM_SAVE_XREG_FORADDR)
| (abs_fsm_ff == ABS_STATE_MEM_RETURN_XREG_FORADDR);
//------------------------------------------------------------------------------
// Abstract command status logic
//------------------------------------------------------------------------------
// Abstract command access busy error register
//------------------------------------------------------------------------------
assign abs_err_acc_busy_upd = clk_en_abs & (abs_fsm_idle | dmi_req_any);
always_ff @(posedge clk) begin
if (abs_err_acc_busy_upd) abs_err_acc_busy_ff <= abs_err_acc_busy_next;
end
assign abs_err_acc_busy_next = ~abs_fsm_idle & dmi_req_any;
// Abstract command access exception error register
//------------------------------------------------------------------------------
assign abs_err_exc_upd = clk_en_abs & (abs_fsm_idle | (dhi_resp & dhi_resp_exc));
always_ff @(posedge clk) begin
if (abs_err_exc_upd) abs_err_exc_ff <= abs_err_exc_next;
end
assign abs_err_exc_next = ~abs_fsm_idle & dhi_resp & dhi_resp_exc;
//------------------------------------------------------------------------------
// Abstract Instruction logic
//------------------------------------------------------------------------------
//
// Cosists of the following functional units:
// - Instruction execution request register
// - Instruction memory FUNCT3 field multiplexer
// - Instruction RS1 multiplexer
// - Instruction RD multiplexer
// - Abstract Instruction register
// Abstract instruction execution request register
//------------------------------------------------------------------------------
assign abs_exec_req_next = ~(abs_fsm_idle | abs_fsm_csr_ro | abs_fsm_err) & ~dhi_resp;
always_ff @(posedge clk) begin
if (clk_en_dm) begin
if (~dmcontrol_dmactive_ff) begin
abs_exec_req_ff <= 1'b0;
end else begin
abs_exec_req_ff <= abs_exec_req_next;
end
end
end
// Abstract instruction memory FUNCT3 field multiplexer
//------------------------------------------------------------------------------
always_comb begin
case (abs_cmd_size_ff)
2'b00 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SB : SCR1_FUNCT3_LBU;
2'b01 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SH : SCR1_FUNCT3_LHU;
2'b10 : abs_instr_mem_funct3 = abs_cmd_wr_ff ? SCR1_FUNCT3_SW : SCR1_FUNCT3_LW;
default: abs_instr_mem_funct3 = SCR1_FUNCT3_SB;
endcase
end
// Abstract instruction RS1 multiplexer
//------------------------------------------------------------------------------
always_comb begin
abs_instr_rs1 = 5'h0;
case (abs_fsm_ff)
ABS_STATE_XREG_RW : abs_instr_rs1 = abs_cmd_wr_ff ? 5'h0 : abs_cmd_regno_ff[4:0];
ABS_STATE_CSR_SAVE_XREG : abs_instr_rs1 = 5'h5;
ABS_STATE_MEM_SAVE_XREG : abs_instr_rs1 = 5'h5;
ABS_STATE_CSR_RETURN_XREG : abs_instr_rs1 = 5'h5;
ABS_STATE_MEM_RETURN_XREG : abs_instr_rs1 = 5'h5;
ABS_STATE_CSR_RW : abs_instr_rs1 = abs_cmd_wr_ff ? 5'h5 : 5'h0;
ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_instr_rs1 = 5'h6;
ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_instr_rs1 = 5'h6;
ABS_STATE_MEM_RW : abs_instr_rs1 = 5'h6;
default : begin end
endcase
end
assign abs_instr_rs2 = 5'h5;
// Abstract instruction RD multiplexer
//------------------------------------------------------------------------------
always_comb begin
abs_instr_rd = 5'h0;
case (abs_fsm_ff)
ABS_STATE_XREG_RW : abs_instr_rd = abs_cmd_wr_ff ? abs_cmd_regno_ff[4:0] : 5'h0;
ABS_STATE_CSR_SAVE_XREG : abs_instr_rd = abs_cmd_wr_ff ? 5'h5 : 5'h0;
ABS_STATE_MEM_SAVE_XREG : abs_instr_rd = abs_cmd_wr_ff ? 5'h5 : 5'h0;
ABS_STATE_CSR_RW : abs_instr_rd = abs_cmd_wr_ff ? 5'h0 : 5'h5;
ABS_STATE_MEM_RW : abs_instr_rd = abs_cmd_wr_ff ? 5'h0 : 5'h5;
ABS_STATE_CSR_RETURN_XREG : abs_instr_rd = 5'h5;
ABS_STATE_MEM_RETURN_XREG : abs_instr_rd = 5'h5;
ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_instr_rd = 5'h6;
ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_instr_rd = 5'h6;
default : begin end
endcase
end
// Abstract instruction register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_abs) begin
abs_exec_instr_ff <= abs_exec_instr_next;
end
end
always_comb begin
abs_exec_instr_next = abs_exec_instr_ff;
case (abs_fsm_ff)
ABS_STATE_XREG_RW,
ABS_STATE_CSR_SAVE_XREG,
ABS_STATE_CSR_RETURN_XREG,
ABS_STATE_MEM_SAVE_XREG,
ABS_STATE_MEM_SAVE_XREG_FORADDR,
ABS_STATE_MEM_RETURN_XREG,
ABS_STATE_MEM_RETURN_XREG_FORADDR: begin
abs_exec_instr_next = {SCR1_HDU_DBGCSR_ADDR_DSCRATCH0, abs_instr_rs1, SCR1_FUNCT3_CSRRW, abs_instr_rd, SCR1_OP_SYSTEM};
end
ABS_STATE_CSR_RW: begin
abs_exec_instr_next = abs_cmd_wr_ff
? {abs_cmd_regno_ff[11:0], abs_instr_rs1, SCR1_FUNCT3_CSRRW, abs_instr_rd, SCR1_OP_SYSTEM}
: {abs_cmd_regno_ff[11:0], abs_instr_rs1, SCR1_FUNCT3_CSRRS, abs_instr_rd, SCR1_OP_SYSTEM};
end
ABS_STATE_MEM_RW: begin
abs_exec_instr_next = abs_cmd_wr_ff
? {7'h0, abs_instr_rs2, abs_instr_rs1, abs_instr_mem_funct3, 5'h0, SCR1_OP_STORE}
: {12'h0, abs_instr_rs1, abs_instr_mem_funct3, abs_instr_rd, SCR1_OP_LOAD};
end
default: begin end
endcase
end
//------------------------------------------------------------------------------
// Abstract registers
//------------------------------------------------------------------------------
//
// Registers:
// - ABSTRACTCS register
// - COMMAND register
// - ABSTRACTAUTO register
// - PROGBUF0..5 registers
// - DATA0..1 registers
// ABSTRACTCS register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_dm) begin
if (~dmcontrol_dmactive_ff) begin
abstractcs_cmderr_ff <= ABS_ERR_NONE;
end else begin
abstractcs_cmderr_ff <= abstractcs_cmderr_next;
end
end
end
always_comb begin
abstractcs_cmderr_next = abstractcs_cmderr_ff;
case (abs_fsm_ff)
ABS_STATE_IDLE: begin
if (command_wr_req | dmi_rpt_command) begin
if (abs_cmd_hartreg_vd) begin
case (1'b1)
abs_cmd_reg_access_req : begin
case (1'b1)
abs_cmd_csr_rw_access_vd: abstractcs_cmderr_next = hart_state_dhalt
? abstractcs_cmderr_ff
: ABS_ERR_NOHALT;
abs_cmd_mprf_access_vd : abstractcs_cmderr_next = hart_state_dhalt
? abstractcs_cmderr_ff
: ABS_ERR_NOHALT;
abs_cmd_csr_ro_access_vd: abstractcs_cmderr_next = abstractcs_cmderr_ff;
default : abstractcs_cmderr_next = ABS_ERR_CMD;
endcase
end
abs_cmd_execprogbuf_req : abstractcs_cmderr_next = abstractcs_cmderr_ff;
default : abstractcs_cmderr_next = ABS_ERR_CMD;
endcase
end else if (abs_cmd_hartmem_vd) begin
abstractcs_cmderr_next = ~abs_cmd_memsize_vd ? ABS_ERR_CMD
: ~hart_state_dhalt ? ABS_ERR_NOHALT
: abstractcs_cmderr_ff;
end else begin
abstractcs_cmderr_next = ABS_ERR_CMD;
end
end
end
ABS_STATE_EXEC: begin
if (dhi_resp) begin
if (dhi_resp_exc) begin
abstractcs_cmderr_next = ABS_ERR_EXCEPTION;
end else if (abs_err_acc_busy_ff) begin
abstractcs_cmderr_next = ABS_ERR_BUSY;
end
end
end
ABS_STATE_XREG_RW,
ABS_STATE_CSR_RO: begin
if (abs_err_acc_busy_ff) begin
abstractcs_cmderr_next = ABS_ERR_BUSY;
end
end
ABS_STATE_CSR_RETURN_XREG,
ABS_STATE_MEM_RETURN_XREG_FORADDR: begin
if (dhi_resp) begin
case (1'b1)
abs_err_exc_ff : abstractcs_cmderr_next = ABS_ERR_EXCEPTION;
abs_err_acc_busy_ff: abstractcs_cmderr_next = ABS_ERR_BUSY;
default: abstractcs_cmderr_next = abstractcs_cmderr_ff;
endcase
end
end
ABS_STATE_ERR: begin
if (dmi_req_abstractcs & dmi2dm_wr_i) begin
abstractcs_cmderr_next = abstractcs_cmderr_ff // cp.7
& (~dmi2dm_wdata_i[SCR1_DBG_ABSTRACTCS_CMDERR_HI:
SCR1_DBG_ABSTRACTCS_CMDERR_LO]);
end
end
default: begin
end
endcase
if (~abs_fsm_idle & hart_state_reset) begin
abstractcs_cmderr_next = ABS_ERR_EXCEPTION;
end
end
assign abstractcs_busy = ~abs_fsm_idle & ~abs_fsm_err;
// Abstract COMMAND register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_dm) abs_command_ff <= abs_command_next;
end
assign abs_command_next = ~dmcontrol_dmactive_ff ? '0
: (command_wr_req & abs_fsm_idle) ? dmi2dm_wdata_i
: abs_command_ff;
// Abstract ABSTRACTAUTO register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_dm) abs_autoexec_ff <= abs_autoexec_next;
end
assign abs_autoexec_next = ~dmcontrol_dmactive_ff ? 1'b0
: (autoexec_wr_req & abs_fsm_idle) ? dmi2dm_wdata_i[0]
: abs_autoexec_ff;
// Program Buffer registers
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_abs & abs_fsm_idle) begin
if (progbuf0_wr_req) abs_progbuf0_ff <= dmi2dm_wdata_i;
if (progbuf1_wr_req) abs_progbuf1_ff <= dmi2dm_wdata_i;
if (progbuf2_wr_req) abs_progbuf2_ff <= dmi2dm_wdata_i;
if (progbuf3_wr_req) abs_progbuf3_ff <= dmi2dm_wdata_i;
if (progbuf4_wr_req) abs_progbuf4_ff <= dmi2dm_wdata_i;
if (progbuf5_wr_req) abs_progbuf5_ff <= dmi2dm_wdata_i;
end
end
// Data 0 register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_abs) begin
abs_data0_ff <= abs_data0_next;
end
end
assign data0_xreg_save = dreg_wr_req & ~abs_cmd_wr_ff;
always_comb begin
abs_data0_next = abs_data0_ff;
case (abs_fsm_ff)
ABS_STATE_IDLE : abs_data0_next = data0_wr_req ? dmi2dm_wdata_i : abs_data0_ff;
ABS_STATE_EXEC : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_CSR_SAVE_XREG : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_CSR_RETURN_XREG: abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_MEM_SAVE_XREG : abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_MEM_RETURN_XREG: abs_data0_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_XREG_RW : abs_data0_next = data0_xreg_save ? pipe2dm_dreg_wdata_i : abs_data0_ff;
ABS_STATE_CSR_RO: begin
case (abs_cmd_regno_ff[11:0])
SCR1_CSR_ADDR_MISA : abs_data0_next = SCR1_CSR_MISA;
SCR1_CSR_ADDR_MVENDORID: abs_data0_next = SCR1_CSR_MVENDORID;
SCR1_CSR_ADDR_MARCHID : abs_data0_next = SCR1_CSR_MARCHID;
SCR1_CSR_ADDR_MIMPID : abs_data0_next = SCR1_CSR_MIMPID;
SCR1_CSR_ADDR_MHARTID : abs_data0_next = soc2dm_fuse_mhartid_i;
default : abs_data0_next = pipe2dm_pc_sample_i;
endcase
end
default : begin end
endcase
end
// Data 1 register
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_abs) begin
abs_data1_ff <= abs_data1_next;
end
end
always_comb begin
abs_data1_next = abs_data1_ff;
case (abs_fsm_ff)
ABS_STATE_IDLE : abs_data1_next = data1_wr_req ? dmi2dm_wdata_i : abs_data1_ff;
ABS_STATE_MEM_SAVE_XREG_FORADDR : abs_data1_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data1_ff;
ABS_STATE_MEM_RETURN_XREG_FORADDR: abs_data1_next = dreg_wr_req ? pipe2dm_dreg_wdata_i : abs_data1_ff;
default : begin end
endcase
end
//------------------------------------------------------------------------------
// Debug Hart Interface : control
//------------------------------------------------------------------------------
assign cmd_resp_ok = pipe2dm_cmd_resp_i & ~pipe2dm_cmd_rcode_i;
assign hart_rst_unexp = ~dhi_fsm_idle & ~dhi_fsm_halt_req & hart_state_reset;
assign halt_req_vd = dmcontrol_haltreq_ff & ~hart_state_dhalt;
assign resume_req_vd = dmcontrol_resumereq_ff & ~dmstatus_allany_resumeack_ff
& hart_state_dhalt;
// DHI fsm
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
dhi_fsm_ff <= DHI_STATE_IDLE;
end else if (clk_en_dm) begin
dhi_fsm_ff <= dhi_fsm_next;
end
end
always_comb begin
dhi_fsm_next = dhi_fsm_ff;
if (~hart_rst_unexp & dmcontrol_dmactive_ff) begin
// Normal work
case (dhi_fsm_ff)
DHI_STATE_IDLE : dhi_fsm_next = dhi_req;
DHI_STATE_EXEC : dhi_fsm_next = cmd_resp_ok ? DHI_STATE_EXEC_RUN : DHI_STATE_EXEC;
DHI_STATE_EXEC_RUN : dhi_fsm_next = hart_state_drun ? DHI_STATE_EXEC_HALT : DHI_STATE_EXEC_RUN;
DHI_STATE_HALT_REQ : dhi_fsm_next = cmd_resp_ok ? DHI_STATE_EXEC_HALT : DHI_STATE_HALT_REQ;
DHI_STATE_EXEC_HALT : dhi_fsm_next = hart_state_dhalt ? DHI_STATE_IDLE : DHI_STATE_EXEC_HALT;
DHI_STATE_RESUME_REQ: dhi_fsm_next = cmd_resp_ok ? DHI_STATE_RESUME_RUN : DHI_STATE_RESUME_REQ;
DHI_STATE_RESUME_RUN: dhi_fsm_next = hart_state_run ? DHI_STATE_IDLE : DHI_STATE_RESUME_RUN;
default : dhi_fsm_next = dhi_fsm_ff;
endcase
end else begin
// In case of DM reset or core unexpected reset
dhi_fsm_next = DHI_STATE_IDLE;
end
end
assign dhi_fsm_idle = (dhi_fsm_ff == DHI_STATE_IDLE);
assign dhi_fsm_halt_req = (dhi_fsm_ff == DHI_STATE_HALT_REQ);
assign dhi_fsm_exec = (dhi_fsm_ff == DHI_STATE_EXEC);
assign dhi_fsm_exec_halt = (dhi_fsm_ff == DHI_STATE_EXEC_HALT);
assign dhi_fsm_resume_req = (dhi_fsm_ff == DHI_STATE_RESUME_REQ);
always_comb begin
case (1'b1)
abs_exec_req_ff: dhi_req = DHI_STATE_EXEC;
halt_req_vd : dhi_req = DHI_STATE_HALT_REQ;
resume_req_vd : dhi_req = DHI_STATE_RESUME_REQ;
default : dhi_req = DHI_STATE_IDLE;
endcase
end
assign dhi_resp = dhi_fsm_exec_halt & hart_state_dhalt;
assign dhi_resp_exc = pipe2dm_hart_event_i & pipe2dm_hart_status_i.except
& ~pipe2dm_hart_status_i.ebreak;
// HART command registers
//------------------------------------------------------------------------------
// HART command request register
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
hart_cmd_req_ff <= 1'b0;
end else if (clk_en_dm) begin
hart_cmd_req_ff <= hart_cmd_req_next;
end
end
assign hart_cmd_req_next = (dhi_fsm_exec | dhi_fsm_halt_req | dhi_fsm_resume_req)
& ~cmd_resp_ok & dmcontrol_dmactive_ff;
// HART command register
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
hart_cmd_ff <= SCR1_HDU_DBGSTATE_RUN;
end else if (clk_en_dm) begin
hart_cmd_ff <= hart_cmd_next;
end
end
always_comb begin
hart_cmd_next = SCR1_HDU_DBGSTATE_RUN;
if (dmcontrol_dmactive_ff) begin
case (dhi_fsm_ff)
DHI_STATE_EXEC : hart_cmd_next = SCR1_HDU_DBGSTATE_DRUN;
DHI_STATE_HALT_REQ : hart_cmd_next = SCR1_HDU_DBGSTATE_DHALTED;
DHI_STATE_RESUME_REQ: hart_cmd_next = SCR1_HDU_DBGSTATE_RUN;
default : hart_cmd_next = dm2pipe_cmd_o;
endcase
end
end
assign dm2pipe_cmd_req_o = hart_cmd_req_ff;
assign dm2pipe_cmd_o = hart_cmd_ff;
//------------------------------------------------------------------------------
// Debug Hart Interface : program buffer
//------------------------------------------------------------------------------
// Program Buffer execution EBREAK flag
//------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (clk_en_dm) hart_pbuf_ebreak_ff <= hart_pbuf_ebreak_next;
end
assign hart_pbuf_ebreak_next = abs_fsm_exec & (dm2pipe_pbuf_instr_o == ABS_EXEC_EBREAK);
// Program Buffer instruction multiplexer
//------------------------------------------------------------------------------
always_comb begin
dm2pipe_pbuf_instr_o = ABS_EXEC_EBREAK;
if (abs_fsm_exec & ~hart_pbuf_ebreak_ff) begin
case (pipe2dm_pbuf_addr_i)
3'h0: dm2pipe_pbuf_instr_o = abs_progbuf0_ff;
3'h1: dm2pipe_pbuf_instr_o = abs_progbuf1_ff;
3'h2: dm2pipe_pbuf_instr_o = abs_progbuf2_ff;
3'h3: dm2pipe_pbuf_instr_o = abs_progbuf3_ff;
3'h4: dm2pipe_pbuf_instr_o = abs_progbuf4_ff;
3'h5: dm2pipe_pbuf_instr_o = abs_progbuf5_ff;
default: ;
endcase
end else if (pipe2dm_pbuf_addr_i == 3'b0) begin
dm2pipe_pbuf_instr_o = abs_exec_instr_ff;
end
end
//------------------------------------------------------------------------------
// Debug Hart Interface : abstract command data
//------------------------------------------------------------------------------
assign dm2pipe_dreg_resp_o = 1'b1;
assign dm2pipe_dreg_fail_o = 1'b0;
assign dm2pipe_dreg_rdata_o = abs_fsm_use_addr ? abs_data1_ff : abs_data0_ff;
`ifdef SCR1_TRGT_SIMULATION
//------------------------------------------------------------------------------
// Assertions
//------------------------------------------------------------------------------
SVA_DM_X_CONTROL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({dmi2dm_req_i, pipe2dm_dreg_req_i, pipe2dm_cmd_resp_i,
pipe2dm_hart_event_i})
) else $error("DM error: control signals is X - %0b", {dmi2dm_req_i,
pipe2dm_dreg_req_i, pipe2dm_cmd_resp_i, pipe2dm_hart_event_i});
SVA_DM_X_DMI : assert property (
@(negedge clk) disable iff (~rst_n)
dmi2dm_req_i |-> !$isunknown({dmi2dm_wr_i, dmi2dm_addr_i, dmi2dm_wdata_i})
) else $error("DM error: data signals is X on dmi");
SVA_DM_X_HART_PBUF : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown (pipe2dm_pbuf_addr_i)
) else $error("DM error: data signals is X on hart_pbuf");
SVA_DM_X_HART_DREG : assert property (
@(negedge clk) disable iff (~rst_n)
pipe2dm_dreg_req_i |-> !$isunknown({pipe2dm_dreg_wr_i, pipe2dm_dreg_wdata_i})
) else $error("DM error: data signals is X on hart_dreg");
SVA_DM_X_HART_CMD : assert property (
@(negedge clk) disable iff (~rst_n)
pipe2dm_cmd_resp_i |-> !$isunknown({pipe2dm_cmd_rcode_i})
) else $error("DM error: data signals is X on dm2pipe_cmd_o");
SVA_DM_X_HART_EVENT : assert property (
@(negedge clk) disable iff (~rst_n)
pipe2dm_hart_event_i |-> !$isunknown(pipe2dm_hart_status_i)
) else $error("DM error: data signals is X on pipe2dm_hart_event_i");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_dm
`endif // SCR1_DBG_EN