Start hacking together a DM
This commit is contained in:
parent
5cc483898d
commit
0dce59daaf
|
@ -0,0 +1,489 @@
|
|||
/**********************************************************************
|
||||
* DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE *
|
||||
* Version 3, April 2008 *
|
||||
* *
|
||||
* Copyright (C) 2021 Luke Wren *
|
||||
* *
|
||||
* Everyone is permitted to copy and distribute verbatim or modified *
|
||||
* copies of this license document and accompanying software, and *
|
||||
* changing either is allowed. *
|
||||
* *
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION *
|
||||
* *
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO. *
|
||||
* 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. *
|
||||
* *
|
||||
*********************************************************************/
|
||||
|
||||
// RISC-V Debug Module for Hazard3
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module hazard3_dm #(
|
||||
// Where there are multiple harts per DM, the least-indexed hart is the
|
||||
// least-significant on each concatenated hart access bus.
|
||||
parameter N_HARTS = 1,
|
||||
// Where there are multiple DMs, the address of each DM should be a
|
||||
// multiple of 'h100, so that the lower 8 bits decode correctly.
|
||||
parameter NEXT_DM_ADDR = 32'h0000_0000,
|
||||
|
||||
parameter XLEN = 32, // Do not modify
|
||||
parameter W_HARTSEL = N_HARTS > 1 ? $clog2(N_HARTS) : 1 // Do not modify
|
||||
) (
|
||||
// DM is assumed to be in same clock domain as core; clock crossing
|
||||
// (if any) is inside DTM, or between DTM and DM.
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
|
||||
// APB access from Debug Transport Module
|
||||
input wire dmi_psel,
|
||||
input wire dmi_penable,
|
||||
input wire dmi_pwrite,
|
||||
input wire [7:0] dmi_paddr,
|
||||
input wire [31:0] dmi_pwdata,
|
||||
output reg [31:0] dmi_prdata,
|
||||
output wire dmi_pready,
|
||||
output wire dmi_pslverr,
|
||||
|
||||
// Reset request/acknowledge. "req" is a pulse >= 1 cycle wide. "done" is
|
||||
// level-sensitive, goes high once component is out of reset.
|
||||
//
|
||||
// The "sys" reset (ndmreset) is conventionally everything apart from DM +
|
||||
// DTM, but, as per section 3.2 in 0.13.2 debug spec: "Exactly what is
|
||||
// affected by this reset is implementation dependent, as long as it is
|
||||
// possible to debug programs from the first instruction executed." So
|
||||
// this could simply be an all-hart reset.
|
||||
output wire sys_reset_req,
|
||||
input wire sys_reset_done,
|
||||
output wire [N_HARTS-1:0] hart_reset_req,
|
||||
input wire [N_HARTS-1:0] hart_reset_done,
|
||||
|
||||
// Hart run/halt control
|
||||
output wire [N_HARTS-1:0] hart_req_halt,
|
||||
output wire [N_HARTS-1:0] hart_req_halt_on_reset,
|
||||
output wire [N_HARTS-1:0] hart_req_resume,
|
||||
input wire [N_HARTS-1:0] hart_halted,
|
||||
input wire [N_HARTS-1:0] hart_running,
|
||||
|
||||
// Hart access to data0 CSR (assumed to be core-internal but per-hart)
|
||||
input wire [N_HARTS*XLEN-1:0] hart_data0_rdata,
|
||||
output wire [N_HARTS*XLEN-1:0] hart_data0_wdata,
|
||||
output wire [N_HARTS-1:0] hart_data0_wen,
|
||||
|
||||
// Hart instruction injection
|
||||
output wire [N_HARTS*XLEN-1:0] hart_instr_data,
|
||||
output wire [N_HARTS-1:0] hart_instr_data_vld,
|
||||
input wire [N_HARTS-1:0] hart_instr_data_rdy,
|
||||
input wire [N_HARTS-1:0] hart_instr_caught_exception,
|
||||
input wire [N_HARTS-1:0] hart_instr_caught_ebreak
|
||||
);
|
||||
|
||||
wire dmi_write = dmi_psel && dmi_penable && dmi_pready && dmi_pwrite;
|
||||
wire dmi_read = dmi_psel && dmi_penable && dmi_pready && !dmi_pwrite;
|
||||
assign dmi_pready = 1'b1;
|
||||
assign dmi_pslverr = 1'b0;
|
||||
|
||||
// Program buffer is fixed at 2 words plus impebreak. The main thing we care
|
||||
// about is support for efficient memory block transfers using abstractauto;
|
||||
// in this case 2 words + impebreak is sufficient for RV32I, and 1 word +
|
||||
// impebreak is sufficient for RV32IC.
|
||||
localparam PROGBUF_SIZE = 2;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Address constants
|
||||
|
||||
localparam ADDR_DATA0 = 8'h04;
|
||||
// Other data registers not present.
|
||||
localparam ADDR_DMCONTROL = 8'h10;
|
||||
localparam ADDR_DMSTATUS = 8'h11;
|
||||
localparam ADDR_HARTINFO = 8'h12;
|
||||
// No halt summary registers (assume no more than 32 harts)
|
||||
// No array mask select registers
|
||||
localparam ADDR_ABSTRACTCS = 8'h16;
|
||||
localparam ADDR_COMMAND = 8'h17;
|
||||
localparam ADDR_ABSTRACTAUTO = 8'h18;
|
||||
localparam ADDR_CONFSTRPTR0 = 8'h19;
|
||||
localparam ADDR_CONFSTRPTR1 = 8'h1a;
|
||||
localparam ADDR_CONFSTRPTR2 = 8'h1b;
|
||||
localparam ADDR_CONFSTRPTR3 = 8'h1c;
|
||||
localparam ADDR_NEXTDM = 8'h1d;
|
||||
localparam ADDR_PROGBUF0 = 8'h20;
|
||||
localparam ADDR_PROGBUF1 = 8'h21;
|
||||
// No authentication, no system bus access
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Hart selection
|
||||
|
||||
reg dmactive;
|
||||
|
||||
// Some fiddliness to make sure we get a single-wide zero-valued signal when
|
||||
// N_HARTS == 1 (so we can use this for indexing of per-hart signals)
|
||||
reg [W_HARTSEL-1:0] hartsel;
|
||||
wire [W_HARTSEL-1:0] hartsel_next;
|
||||
|
||||
generate
|
||||
if (N_HARTS > 1) begin: has_hartsel
|
||||
// only the lower 10 bits of hartsel are supported
|
||||
assign hartsel_next = dmi_write && dmi_paddr == ADDR_DMCONTROL ?
|
||||
dmi_pwdata[16 +: W_HARTSEL] : hartsel;
|
||||
end else begin: has_no_hartsel
|
||||
assign hartsel_next = 1'b0;
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
hartsel <= {W_HARTSEL{1'b0}};
|
||||
end else if (!dmactive) begin
|
||||
hartsel <= {W_HARTSEL{1'b0}};
|
||||
end else begin
|
||||
hartsel <= hartsel_next;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Run/halt/reset control
|
||||
|
||||
// Normal read/write fields for dmcontrol (note some of these are per-hart
|
||||
// fields that get rotated into dmcontrol based on the current/next hartsel).
|
||||
reg [N_HARTS-1:0] dmcontrol_haltreq;
|
||||
reg [N_HARTS-1:0] dmcontrol_hartreset;
|
||||
reg [N_HARTS-1:0] dmcontrol_resethaltreq;
|
||||
reg dmcontrol_ndmreset;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dmactive <= 1'b0;
|
||||
dmcontrol_ndmreset <= 1'b0;
|
||||
dmcontrol_haltreq <= {N_HARTS{1'b0}};
|
||||
dmcontrol_hartreset <= {N_HARTS{1'b0}};
|
||||
dmcontrol_resethaltreq <= {N_HARTS{1'b0}};
|
||||
end else if (!dmactive) begin
|
||||
// Only dmactive is writable when !dmactive
|
||||
if (dmi_write && dmi_paddr == ADDR_DMCONTROL)
|
||||
dmactive <= dmi_pwdata[0];
|
||||
dmcontrol_ndmreset <= 1'b0;
|
||||
dmcontrol_haltreq <= {N_HARTS{1'b0}};
|
||||
dmcontrol_hartreset <= {N_HARTS{1'b0}};
|
||||
dmcontrol_resethaltreq <= {N_HARTS{1'b0}};
|
||||
end else if dmi_write && dmi_paddr == ADDR_DMCONTROL) begin
|
||||
dmactive <= dmi_pwdata[0];
|
||||
dmcontrol_ndmreset <= dmi_pwdata[1];
|
||||
dmcontrol_haltreq[hartsel_next] <= dmi_pwdata[31];
|
||||
dmcontrol_hartreset[hartsel_next] <= dmi_pwdata[29];
|
||||
// set/clear fields on this one for some reason
|
||||
dmcontrol_resethaltreq[hartsel_next] <= dmcontrol_resethaltreq[hartsel_next]
|
||||
&& !dmi_pwdata[2] || dmi_pwdata[3];
|
||||
end
|
||||
end
|
||||
|
||||
assign sys_reset_req = dmcontrol_ndmreset;
|
||||
assign hart_reset_req = dmcontrol_hartreset;
|
||||
assign hart_req_halt = dmcontrol_haltreq;
|
||||
assign hart_req_halt_on_reset = dmcontrol_resethaltreq;
|
||||
|
||||
reg [N_HARTS-1:0] hart_reset_done_prev;
|
||||
reg [N_HARTS-1:0] dmstatus_havereset;
|
||||
wire [N_HARTS-1:0] hart_available = hart_reset_done & {N_HARTS{sys_reset_done}};
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
hart_reset_done_prev <= {N_HARTS{1'b0}};
|
||||
end else begin
|
||||
hart_reset_done_prev <= hart_reset_done;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dmstatus_havereset <= {N_HARTS{1'b0}};
|
||||
end else if (!dmactive) begin
|
||||
dmstatus_havereset <= {N_HARTS{1'b0}};
|
||||
end else begin
|
||||
dmstatus_havereset <= dmstatus_havereset | (hart_reset_done & ~hart_reset_done_prev);
|
||||
// dmcontrol.ackhavereset:
|
||||
if (dmi_write && dmi_paddr == ADDR_DMCONTROL && dmi_pwdata[28])
|
||||
dmstatus_havereset[hartsel_next] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
reg [N_HARTS-1:0] dmstatus_resumeack;
|
||||
reg [N_HARTS-1:0] dmcontrol_resumereq_sticky;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dmstatus_resumeack <= {N_HARTS{1'b0}};
|
||||
dmcontrol_resumereq_sticky <= {N_HARTS{1'b0}};
|
||||
end else if (!dmactive) begin
|
||||
dmstatus_resumeack <= {N_HARTS{1'b0}};
|
||||
dmcontrol_resumereq_sticky <= {N_HARTS{1'b0}};
|
||||
end else begin
|
||||
dmstatus_resumeack <= dmstatus_resumeack | (dmcontrol_resumereq_sticky & hart_running);
|
||||
dmcontrol_resumereq_sticky <= dmcontrol_resumereq_sticky & ~hart_running;
|
||||
// dmcontrol.resumereq:
|
||||
if (dmi_write && dmi_paddr == ADDR_DMCONTROL && dmi_pwdata[30]) begin
|
||||
dmcontrol_resumereq_sticky[hartsel_next] <= 1'b1;
|
||||
dmstatus_resumeack[hartsel_next] <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign hart_req_resume = ~dmstatus_resumeack;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Abstract command data registers
|
||||
|
||||
wire abstractcs_busy;
|
||||
|
||||
assign hart_data0_wdata = {N_HARTS{dmi_pwdata}};
|
||||
assign hart_data0_wen = {{N_HARTS-1{1'b0}}, dmi_write && dmi_paddr == ADDR_DATA0 && !abstractcs_busy} << hartsel;
|
||||
|
||||
reg [XLEN-1:0] progbuf0;
|
||||
reg [XLEN-1:0] progbuf1;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
progbuf0 <= {XLEN{1'b0}};
|
||||
progbuf1 <= {XLEN{1'b0}};
|
||||
end else if (!dmactive) begin
|
||||
progbuf0 <= {XLEN{1'b0}};
|
||||
progbuf1 <= {XLEN{1'b0}};
|
||||
end else if (dmi_write && !abstractcs_busy) begin
|
||||
if (dmi_paddr == ADDR_PROGBUF0)
|
||||
progbuf0 <= dmi_pwdata;
|
||||
if (dmi_paddr == ADDR_PROGBUF1)
|
||||
progbuf1 <= dmi_pwdata;
|
||||
end
|
||||
end
|
||||
|
||||
// We only support abstractauto on data0 update (use case is bulk memory read/write)
|
||||
reg abstractauto_autoexecdata;
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
abstractauto_autoexecdata <= 1'b0;
|
||||
end else if (!dmactive) begin
|
||||
abstractauto_autoexecdata <= 1'b0;
|
||||
end else if (dmi_write && dmi_paddr == ADDR_ABSTRACTAUTO) begin
|
||||
abstractauto_autoexecdata <= pwdata[1];
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Abstract command state machine
|
||||
|
||||
localparam W_STATE = 4;
|
||||
localparam S_IDLE = 4'd0;
|
||||
|
||||
localparam S_ISSUE_REGREAD = 4'd1;
|
||||
localparam S_ISSUE_REGWRITE = 4'd2;
|
||||
localparam S_ISSUE_REGEBREAK = 4'd3;
|
||||
localparam S_WAIT_REGEBREAK = 4'd4;
|
||||
|
||||
localparam S_ISSUE_PROGBUF0 = 4'd5;
|
||||
localparam S_ISSUE_PROGBUF1 = 4'd6;
|
||||
localparam S_ISSUE_IMPEBREAK = 4'd7;
|
||||
localparam S_WAIT_IMPEBREAK = 4'd8;
|
||||
|
||||
localparam CMDERR_OK = 3'h0;
|
||||
localparam CMDERR_BUSY = 3'h1;
|
||||
localparam CMDERR_UNSUPPORTED = 3'h2;
|
||||
localparam CMDERR_EXCEPTION = 3'h3;
|
||||
localparam CMDERR_HALTRESUME = 3'h4;
|
||||
|
||||
reg [2:0] abstractcs_cmderr;
|
||||
reg [W_STATE-1:0] acmd_state;
|
||||
|
||||
assign abstracts_busy = acmd_state != S_IDLE;
|
||||
|
||||
wire start_abstract_cmd = abstractcs_cmderr == CMDERR_OK && !abstractcs_busy && (
|
||||
(dmi_write && dmi_paddr == ADDR_COMMAND) ||
|
||||
((dmi_write || dmi_read) && abstractauto_autoexecdata && dmi_paddr == ADDR_DATA0
|
||||
);
|
||||
|
||||
wire dmi_access_illegal_when_busy =
|
||||
(dmi_write && (
|
||||
dmi_paddr == ADDR_ABSTRACTCS || dmi_paddr == ADDR_COMMAND || dmi_paddr == ADDR_ABSTRACTAUTO ||
|
||||
dmi_paddr == ADDR_DATA0 || dmi_paddr == ADDR_PROGBUF0 || dmi_paddr == ADDR_PROGBUF0)) ||
|
||||
(dmi_read && (
|
||||
dmi_paddr == ADDR_DATA0 || dmi_paddr == ADDR_PROGBUF0 || dmi_paddr == ADDR_PROGBUF0));
|
||||
|
||||
wire acmd_unsupported =
|
||||
dmi_pwdata[31:24] != 8'h00 || // Only Access Register command supported
|
||||
dmi_pwdata[22:20] != 3'h2 || // Must be 32 bits in size
|
||||
dmi_pwdata[19] || // aarpostincrement not supported
|
||||
dmi_pwdata[15:12] != 4'h1 || // Only core register access supported
|
||||
dmi_pwdata[11:5] != 7'h0; // Only GPRs supported
|
||||
|
||||
wire acmd_postexec = dmi_pwdata[18];
|
||||
wire acmd_transfer = dmi_pwdata[17];
|
||||
wire acmd_write = dmi_pwdata[16];
|
||||
wire [4:0] acmd_regno = dmi_pwdata[4:0]
|
||||
|
||||
reg acmd_postexec_r;
|
||||
reg [4:0] acmd_regno_r;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
abstractcs_cmderr <= CMDERR_OK;
|
||||
abstractcs_state <= S_IDLE;
|
||||
acmd_postexec_r <= 1'b0;
|
||||
acmd_regno_r <= 5'h0;
|
||||
end else if (!dmactive) begin
|
||||
abstractcs_cmderr <= CMDERR_OK;
|
||||
abstractcs_state <= S_IDLE;
|
||||
end else begin
|
||||
if (abstractcs_cmderr == CMDERR_OK && abstracts_busy && dmi_access_illegal_when_busy)
|
||||
abstractcs_cmderr <= CMDERR_BUSY;
|
||||
if (state != S_IDLE && hart_instr_caught_exception)
|
||||
abstractcs_cmderr <= CMDERR_EXCEPTION;
|
||||
case (acmd_state)
|
||||
S_IDLE: begin
|
||||
if (start_abstract_cmd) begin
|
||||
if (!hart_halted[hartsel] || !hart_available[hartsel]) begin
|
||||
abstracts_cmderr <= CMDERR_HALTRESUME;
|
||||
end else if (acmd_unsupported)
|
||||
abstractcs_cmderr <= CMDERR_UNSUPPORTED;
|
||||
end else begin
|
||||
acmd_postexec_r <= acmd_postexec;
|
||||
acmd_regno_r <= acmd_regno;
|
||||
if (acmd_transfer && acmd_write)
|
||||
state <= S_ISSUE_REGWRITE;
|
||||
else if (acmd_transfer && !acmd_write)
|
||||
state <= S_ISSUE_REGREAD;
|
||||
else if (acmd_postexec)
|
||||
state <= S_ISSUE_PROGBUF0;
|
||||
else
|
||||
state <= S_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
S_ISSUE_REGREAD: begin
|
||||
if (hart_instr_data_rdy[hartsel])
|
||||
state <= S_ISSUE_REGEBREAK;
|
||||
end
|
||||
S_ISSUE_REGWRITE: begin
|
||||
if (hart_instr_data_rdy[hartsel])
|
||||
state <= S_ISSUE_REGEBREAK;
|
||||
end
|
||||
S_ISSUE_REGEBREAK: begin
|
||||
if (hart_instr_data_rdy[hartsel])
|
||||
state <= S_WAIT_REGEBREAK
|
||||
end
|
||||
S_WAIT_REGEBREAK: begin
|
||||
if (hart_instr_caught_ebreak) begin
|
||||
if (acmd_postexec_r)
|
||||
state <= S_ISSUE_PROGBUF0;
|
||||
else
|
||||
state <= S_IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
S_ISSUE_PROGBUF0: begin
|
||||
if (hart_instr_data_rdy[hartsel])
|
||||
state <= S_ISSUE_PROGBUF1;
|
||||
end
|
||||
S_ISSUE_PROGBUF1: begin
|
||||
if (hart_instr_caught_exception || hart_instr_caught_ebreak) begin
|
||||
state <= S_IDLE;
|
||||
end else if (hart_instr_data_rdy[hartsel]) begin
|
||||
state <= S_ISSUE_IMPEBREAK;
|
||||
end
|
||||
end
|
||||
S_ISSUE_IMPEBREAK: begin
|
||||
if (hart_instr_caught_exception || hart_instr_caught_ebreak) begin
|
||||
state <= S_IDLE;
|
||||
end else if (hart_instr_data_rdy[hartsel]) begin
|
||||
state <= S_WAIT_IMPEBREAK;
|
||||
end
|
||||
end
|
||||
S_WAIT_IMPEBREAK: begin
|
||||
if (hart_instr_caught_exception || hart_instr_caught_ebreak) begin
|
||||
state <= S_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign hart_instr_data_vld = {{N_HARTS{1'b0}},
|
||||
state == S_ISSUE_REGREAD || state == S_ISSUE_REGWRITE || state == S_ISSUE_REGEBREAK ||
|
||||
state == S_ISSUE_PROGBUF0 || state == S_ISSUE_PROGBUF1 || state == S_ISSUE_IMPEBREAK
|
||||
} << hartsel;
|
||||
|
||||
assign hart_instr_data = {N_HARTS{
|
||||
state == S_ISSUE_REGWRITE ? 32'h7b202073 | {20'd0, acmd_regno_r, 7'd0} : // csrr xx, data0
|
||||
state == S_ISSUE_REGREAD ? 32'h7b201073 | {12'd0, acmd_regno_r, 15'd0} : // csrw data0, xx
|
||||
state == S_ISSUE_PROGBUF0 ? progbuf0 :
|
||||
state == S_ISSUE_PROGBUF1 ? progbuf1 :
|
||||
32'h00100073 // ebreak
|
||||
}};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DMI read data mux
|
||||
always @ (*) begin
|
||||
case (dmi_paddr)
|
||||
ADDR_DATA0: dmi_prdata = hart_data0_rdata[hartsel * XLEN +: XLEN];
|
||||
ADDR_DMCONTROL: dmi_prdata = {
|
||||
dmcontrol_haltreq[hartsel],
|
||||
1'b0, // resumereq is a W1 field
|
||||
dmcontrol_hartreset[hartsel],
|
||||
1'b0, // ackhavereset is a W1 field
|
||||
1'b0, // reserved
|
||||
1'b0, // hasel hardwired 0 (no array mask)
|
||||
{{10-W_HARTSEL{1'b0}}, hartsel} // hartsello
|
||||
10'h0, // hartselhi
|
||||
2'h0, // reserved
|
||||
2'h0, // set/clrresethaltreq are W1 fields
|
||||
dmcontrol_ndmreset,
|
||||
dmactive
|
||||
};
|
||||
ADDR_DMSTATUS: dmi_prdata = {
|
||||
9'h0, // reserved
|
||||
1'b1, // impebreak = 1
|
||||
2'h0, // reserved
|
||||
{2{dmstatus_havereset[hartsel]}}, // allhavereset, anyhavereset
|
||||
{2{dmstatus_resumeack[hartsel]}}, // allresumeack, anyresumeack
|
||||
{2{hartsel >= N_HARTS}}, // allnonexistent, anynonexistent
|
||||
{2{!hart_available[hartsel}}, // allunavail, anyunavail
|
||||
{2{hart_running[hartsel]}}, // allrunning, anyrunning
|
||||
{2{hart_halted[hartsel]}}, // allhalted, anyhalted
|
||||
1'b1, // authenticated
|
||||
1'b0, // authbusy
|
||||
1'b1, // hasresethaltreq = 1 (we do support it)
|
||||
1'b0, // confstrptrvalid
|
||||
4'd2 // version = 2: RISC-V debug spec 0.13.2
|
||||
};
|
||||
ADDR_HARTINFO: dmi_prdata = {
|
||||
8'h0, // reserved
|
||||
4'h0, // nscratch = 0
|
||||
3'h0, // reserved
|
||||
1'b0, // dataccess = 0, data0 is backed by a per-hart CSR
|
||||
4'h1, // datasize = 1, a single data CSR (data0) is available
|
||||
12'h7b2 // dataaddr, same location where dscratch0 would be if implemented
|
||||
};
|
||||
ADDR_ABSTRACTCS: dmi_prdata = {
|
||||
3'h0, // reserved
|
||||
5'd2, // progbufsize = 2
|
||||
11'h0, // reserved
|
||||
abstractcs_busy,
|
||||
1'b0,
|
||||
abstractcs_cmderr,
|
||||
4'h0,
|
||||
4'd1 // datacount = 1
|
||||
};
|
||||
ADDR_ABSTRACTAUTO: dmi_prdata = {
|
||||
31'h0,
|
||||
abstractauto_autoexecdata // only data0 supported
|
||||
};
|
||||
ADDR_CONFSTRPTR0: dmi_prdata = 32'h4c296328;
|
||||
ADDR_CONFSTRPTR1: dmi_prdata = 32'h20656b75;
|
||||
ADDR_CONFSTRPTR2: dmi_prdata = 32'h6e657257;
|
||||
ADDR_CONFSTRPTR3: dmi_prdata = 32'h31322720;
|
||||
ADDR_NEXTDM: dmi_prdata = NEXT_DM_ADDR;
|
||||
ADDR_PROGBUF0: dmi_prdata = progbuf0;
|
||||
ADDR_PROGBUF1: dmi_prdata = progbuf1;
|
||||
default: dmi_prdata = {XLEN{1'b0}};
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue