blob: ba482d68993d799d95232393400cd0555e521c40 [file] [log] [blame]
From 2cbdb09aca95a2a8a30077826c5596e0f6843917 Mon Sep 17 00:00:00 2001
From: Michael Schaffner <msf@google.com>
Date: Thu, 17 Oct 2019 19:02:22 -0700
Subject: [PATCH 2/9] [lint/cleanup] Change indentation from 4 to 2 spaces per
tab
This helps in reducing the amount of overly long lines, which cause lint warnings.
---
src/dm_csrs.sv | 1102 +++++++++++++++++++++----------------------
src/dm_mem.sv | 890 +++++++++++++++++-----------------
src/dm_pkg.sv | 730 ++++++++++++++--------------
src/dm_sba.sv | 321 +++++++------
src/dm_top.sv | 418 ++++++++--------
src/dmi_cdc.sv | 72 +--
src/dmi_jtag.sv | 480 +++++++++----------
src/dmi_jtag_tap.sv | 613 ++++++++++++------------
8 files changed, 2309 insertions(+), 2317 deletions(-)
diff --git a/src/dm_csrs.sv b/src/dm_csrs.sv
index f23ea9d..808a95d 100644
--- a/src/dm_csrs.sv
+++ b/src/dm_csrs.sv
@@ -16,591 +16,587 @@
*/
module dm_csrs #(
- parameter int NrHarts = 1,
- parameter int BusWidth = 32,
- parameter logic [NrHarts-1:0] SelectableHarts = 1
+ parameter int NrHarts = 1,
+ parameter int BusWidth = 32,
+ parameter logic [NrHarts-1:0] SelectableHarts = 1
) (
- input logic clk_i, // Clock
- input logic rst_ni, // Asynchronous reset active low
- input logic testmode_i,
- input logic dmi_rst_ni, // Debug Module Intf reset active-low
- input logic dmi_req_valid_i,
- output logic dmi_req_ready_o,
- input dm::dmi_req_t dmi_req_i,
- // every request needs a response one cycle later
- output logic dmi_resp_valid_o,
- input logic dmi_resp_ready_i,
- output dm::dmi_resp_t dmi_resp_o,
- // global ctrl
- output logic ndmreset_o, // non-debug module reset active-high
- output logic dmactive_o, // 1 -> debug-module is active,
- // 0 -> synchronous re-set
- // hart status
- input dm::hartinfo_t [NrHarts-1:0] hartinfo_i, // static hartinfo
- input logic [NrHarts-1:0] halted_i, // hart is halted
- input logic [NrHarts-1:0] unavailable_i, // e.g.: powered down
- input logic [NrHarts-1:0] resumeack_i, // hart acknowledged resume request
- // hart control
- output logic [19:0] hartsel_o, // hartselect to ctrl module
- output logic [NrHarts-1:0] haltreq_o, // request to halt a hart
- output logic [NrHarts-1:0] resumereq_o, // request hart to resume
- output logic clear_resumeack_o,
-
- output logic cmd_valid_o, // debugger writing to cmd field
- output dm::command_t cmd_o, // abstract command
- input logic cmderror_valid_i, // an error occured
- input dm::cmderr_e cmderror_i, // this error occured
- input logic cmdbusy_i, // cmd is currently busy executing
-
- output logic [dm::ProgBufSize-1:0][31:0] progbuf_o, // to system bus
- output logic [dm::DataCount-1:0][31:0] data_o,
-
- input logic [dm::DataCount-1:0][31:0] data_i,
- input logic data_valid_i,
- // system bus access module (SBA)
- output logic [BusWidth-1:0] sbaddress_o,
- input logic [BusWidth-1:0] sbaddress_i,
- output logic sbaddress_write_valid_o,
- // control signals in
- output logic sbreadonaddr_o,
- output logic sbautoincrement_o,
- output logic [2:0] sbaccess_o,
- // data out
- output logic sbreadondata_o,
- output logic [BusWidth-1:0] sbdata_o,
- output logic sbdata_read_valid_o,
- output logic sbdata_write_valid_o,
- // read data in
- input logic [BusWidth-1:0] sbdata_i,
- input logic sbdata_valid_i,
- // control signals
- input logic sbbusy_i,
- input logic sberror_valid_i, // bus error occurred
- input logic [2:0] sberror_i // bus error occurred
+ input logic clk_i, // Clock
+ input logic rst_ni, // Asynchronous reset active low
+ input logic testmode_i,
+ input logic dmi_rst_ni, // Debug Module Intf reset active-low
+ input logic dmi_req_valid_i,
+ output logic dmi_req_ready_o,
+ input dm::dmi_req_t dmi_req_i,
+ // every request needs a response one cycle later
+ output logic dmi_resp_valid_o,
+ input logic dmi_resp_ready_i,
+ output dm::dmi_resp_t dmi_resp_o,
+ // global ctrl
+ output logic ndmreset_o, // non-debug module reset active-high
+ output logic dmactive_o, // 1 -> debug-module is active,
+ // 0 -> synchronous re-set
+ // hart status
+ input dm::hartinfo_t [NrHarts-1:0] hartinfo_i, // static hartinfo
+ input logic [NrHarts-1:0] halted_i, // hart is halted
+ input logic [NrHarts-1:0] unavailable_i, // e.g.: powered down
+ input logic [NrHarts-1:0] resumeack_i, // hart acknowledged resume request
+ // hart control
+ output logic [19:0] hartsel_o, // hartselect to ctrl module
+ output logic [NrHarts-1:0] haltreq_o, // request to halt a hart
+ output logic [NrHarts-1:0] resumereq_o, // request hart to resume
+ output logic clear_resumeack_o,
+
+ output logic cmd_valid_o, // debugger writing to cmd field
+ output dm::command_t cmd_o, // abstract command
+ input logic cmderror_valid_i, // an error occured
+ input dm::cmderr_e cmderror_i, // this error occured
+ input logic cmdbusy_i, // cmd is currently busy executing
+
+ output logic [dm::ProgBufSize-1:0][31:0] progbuf_o, // to system bus
+ output logic [dm::DataCount-1:0][31:0] data_o,
+
+ input logic [dm::DataCount-1:0][31:0] data_i,
+ input logic data_valid_i,
+ // system bus access module (SBA)
+ output logic [BusWidth-1:0] sbaddress_o,
+ input logic [BusWidth-1:0] sbaddress_i,
+ output logic sbaddress_write_valid_o,
+ // control signals in
+ output logic sbreadonaddr_o,
+ output logic sbautoincrement_o,
+ output logic [2:0] sbaccess_o,
+ // data out
+ output logic sbreadondata_o,
+ output logic [BusWidth-1:0] sbdata_o,
+ output logic sbdata_read_valid_o,
+ output logic sbdata_write_valid_o,
+ // read data in
+ input logic [BusWidth-1:0] sbdata_i,
+ input logic sbdata_valid_i,
+ // control signals
+ input logic sbbusy_i,
+ input logic sberror_valid_i, // bus error occurred
+ input logic [2:0] sberror_i // bus error occurred
);
- // the amount of bits we need to represent all harts
- localparam HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
- dm::dtm_op_e dtm_op;
- assign dtm_op = dm::dtm_op_e'(dmi_req_i.op);
-
- logic resp_queue_full;
- logic resp_queue_empty;
- logic resp_queue_push;
- logic resp_queue_pop;
- logic [31:0] resp_queue_data;
-
- localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'((dm::Data0 + {4'b0, dm::DataCount}));
- localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'((dm::ProgBuf0 + {4'b0, dm::ProgBufSize}));
-
- logic [31:0] haltsum0, haltsum1, haltsum2, haltsum3;
- logic [((NrHarts-1)/2**5 + 1) * 32 - 1 : 0] halted;
- logic [(NrHarts-1)/2**5:0][31:0] halted_reshaped0;
- logic [NrHarts/2**10:0][31:0] halted_reshaped1;
- logic [NrHarts/2**15:0][31:0] halted_reshaped2;
- logic [(NrHarts/2**10+1)*32-1:0] halted_flat1;
- logic [(NrHarts/2**15+1)*32-1:0] halted_flat2;
- logic [32-1:0] halted_flat3;
-
- // haltsum0
- always_comb begin
- halted = '0;
- halted[NrHarts-1:0] = halted_i;
- halted_reshaped0 = halted;
- haltsum0 = halted_reshaped0[hartsel_o[19:5]];
+ // the amount of bits we need to represent all harts
+ localparam HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
+ dm::dtm_op_e dtm_op;
+ assign dtm_op = dm::dtm_op_e'(dmi_req_i.op);
+
+ logic resp_queue_full;
+ logic resp_queue_empty;
+ logic resp_queue_push;
+ logic resp_queue_pop;
+ logic [31:0] resp_queue_data;
+
+ localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'((dm::Data0 + {4'b0, dm::DataCount}));
+ localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'((dm::ProgBuf0 + {4'b0, dm::ProgBufSize}));
+
+ logic [31:0] haltsum0, haltsum1, haltsum2, haltsum3;
+ logic [((NrHarts-1)/2**5 + 1) * 32 - 1 : 0] halted;
+ logic [(NrHarts-1)/2**5:0][31:0] halted_reshaped0;
+ logic [NrHarts/2**10:0][31:0] halted_reshaped1;
+ logic [NrHarts/2**15:0][31:0] halted_reshaped2;
+ logic [(NrHarts/2**10+1)*32-1:0] halted_flat1;
+ logic [(NrHarts/2**15+1)*32-1:0] halted_flat2;
+ logic [32-1:0] halted_flat3;
+
+ // haltsum0
+ always_comb begin
+ halted = '0;
+ halted[NrHarts-1:0] = halted_i;
+ halted_reshaped0 = halted;
+ haltsum0 = halted_reshaped0[hartsel_o[19:5]];
+ end
+
+ // haltsum1
+ always_comb begin : p_reduction1
+ halted_flat1 = '0;
+ for (int k=0; k<NrHarts/2**5+1; k++) begin
+ halted_flat1[k] = |halted_reshaped0[k];
end
-
- // haltsum1
- always_comb begin : p_reduction1
- halted_flat1 = '0;
- for (int k=0; k<NrHarts/2**5+1; k++) begin
- halted_flat1[k] = |halted_reshaped0[k];
- end
- halted_reshaped1 = halted_flat1;
- haltsum1 = halted_reshaped1[hartsel_o[19:10]];
+ halted_reshaped1 = halted_flat1;
+ haltsum1 = halted_reshaped1[hartsel_o[19:10]];
+ end
+ // haltsum2
+ always_comb begin : p_reduction2
+ halted_flat2 = '0;
+ for (int k=0; k<NrHarts/2**10+1; k++) begin
+ halted_flat2[k] = |halted_reshaped1[k];
end
- // haltsum2
- always_comb begin : p_reduction2
- halted_flat2 = '0;
- for (int k=0; k<NrHarts/2**10+1; k++) begin
- halted_flat2[k] = |halted_reshaped1[k];
- end
- halted_reshaped2 = halted_flat2;
- haltsum2 = halted_reshaped2[hartsel_o[19:15]];
+ halted_reshaped2 = halted_flat2;
+ haltsum2 = halted_reshaped2[hartsel_o[19:15]];
+ end
+ // haltsum3
+ always_comb begin : p_reduction3
+ halted_flat3 = '0;
+ for (int k=0; k<NrHarts/2**15+1; k++) begin
+ halted_flat3[k] = |halted_reshaped2[k];
end
- // haltsum3
- always_comb begin : p_reduction3
- halted_flat3 = '0;
- for (int k=0; k<NrHarts/2**15+1; k++) begin
- halted_flat3[k] = |halted_reshaped2[k];
+ haltsum3 = halted_flat3;
+ end
+
+
+ dm::dmstatus_t dmstatus;
+ dm::dmcontrol_t dmcontrol_d, dmcontrol_q;
+ dm::abstractcs_t abstractcs;
+ dm::cmderr_e cmderr_d, cmderr_q;
+ dm::command_t command_d, command_q;
+ logic cmd_valid_d, cmd_valid_q;
+ dm::abstractauto_t abstractauto_d, abstractauto_q;
+ dm::sbcs_t sbcs_d, sbcs_q;
+ logic [63:0] sbaddr_d, sbaddr_q;
+ logic [63:0] sbdata_d, sbdata_q;
+
+ logic [NrHarts-1:0] havereset_d, havereset_q;
+ // program buffer
+ logic [dm::ProgBufSize-1:0][31:0] progbuf_d, progbuf_q;
+ // because first data address starts at 0x04
+ logic [({3'b0, dm::DataCount} + dm::Data0 - 1):(dm::Data0)][31:0] data_d, data_q;
+
+ logic [HartSelLen-1:0] selected_hart;
+
+ // a successful response returns zero
+ assign dmi_resp_o.resp = dm::DTM_SUCCESS;
+ assign dmi_resp_valid_o = ~resp_queue_empty;
+ assign dmi_req_ready_o = ~resp_queue_full;
+ assign resp_queue_push = dmi_req_valid_i & dmi_req_ready_o;
+ // SBA
+ assign sbautoincrement_o = sbcs_q.sbautoincrement;
+ assign sbreadonaddr_o = sbcs_q.sbreadonaddr;
+ assign sbreadondata_o = sbcs_q.sbreadondata;
+ assign sbaccess_o = sbcs_q.sbaccess;
+ assign sbdata_o = sbdata_q[BusWidth-1:0];
+ assign sbaddress_o = sbaddr_q[BusWidth-1:0];
+
+ assign hartsel_o = {dmcontrol_q.hartselhi, dmcontrol_q.hartsello};
+
+ always_comb begin : csr_read_write
+ // --------------------
+ // Static Values (R/O)
+ // --------------------
+ // dmstatus
+ dmstatus = '0;
+ dmstatus.version = dm::DbgVersion013;
+ // no authentication implemented
+ dmstatus.authenticated = 1'b1;
+ // we do not support halt-on-reset sequence
+ dmstatus.hasresethaltreq = 1'b0;
+ // TODO(zarubaf) things need to change here if we implement the array mask
+ dmstatus.allhavereset = havereset_q[selected_hart];
+ dmstatus.anyhavereset = havereset_q[selected_hart];
+
+ dmstatus.allresumeack = resumeack_i[selected_hart];
+ dmstatus.anyresumeack = resumeack_i[selected_hart];
+
+ dmstatus.allunavail = unavailable_i[selected_hart];
+ dmstatus.anyunavail = unavailable_i[selected_hart];
+
+ // as soon as we are out of the legal Hart region tell the debugger
+ // that there are only non-existent harts
+ dmstatus.allnonexistent = (hartsel_o > (NrHarts - 1)) ? 1'b1 : 1'b0;
+ dmstatus.anynonexistent = (hartsel_o > (NrHarts - 1)) ? 1'b1 : 1'b0;
+
+ // We are not allowed to be in multiple states at once. This is a to
+ // make the running/halted and unavailable states exclusive.
+ dmstatus.allhalted = halted_i[selected_hart] & ~unavailable_i[selected_hart];
+ dmstatus.anyhalted = halted_i[selected_hart] & ~unavailable_i[selected_hart];
+
+ dmstatus.allrunning = ~halted_i[selected_hart] & ~unavailable_i[selected_hart];
+ dmstatus.anyrunning = ~halted_i[selected_hart] & ~unavailable_i[selected_hart];
+
+ // abstractcs
+ abstractcs = '0;
+ abstractcs.datacount = dm::DataCount;
+ abstractcs.progbufsize = dm::ProgBufSize;
+ abstractcs.busy = cmdbusy_i;
+ abstractcs.cmderr = cmderr_q;
+
+ // abstractautoexec
+ abstractauto_d = abstractauto_q;
+ abstractauto_d.zero0 = '0;
+
+ // default assignments
+ havereset_d = havereset_q;
+ dmcontrol_d = dmcontrol_q;
+ cmderr_d = cmderr_q;
+ command_d = command_q;
+ progbuf_d = progbuf_q;
+ data_d = data_q;
+ sbcs_d = sbcs_q;
+ sbaddr_d = sbaddress_i;
+ sbdata_d = sbdata_q;
+
+ resp_queue_data = 32'b0;
+ cmd_valid_d = 1'b0;
+ sbaddress_write_valid_o = 1'b0;
+ sbdata_read_valid_o = 1'b0;
+ sbdata_write_valid_o = 1'b0;
+ clear_resumeack_o = 1'b0;
+
+ // reads
+ if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) begin
+ unique case ({1'b0, dmi_req_i.addr}) inside
+ [(dm::Data0):DataEnd]: begin
+ if (dm::DataCount > 0) begin
+ resp_queue_data = data_q[dmi_req_i.addr[4:0]];
+ end
+ if (!cmdbusy_i) begin
+ // check whether we need to re-execute the command (just give a cmd_valid)
+ cmd_valid_d = abstractauto_q.autoexecdata[dmi_req_i.addr[3:0] -
+ int'(dm::Data0)];
+ end
+ end
+ dm::DMControl: resp_queue_data = dmcontrol_q;
+ dm::DMStatus: resp_queue_data = dmstatus;
+ dm::Hartinfo: resp_queue_data = hartinfo_i[selected_hart];
+ dm::AbstractCS: resp_queue_data = abstractcs;
+ dm::AbstractAuto: resp_queue_data = abstractauto_q;
+ // command is read-only
+ dm::Command: resp_queue_data = '0;
+ [(dm::ProgBuf0):ProgBufEnd]: begin
+ resp_queue_data = progbuf_q[dmi_req_i.addr[4:0]];
+ if (!cmdbusy_i) begin
+ // check whether we need to re-execute the command (just give a cmd_valid)
+ // TODO(zarubaf): check if offset is correct: without it this may assign Xes
+ cmd_valid_d = abstractauto_q.autoexecprogbuf[dmi_req_i.addr[3:0]+16];
+ end
+ end
+ dm::HaltSum0: resp_queue_data = haltsum0;
+ dm::HaltSum1: resp_queue_data = haltsum1;
+ dm::HaltSum2: resp_queue_data = haltsum2;
+ dm::HaltSum3: resp_queue_data = haltsum3;
+ dm::SBCS: begin
+ resp_queue_data = sbcs_q;
+ end
+ dm::SBAddress0: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ resp_queue_data = sbaddr_q[31:0];
+ end
+ end
+ dm::SBAddress1: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ resp_queue_data = sbaddr_q[63:32];
+ end
+ end
+ dm::SBData0: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ sbdata_read_valid_o = (sbcs_q.sberror == '0);
+ resp_queue_data = sbdata_q[31:0];
+ end
+ end
+ dm::SBData1: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ resp_queue_data = sbdata_q[63:32];
+ end
end
- haltsum3 = halted_flat3;
+ default:;
+ endcase
end
-
- dm::dmstatus_t dmstatus;
- dm::dmcontrol_t dmcontrol_d, dmcontrol_q;
- dm::abstractcs_t abstractcs;
- dm::cmderr_e cmderr_d, cmderr_q;
- dm::command_t command_d, command_q;
- logic cmd_valid_d, cmd_valid_q;
- dm::abstractauto_t abstractauto_d, abstractauto_q;
- dm::sbcs_t sbcs_d, sbcs_q;
- logic [63:0] sbaddr_d, sbaddr_q;
- logic [63:0] sbdata_d, sbdata_q;
-
- logic [NrHarts-1:0] havereset_d, havereset_q;
- // program buffer
- logic [dm::ProgBufSize-1:0][31:0] progbuf_d, progbuf_q;
- // because first data address starts at 0x04
- logic [({3'b0, dm::DataCount} + dm::Data0 - 1):(dm::Data0)][31:0] data_d, data_q;
-
- logic [HartSelLen-1:0] selected_hart;
-
- // a successful response returns zero
- assign dmi_resp_o.resp = dm::DTM_SUCCESS;
- assign dmi_resp_valid_o = ~resp_queue_empty;
- assign dmi_req_ready_o = ~resp_queue_full;
- assign resp_queue_push = dmi_req_valid_i & dmi_req_ready_o;
- // SBA
- assign sbautoincrement_o = sbcs_q.sbautoincrement;
- assign sbreadonaddr_o = sbcs_q.sbreadonaddr;
- assign sbreadondata_o = sbcs_q.sbreadondata;
- assign sbaccess_o = sbcs_q.sbaccess;
- assign sbdata_o = sbdata_q[BusWidth-1:0];
- assign sbaddress_o = sbaddr_q[BusWidth-1:0];
-
- assign hartsel_o = {dmcontrol_q.hartselhi, dmcontrol_q.hartsello};
-
- always_comb begin : csr_read_write
- // --------------------
- // Static Values (R/O)
- // --------------------
- // dmstatus
- dmstatus = '0;
- dmstatus.version = dm::DbgVersion013;
- // no authentication implemented
- dmstatus.authenticated = 1'b1;
- // we do not support halt-on-reset sequence
- dmstatus.hasresethaltreq = 1'b0;
- // TODO(zarubaf) things need to change here if we implement the array mask
- dmstatus.allhavereset = havereset_q[selected_hart];
- dmstatus.anyhavereset = havereset_q[selected_hart];
-
- dmstatus.allresumeack = resumeack_i[selected_hart];
- dmstatus.anyresumeack = resumeack_i[selected_hart];
-
- dmstatus.allunavail = unavailable_i[selected_hart];
- dmstatus.anyunavail = unavailable_i[selected_hart];
-
- // as soon as we are out of the legal Hart region tell the debugger
- // that there are only non-existent harts
- dmstatus.allnonexistent = (hartsel_o > (NrHarts - 1)) ? 1'b1 : 1'b0;
- dmstatus.anynonexistent = (hartsel_o > (NrHarts - 1)) ? 1'b1 : 1'b0;
-
- // We are not allowed to be in multiple states at once. This is a to
- // make the running/halted and unavailable states exclusive.
- dmstatus.allhalted = halted_i[selected_hart] & ~unavailable_i[selected_hart];
- dmstatus.anyhalted = halted_i[selected_hart] & ~unavailable_i[selected_hart];
-
- dmstatus.allrunning = ~halted_i[selected_hart] & ~unavailable_i[selected_hart];
- dmstatus.anyrunning = ~halted_i[selected_hart] & ~unavailable_i[selected_hart];
-
- // abstractcs
- abstractcs = '0;
- abstractcs.datacount = dm::DataCount;
- abstractcs.progbufsize = dm::ProgBufSize;
- abstractcs.busy = cmdbusy_i;
- abstractcs.cmderr = cmderr_q;
-
- // abstractautoexec
- abstractauto_d = abstractauto_q;
- abstractauto_d.zero0 = '0;
-
- // default assignments
- havereset_d = havereset_q;
- dmcontrol_d = dmcontrol_q;
- cmderr_d = cmderr_q;
- command_d = command_q;
- progbuf_d = progbuf_q;
- data_d = data_q;
- sbcs_d = sbcs_q;
- sbaddr_d = sbaddress_i;
- sbdata_d = sbdata_q;
-
- resp_queue_data = 32'b0;
- cmd_valid_d = 1'b0;
- sbaddress_write_valid_o = 1'b0;
- sbdata_read_valid_o = 1'b0;
- sbdata_write_valid_o = 1'b0;
- clear_resumeack_o = 1'b0;
-
- // reads
- if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) begin
- unique case ({1'b0, dmi_req_i.addr}) inside
- [(dm::Data0):DataEnd]: begin
- if (dm::DataCount > 0) begin
- resp_queue_data = data_q[dmi_req_i.addr[4:0]];
- end
- if (!cmdbusy_i) begin
- // check whether we need to re-execute the command (just give a cmd_valid)
- cmd_valid_d = abstractauto_q.autoexecdata[dmi_req_i.addr[3:0] -
- int'(dm::Data0)];
- end
- end
- dm::DMControl: resp_queue_data = dmcontrol_q;
- dm::DMStatus: resp_queue_data = dmstatus;
- dm::Hartinfo: resp_queue_data = hartinfo_i[selected_hart];
- dm::AbstractCS: resp_queue_data = abstractcs;
- dm::AbstractAuto: resp_queue_data = abstractauto_q;
- // command is read-only
- dm::Command: resp_queue_data = '0;
- [(dm::ProgBuf0):ProgBufEnd]: begin
- resp_queue_data = progbuf_q[dmi_req_i.addr[4:0]];
- if (!cmdbusy_i) begin
- // check whether we need to re-execute the command (just give a cmd_valid)
- // TODO(zarubaf): check if offset is correct: without it this may assign Xes
- cmd_valid_d = abstractauto_q.autoexecprogbuf[dmi_req_i.addr[3:0]+16];
- end
- end
- dm::HaltSum0: resp_queue_data = haltsum0;
- dm::HaltSum1: resp_queue_data = haltsum1;
- dm::HaltSum2: resp_queue_data = haltsum2;
- dm::HaltSum3: resp_queue_data = haltsum3;
- dm::SBCS: begin
- resp_queue_data = sbcs_q;
- end
- dm::SBAddress0: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- resp_queue_data = sbaddr_q[31:0];
- end
- end
- dm::SBAddress1: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- resp_queue_data = sbaddr_q[63:32];
- end
- end
- dm::SBData0: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- sbdata_read_valid_o = (sbcs_q.sberror == '0);
- resp_queue_data = sbdata_q[31:0];
- end
- end
- dm::SBData1: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- resp_queue_data = sbdata_q[63:32];
- end
- end
- default:;
- endcase
+ // write
+ if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_WRITE) begin
+ unique case (dm::dm_csr_e'({1'b0, dmi_req_i.addr})) inside
+ [(dm::Data0):DataEnd]: begin
+ // attempts to write them while busy is set does not change their value
+ if (!cmdbusy_i && dm::DataCount > 0) begin
+ data_d[dmi_req_i.addr[4:0]] = dmi_req_i.data;
+ // check whether we need to re-execute the command (just give a cmd_valid)
+ cmd_valid_d = abstractauto_q.autoexecdata[dmi_req_i.addr[3:0] -
+ int'(dm::Data0)];
+ end
end
-
- // write
- if (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_WRITE) begin
- unique case (dm::dm_csr_e'({1'b0, dmi_req_i.addr})) inside
- [(dm::Data0):DataEnd]: begin
- // attempts to write them while busy is set does not change their value
- if (!cmdbusy_i && dm::DataCount > 0) begin
- data_d[dmi_req_i.addr[4:0]] = dmi_req_i.data;
- // check whether we need to re-execute the command (just give a cmd_valid)
- cmd_valid_d = abstractauto_q.autoexecdata[dmi_req_i.addr[3:0] -
- int'(dm::Data0)];
- end
- end
- dm::DMControl: begin
- automatic dm::dmcontrol_t dmcontrol;
- dmcontrol = dm::dmcontrol_t'(dmi_req_i.data);
- // clear the havreset of the selected hart
- if (dmcontrol.ackhavereset) begin
- havereset_d[selected_hart] = 1'b0;
- end
- dmcontrol_d = dmi_req_i.data;
- end
- dm::DMStatus:; // write are ignored to R/O register
- dm::Hartinfo:; // hartinfo is R/O
- // only command error is write-able
- dm::AbstractCS: begin // W1C
- // Gets set if an abstract command fails. The bits in this
- // field remain set until they are cleared by writing 1 to
- // them. No abstract command is started until the value is
- // reset to 0.
- automatic dm::abstractcs_t a_abstractcs;
- a_abstractcs = dm::abstractcs_t'(dmi_req_i.data);
- // reads during abstract command execution are not allowed
- if (!cmdbusy_i) begin
- cmderr_d = dm::cmderr_e'(~a_abstractcs.cmderr & cmderr_q);
- end else if (cmderr_q == dm::CmdErrNone) begin
- cmderr_d = dm::CmdErrBusy;
- end
-
- end
- dm::Command: begin
- // writes are ignored if a command is already busy
- if (!cmdbusy_i) begin
- cmd_valid_d = 1'b1;
- command_d = dm::command_t'(dmi_req_i.data);
- // if there was an attempted to write during a busy execution
- // and the cmderror field is zero set the busy error
- end else if (cmderr_q == dm::CmdErrNone) begin
- cmderr_d = dm::CmdErrBusy;
- end
- end
- dm::AbstractAuto: begin
- // this field can only be written legally when there is no command executing
- if (!cmdbusy_i) begin
- abstractauto_d = 32'b0;
- abstractauto_d.autoexecdata = 12'(dmi_req_i.data[dm::DataCount-1:0]);
- abstractauto_d.autoexecprogbuf = 16'(dmi_req_i.data[dm::ProgBufSize-1+16:16]);
-
- end else if (cmderr_q == dm::CmdErrNone) begin
- cmderr_d = dm::CmdErrBusy;
- end
- end
- [(dm::ProgBuf0):ProgBufEnd]: begin
- // attempts to write them while busy is set does not change their value
- if (!cmdbusy_i) begin
- progbuf_d[dmi_req_i.addr[4:0]] = dmi_req_i.data;
- // check whether we need to re-execute the command (just give a cmd_valid)
- // this should probably throw an error if executed during another command
- // was busy
- // TODO(zarubaf): check if offset is correct - without it this may
- // assign Xes
- cmd_valid_d = abstractauto_q.autoexecprogbuf[dmi_req_i.addr[3:0]+16];
- end
- end
- dm::SBCS: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- automatic dm::sbcs_t sbcs;
- sbcs = dm::sbcs_t'(dmi_req_i.data);
- sbcs_d = sbcs;
- // R/W1C
- sbcs_d.sbbusyerror = sbcs_q.sbbusyerror & (~sbcs.sbbusyerror);
- sbcs_d.sberror = sbcs_q.sberror & (~sbcs.sberror);
- end
- end
- dm::SBAddress0: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- sbaddr_d[31:0] = dmi_req_i.data;
- sbaddress_write_valid_o = (sbcs_q.sberror == '0);
- end
- end
- dm::SBAddress1: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- sbaddr_d[63:32] = dmi_req_i.data;
- end
- end
- dm::SBData0: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- sbdata_d[31:0] = dmi_req_i.data;
- sbdata_write_valid_o = (sbcs_q.sberror == '0);
- end
- end
- dm::SBData1: begin
- // access while the SBA was busy
- if (sbbusy_i) begin
- sbcs_d.sbbusyerror = 1'b1;
- end else begin
- sbdata_d[63:32] = dmi_req_i.data;
- end
- end
- default:;
- endcase
+ dm::DMControl: begin
+ automatic dm::dmcontrol_t dmcontrol;
+ dmcontrol = dm::dmcontrol_t'(dmi_req_i.data);
+ // clear the havreset of the selected hart
+ if (dmcontrol.ackhavereset) begin
+ havereset_d[selected_hart] = 1'b0;
+ end
+ dmcontrol_d = dmi_req_i.data;
end
- // hart threw a command error and has precedence over bus writes
- if (cmderror_valid_i) begin
- cmderr_d = cmderror_i;
+ dm::DMStatus:; // write are ignored to R/O register
+ dm::Hartinfo:; // hartinfo is R/O
+ // only command error is write-able
+ dm::AbstractCS: begin // W1C
+ // Gets set if an abstract command fails. The bits in this
+ // field remain set until they are cleared by writing 1 to
+ // them. No abstract command is started until the value is
+ // reset to 0.
+ automatic dm::abstractcs_t a_abstractcs;
+ a_abstractcs = dm::abstractcs_t'(dmi_req_i.data);
+ // reads during abstract command execution are not allowed
+ if (!cmdbusy_i) begin
+ cmderr_d = dm::cmderr_e'(~a_abstractcs.cmderr & cmderr_q);
+ end else if (cmderr_q == dm::CmdErrNone) begin
+ cmderr_d = dm::CmdErrBusy;
+ end
end
-
- // update data registers
- if (data_valid_i)
- data_d = data_i;
-
- // set the havereset flag when we did a ndmreset
- if (ndmreset_o) begin
- havereset_d = '1;
+ dm::Command: begin
+ // writes are ignored if a command is already busy
+ if (!cmdbusy_i) begin
+ cmd_valid_d = 1'b1;
+ command_d = dm::command_t'(dmi_req_i.data);
+ // if there was an attempted to write during a busy execution
+ // and the cmderror field is zero set the busy error
+ end else if (cmderr_q == dm::CmdErrNone) begin
+ cmderr_d = dm::CmdErrBusy;
+ end
end
- // -------------
- // System Bus
- // -------------
- // set bus error
- if (sberror_valid_i) begin
- sbcs_d.sberror = sberror_i;
+ dm::AbstractAuto: begin
+ // this field can only be written legally when there is no command executing
+ if (!cmdbusy_i) begin
+ abstractauto_d = 32'b0;
+ abstractauto_d.autoexecdata = 12'(dmi_req_i.data[dm::DataCount-1:0]);
+ abstractauto_d.autoexecprogbuf = 16'(dmi_req_i.data[dm::ProgBufSize-1+16:16]);
+ end else if (cmderr_q == dm::CmdErrNone) begin
+ cmderr_d = dm::CmdErrBusy;
+ end
end
- // update read data
- if (sbdata_valid_i) begin
- sbdata_d = 64'(sbdata_i);
+ [(dm::ProgBuf0):ProgBufEnd]: begin
+ // attempts to write them while busy is set does not change their value
+ if (!cmdbusy_i) begin
+ progbuf_d[dmi_req_i.addr[4:0]] = dmi_req_i.data;
+ // check whether we need to re-execute the command (just give a cmd_valid)
+ // this should probably throw an error if executed during another command
+ // was busy
+ // TODO(zarubaf): check if offset is correct - without it this may
+ // assign Xes
+ cmd_valid_d = abstractauto_q.autoexecprogbuf[dmi_req_i.addr[3:0]+16];
+ end
end
-
- // dmcontrol
- // TODO(zarubaf) we currently do not implement the hartarry mask
- dmcontrol_d.hasel = 1'b0;
- // we do not support resetting an individual hart
- dmcontrol_d.hartreset = 1'b0;
- dmcontrol_d.setresethaltreq = 1'b0;
- dmcontrol_d.clrresethaltreq = 1'b0;
- dmcontrol_d.zero1 = '0;
- dmcontrol_d.zero0 = '0;
- // Non-writeable, clear only
- dmcontrol_d.ackhavereset = 1'b0;
- if (!dmcontrol_q.resumereq && dmcontrol_d.resumereq) begin
- clear_resumeack_o = 1'b1;
+ dm::SBCS: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ automatic dm::sbcs_t sbcs;
+ sbcs = dm::sbcs_t'(dmi_req_i.data);
+ sbcs_d = sbcs;
+ // R/W1C
+ sbcs_d.sbbusyerror = sbcs_q.sbbusyerror & (~sbcs.sbbusyerror);
+ sbcs_d.sberror = sbcs_q.sberror & (~sbcs.sberror);
+ end
+ end
+ dm::SBAddress0: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ sbaddr_d[31:0] = dmi_req_i.data;
+ sbaddress_write_valid_o = (sbcs_q.sberror == '0);
+ end
+ end
+ dm::SBAddress1: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ sbaddr_d[63:32] = dmi_req_i.data;
+ end
end
- if (dmcontrol_q.resumereq && resumeack_i) begin
- dmcontrol_d.resumereq = 1'b0;
+ dm::SBData0: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ sbdata_d[31:0] = dmi_req_i.data;
+ sbdata_write_valid_o = (sbcs_q.sberror == '0);
+ end
end
- // static values for dcsr
- sbcs_d.sbversion = 3'b1;
- sbcs_d.sbbusy = sbbusy_i;
- sbcs_d.sbasize = BusWidth;
- sbcs_d.sbaccess128 = 1'b0;
- sbcs_d.sbaccess64 = BusWidth == 64;
- sbcs_d.sbaccess32 = BusWidth == 32;
- sbcs_d.sbaccess16 = 1'b0;
- sbcs_d.sbaccess8 = 1'b0;
- sbcs_d.sbaccess = BusWidth == 64 ? 2'd3 : 2'd2;
+ dm::SBData1: begin
+ // access while the SBA was busy
+ if (sbbusy_i) begin
+ sbcs_d.sbbusyerror = 1'b1;
+ end else begin
+ sbdata_d[63:32] = dmi_req_i.data;
+ end
+ end
+ default:;
+ endcase
end
-
- // output multiplexer
- always_comb begin
- selected_hart = hartsel_o[HartSelLen-1:0];
- // default assignment
- haltreq_o = '0;
- resumereq_o = '0;
- haltreq_o[selected_hart] = dmcontrol_q.haltreq;
- resumereq_o[selected_hart] = dmcontrol_q.resumereq;
+ // hart threw a command error and has precedence over bus writes
+ if (cmderror_valid_i) begin
+ cmderr_d = cmderror_i;
end
- assign dmactive_o = dmcontrol_q.dmactive;
- assign cmd_o = command_q;
- assign cmd_valid_o = cmd_valid_q;
- assign progbuf_o = progbuf_q;
- assign data_o = data_q;
-
- assign resp_queue_pop = dmi_resp_ready_i & ~resp_queue_empty;
-
- assign ndmreset_o = dmcontrol_q.ndmreset;
-
- // response FIFO
- fifo_v2 #(
- .dtype ( logic [31:0] ),
- .DEPTH ( 2 )
- ) i_fifo (
- .clk_i ( clk_i ),
- .rst_ni ( dmi_rst_ni ), // reset only when system is re-set
- .flush_i ( 1'b0 ), // we do not need to flush this queue
- .testmode_i ( testmode_i ),
- .full_o ( resp_queue_full ),
- .empty_o ( resp_queue_empty ),
- .alm_full_o ( ),
- .alm_empty_o ( ),
- .data_i ( resp_queue_data ),
- .push_i ( resp_queue_push ),
- .data_o ( dmi_resp_o.data ),
- .pop_i ( resp_queue_pop )
- );
+ // update data registers
+ if (data_valid_i)
+ data_d = data_i;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // PoR
- if (!rst_ni) begin
- dmcontrol_q <= '0;
- // this is the only write-able bit during reset
- cmderr_q <= dm::CmdErrNone;
- command_q <= '0;
- abstractauto_q <= '0;
- progbuf_q <= '0;
- data_q <= '0;
- sbcs_q <= '0;
- sbaddr_q <= '0;
- sbdata_q <= '0;
- end else begin
- // synchronous re-set of debug module, active-low, except for dmactive
- if (!dmcontrol_q.dmactive) begin
- dmcontrol_q.haltreq <= '0;
- dmcontrol_q.resumereq <= '0;
- dmcontrol_q.hartreset <= '0;
- dmcontrol_q.zero1 <= '0;
- dmcontrol_q.hasel <= '0;
- dmcontrol_q.hartsello <= '0;
- dmcontrol_q.hartselhi <= '0;
- dmcontrol_q.zero0 <= '0;
- dmcontrol_q.setresethaltreq <= '0;
- dmcontrol_q.clrresethaltreq <= '0;
- dmcontrol_q.ndmreset <= '0;
- // this is the only write-able bit during reset
- dmcontrol_q.dmactive <= dmcontrol_d.dmactive;
- cmderr_q <= dm::CmdErrNone;
- command_q <= '0;
- cmd_valid_q <= '0;
- abstractauto_q <= '0;
- progbuf_q <= '0;
- data_q <= '0;
- sbcs_q <= '0;
- sbaddr_q <= '0;
- sbdata_q <= '0;
- end else begin
- dmcontrol_q <= dmcontrol_d;
- cmderr_q <= cmderr_d;
- command_q <= command_d;
- cmd_valid_q <= cmd_valid_d;
- abstractauto_q <= abstractauto_d;
- progbuf_q <= progbuf_d;
- data_q <= data_d;
- sbcs_q <= sbcs_d;
- sbaddr_q <= sbaddr_d;
- sbdata_q <= sbdata_d;
- end
- end
+ // set the havereset flag when we did a ndmreset
+ if (ndmreset_o) begin
+ havereset_d = '1;
+ end
+ // -------------
+ // System Bus
+ // -------------
+ // set bus error
+ if (sberror_valid_i) begin
+ sbcs_d.sberror = sberror_i;
+ end
+ // update read data
+ if (sbdata_valid_i) begin
+ sbdata_d = 64'(sbdata_i);
+ end
+
+ // dmcontrol
+ // TODO(zarubaf) we currently do not implement the hartarry mask
+ dmcontrol_d.hasel = 1'b0;
+ // we do not support resetting an individual hart
+ dmcontrol_d.hartreset = 1'b0;
+ dmcontrol_d.setresethaltreq = 1'b0;
+ dmcontrol_d.clrresethaltreq = 1'b0;
+ dmcontrol_d.zero1 = '0;
+ dmcontrol_d.zero0 = '0;
+ // Non-writeable, clear only
+ dmcontrol_d.ackhavereset = 1'b0;
+ if (!dmcontrol_q.resumereq && dmcontrol_d.resumereq) begin
+ clear_resumeack_o = 1'b1;
+ end
+ if (dmcontrol_q.resumereq && resumeack_i) begin
+ dmcontrol_d.resumereq = 1'b0;
end
+ // static values for dcsr
+ sbcs_d.sbversion = 3'b1;
+ sbcs_d.sbbusy = sbbusy_i;
+ sbcs_d.sbasize = BusWidth;
+ sbcs_d.sbaccess128 = 1'b0;
+ sbcs_d.sbaccess64 = BusWidth == 64;
+ sbcs_d.sbaccess32 = BusWidth == 32;
+ sbcs_d.sbaccess16 = 1'b0;
+ sbcs_d.sbaccess8 = 1'b0;
+ sbcs_d.sbaccess = BusWidth == 64 ? 2'd3 : 2'd2;
+ end
+
+ // output multiplexer
+ always_comb begin
+ selected_hart = hartsel_o[HartSelLen-1:0];
+ // default assignment
+ haltreq_o = '0;
+ resumereq_o = '0;
+ haltreq_o[selected_hart] = dmcontrol_q.haltreq;
+ resumereq_o[selected_hart] = dmcontrol_q.resumereq;
+ end
+
+ assign dmactive_o = dmcontrol_q.dmactive;
+ assign cmd_o = command_q;
+ assign cmd_valid_o = cmd_valid_q;
+ assign progbuf_o = progbuf_q;
+ assign data_o = data_q;
+
+ assign resp_queue_pop = dmi_resp_ready_i & ~resp_queue_empty;
+
+ assign ndmreset_o = dmcontrol_q.ndmreset;
+
+ // response FIFO
+ fifo_v2 #(
+ .dtype ( logic [31:0] ),
+ .DEPTH ( 2 )
+ ) i_fifo (
+ .clk_i ( clk_i ),
+ .rst_ni ( dmi_rst_ni ), // reset only when system is re-set
+ .flush_i ( 1'b0 ), // we do not need to flush this queue
+ .testmode_i ( testmode_i ),
+ .full_o ( resp_queue_full ),
+ .empty_o ( resp_queue_empty ),
+ .alm_full_o ( ),
+ .alm_empty_o ( ),
+ .data_i ( resp_queue_data ),
+ .push_i ( resp_queue_push ),
+ .data_o ( dmi_resp_o.data ),
+ .pop_i ( resp_queue_pop )
+ );
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ // PoR
+ if (!rst_ni) begin
+ dmcontrol_q <= '0;
+ // this is the only write-able bit during reset
+ cmderr_q <= dm::CmdErrNone;
+ command_q <= '0;
+ abstractauto_q <= '0;
+ progbuf_q <= '0;
+ data_q <= '0;
+ sbcs_q <= '0;
+ sbaddr_q <= '0;
+ sbdata_q <= '0;
+ end else begin
+ // synchronous re-set of debug module, active-low, except for dmactive
+ if (!dmcontrol_q.dmactive) begin
+ dmcontrol_q.haltreq <= '0;
+ dmcontrol_q.resumereq <= '0;
+ dmcontrol_q.hartreset <= '0;
+ dmcontrol_q.zero1 <= '0;
+ dmcontrol_q.hasel <= '0;
+ dmcontrol_q.hartsello <= '0;
+ dmcontrol_q.hartselhi <= '0;
+ dmcontrol_q.zero0 <= '0;
+ dmcontrol_q.setresethaltreq <= '0;
+ dmcontrol_q.clrresethaltreq <= '0;
+ dmcontrol_q.ndmreset <= '0;
+ // this is the only write-able bit during reset
+ dmcontrol_q.dmactive <= dmcontrol_d.dmactive;
+ cmderr_q <= dm::CmdErrNone;
+ command_q <= '0;
+ cmd_valid_q <= '0;
+ abstractauto_q <= '0;
+ progbuf_q <= '0;
+ data_q <= '0;
+ sbcs_q <= '0;
+ sbaddr_q <= '0;
+ sbdata_q <= '0;
+ end else begin
+ dmcontrol_q <= dmcontrol_d;
+ cmderr_q <= cmderr_d;
+ command_q <= command_d;
+ cmd_valid_q <= cmd_valid_d;
+ abstractauto_q <= abstractauto_d;
+ progbuf_q <= progbuf_d;
+ data_q <= data_d;
+ sbcs_q <= sbcs_d;
+ sbaddr_q <= sbaddr_d;
+ sbdata_q <= sbdata_d;
+ end
+ end
+ end
- for (genvar k = 0; k < NrHarts; k++) begin : gen_havereset
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- havereset_q[k] <= 1'b1;
- end else begin
- havereset_q[k] <= SelectableHarts[k] ? havereset_d[k] : 1'b0;
- end
- end
+ for (genvar k = 0; k < NrHarts; k++) begin : gen_havereset
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ havereset_q[k] <= 1'b1;
+ end else begin
+ havereset_q[k] <= SelectableHarts[k] ? havereset_d[k] : 1'b0;
+ end
end
+ end
///////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////
-
//pragma translate_off
`ifndef VERILATOR
- haltsum: assert property (
- @(posedge clk_i) disable iff (!rst_ni)
- (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) |->
- !({1'b0, dmi_req_i.addr} inside
- {dm::HaltSum0, dm::HaltSum1, dm::HaltSum2, dm::HaltSum3}))
- else $warning("Haltsums have not been properly tested yet.");
+ haltsum: assert property (
+ @(posedge clk_i) disable iff (!rst_ni)
+ (dmi_req_ready_o && dmi_req_valid_i && dtm_op == dm::DTM_READ) |->
+ !({1'b0, dmi_req_i.addr} inside
+ {dm::HaltSum0, dm::HaltSum1, dm::HaltSum2, dm::HaltSum3}))
+ else $warning("Haltsums have not been properly tested yet.");
`endif
//pragma translate_on
-
endmodule
diff --git a/src/dm_mem.sv b/src/dm_mem.sv
index c09126c..1ecc878 100644
--- a/src/dm_mem.sv
+++ b/src/dm_mem.sv
@@ -1,470 +1,466 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
- * Copyright and related rights are licensed under the Solderpad Hardware
- * License, Version 0.51 (the “License”); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
- * or agreed to in writing, software, hardware and materials distributed under
- * this 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.
- *
- * File: dm_mem.sv
- * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
- * Date: 11.7.2018
- *
- * Description: Memory module for execution-based debug clients
- *
- */
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File: dm_mem.sv
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+* Date: 11.7.2018
+*
+* Description: Memory module for execution-based debug clients
+*
+*/
module dm_mem #(
- parameter int NrHarts = -1,
- parameter int BusWidth = -1,
- parameter logic [NrHarts-1:0] SelectableHarts = -1
-)(
- input logic clk_i, // Clock
- input logic rst_ni, // debug module reset
-
- output logic [NrHarts-1:0] debug_req_o,
- input logic [19:0] hartsel_i,
- // from Ctrl and Status register
- input logic [NrHarts-1:0] haltreq_i,
- input logic [NrHarts-1:0] resumereq_i,
- input logic clear_resumeack_i,
-
- // state bits
- output logic [NrHarts-1:0] halted_o, // hart acknowledge halt
- output logic [NrHarts-1:0] resuming_o, // hart is resuming
-
- input logic [dm::ProgBufSize-1:0][31:0] progbuf_i, // program buffer to expose
-
- input logic [dm::DataCount-1:0][31:0] data_i, // data in
- output logic [dm::DataCount-1:0][31:0] data_o, // data out
- output logic data_valid_o, // data out is valid
- // abstract command interface
- input logic cmd_valid_i,
- input dm::command_t cmd_i,
- output logic cmderror_valid_o,
- output dm::cmderr_e cmderror_o,
- output logic cmdbusy_o,
- // data interface
-
- // SRAM interface
- input logic req_i,
- input logic we_i,
- input logic [BusWidth-1:0] addr_i,
- input logic [BusWidth-1:0] wdata_i,
- input logic [BusWidth/8-1:0] be_i,
- output logic [BusWidth-1:0] rdata_o
+ parameter int NrHarts = -1,
+ parameter int BusWidth = -1,
+ parameter logic [NrHarts-1:0] SelectableHarts = -1
+) (
+ input logic clk_i, // Clock
+ input logic rst_ni, // debug module reset
+
+ output logic [NrHarts-1:0] debug_req_o,
+ input logic [19:0] hartsel_i,
+ // from Ctrl and Status register
+ input logic [NrHarts-1:0] haltreq_i,
+ input logic [NrHarts-1:0] resumereq_i,
+ input logic clear_resumeack_i,
+
+ // state bits
+ output logic [NrHarts-1:0] halted_o, // hart acknowledge halt
+ output logic [NrHarts-1:0] resuming_o, // hart is resuming
+
+ input logic [dm::ProgBufSize-1:0][31:0] progbuf_i, // program buffer to expose
+
+ input logic [dm::DataCount-1:0][31:0] data_i, // data in
+ output logic [dm::DataCount-1:0][31:0] data_o, // data out
+ output logic data_valid_o, // data out is valid
+ // abstract command interface
+ input logic cmd_valid_i,
+ input dm::command_t cmd_i,
+ output logic cmderror_valid_o,
+ output dm::cmderr_e cmderror_o,
+ output logic cmdbusy_o,
+ // data interface
+
+ // SRAM interface
+ input logic req_i,
+ input logic we_i,
+ input logic [BusWidth-1:0] addr_i,
+ input logic [BusWidth-1:0] wdata_i,
+ input logic [BusWidth/8-1:0] be_i,
+ output logic [BusWidth-1:0] rdata_o
);
- localparam int HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
- localparam int MaxAar = (BusWidth == 64) ? 4 : 3;
- localparam DbgAddressBits = 12;
- localparam logic [DbgAddressBits-1:0] DataBase = (dm::DataAddr);
- localparam logic [DbgAddressBits-1:0] DataEnd = (dm::DataAddr + 4*dm::DataCount);
- localparam logic [DbgAddressBits-1:0] ProgBufBase = (dm::DataAddr - 4*dm::ProgBufSize);
- localparam logic [DbgAddressBits-1:0] ProgBufEnd = (dm::DataAddr - 1);
- localparam logic [DbgAddressBits-1:0] AbstractCmdBase = (ProgBufBase - 4*10);
- localparam logic [DbgAddressBits-1:0] AbstractCmdEnd = (ProgBufBase - 1);
- localparam logic [DbgAddressBits-1:0] WhereTo = 'h300;
- localparam logic [DbgAddressBits-1:0] FlagsBase = 'h400;
- localparam logic [DbgAddressBits-1:0] FlagsEnd = 'h7FF;
-
-
- localparam logic [DbgAddressBits-1:0] Halted = 'h100;
- localparam logic [DbgAddressBits-1:0] Going = 'h104;
- localparam logic [DbgAddressBits-1:0] Resuming = 'h108;
- localparam logic [DbgAddressBits-1:0] Exception = 'h10C;
-
- logic [dm::ProgBufSize/2-1:0][63:0] progbuf;
- logic [4:0][63:0] abstract_cmd;
- logic [NrHarts-1:0] halted_d, halted_q;
- logic [NrHarts-1:0] resuming_d, resuming_q;
- logic resume, go, going;
- logic [NrHarts-1:0] halted;
-
- logic [HartSelLen-1:0] hart_sel;
- logic exception;
- logic unsupported_command;
-
- logic [63:0] rom_rdata;
- logic [63:0] rdata_d, rdata_q;
- logic word_enable32_q;
-
- // distinguish whether we need to forward data from the ROM or the FSM
- // latch the address for this
- logic fwd_rom_d, fwd_rom_q;
- dm::ac_ar_cmd_t ac_ar;
-
- // Abstract Command Access Register
- assign ac_ar = dm::ac_ar_cmd_t'(cmd_i.control);
- assign hart_sel = wdata_i[HartSelLen-1:0];
- assign debug_req_o = haltreq_i;
- assign halted_o = halted_q;
- assign resuming_o = resuming_q;
-
- // reshape progbuf
- assign progbuf = progbuf_i;
-
- typedef enum logic [1:0] { Idle, Go, Resume, CmdExecuting } state_e;
- state_e state_d, state_q;
-
- // hart ctrl queue
- always_comb begin
- cmderror_valid_o = 1'b0;
- cmderror_o = dm::CmdErrNone;
- state_d = state_q;
- go = 1'b0;
- resume = 1'b0;
- cmdbusy_o = 1'b1;
-
- case (state_q)
- Idle: begin
- cmdbusy_o = 1'b0;
- if (cmd_valid_i && halted_q[hartsel_i]) begin
- // give the go signal
- state_d = Go;
- end else if (cmd_valid_i) begin
- // hart must be halted for all requests
- cmderror_valid_o = 1'b1;
- cmderror_o = dm::CmdErrorHaltResume;
- end
- // CSRs want to resume, the request is ignored when the hart is
- // requested to halt or it didn't clear the resuming_q bit before
- if (resumereq_i[hartsel_i] && !resuming_q[hartsel_i] &&
- !haltreq_i[hartsel_i] && halted_q[hartsel_i]) begin
- state_d = Resume;
- end
- end
-
- Go: begin
- // we are already busy here since we scheduled the execution of a program
- cmdbusy_o = 1'b1;
- go = 1'b1;
- // the thread is now executing the command, track its state
- if (going)
- state_d = CmdExecuting;
- end
-
- Resume: begin
- cmdbusy_o = 1'b1;
- resume = 1'b1;
- if (resuming_o[hartsel_i])
- state_d = Idle;
- end
-
- CmdExecuting: begin
- cmdbusy_o = 1'b1;
- go = 1'b0;
- // wait until the hart has halted again
- if (halted[hartsel_i]) begin
- state_d = Idle;
- end
- end
- endcase
-
- // only signal once that cmd is unsupported so that we can clear cmderr
- // in subsequent writes to abstractcs
- if (unsupported_command && cmd_valid_i) begin
- cmderror_valid_o = 1'b1;
- cmderror_o = dm::CmdErrNotSupported;
+ localparam int HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
+ localparam int MaxAar = (BusWidth == 64) ? 4 : 3;
+ localparam DbgAddressBits = 12;
+ localparam logic [DbgAddressBits-1:0] DataBase = (dm::DataAddr);
+ localparam logic [DbgAddressBits-1:0] DataEnd = (dm::DataAddr + 4*dm::DataCount);
+ localparam logic [DbgAddressBits-1:0] ProgBufBase = (dm::DataAddr - 4*dm::ProgBufSize);
+ localparam logic [DbgAddressBits-1:0] ProgBufEnd = (dm::DataAddr - 1);
+ localparam logic [DbgAddressBits-1:0] AbstractCmdBase = (ProgBufBase - 4*10);
+ localparam logic [DbgAddressBits-1:0] AbstractCmdEnd = (ProgBufBase - 1);
+ localparam logic [DbgAddressBits-1:0] WhereTo = 'h300;
+ localparam logic [DbgAddressBits-1:0] FlagsBase = 'h400;
+ localparam logic [DbgAddressBits-1:0] FlagsEnd = 'h7FF;
+
+
+ localparam logic [DbgAddressBits-1:0] Halted = 'h100;
+ localparam logic [DbgAddressBits-1:0] Going = 'h104;
+ localparam logic [DbgAddressBits-1:0] Resuming = 'h108;
+ localparam logic [DbgAddressBits-1:0] Exception = 'h10C;
+
+ logic [dm::ProgBufSize/2-1:0][63:0] progbuf;
+ logic [4:0][63:0] abstract_cmd;
+ logic [NrHarts-1:0] halted_d, halted_q;
+ logic [NrHarts-1:0] resuming_d, resuming_q;
+ logic resume, go, going;
+ logic [NrHarts-1:0] halted;
+
+ logic [HartSelLen-1:0] hart_sel;
+ logic exception;
+ logic unsupported_command;
+
+ logic [63:0] rom_rdata;
+ logic [63:0] rdata_d, rdata_q;
+ logic word_enable32_q;
+
+ // distinguish whether we need to forward data from the ROM or the FSM
+ // latch the address for this
+ logic fwd_rom_d, fwd_rom_q;
+ dm::ac_ar_cmd_t ac_ar;
+
+ // Abstract Command Access Register
+ assign ac_ar = dm::ac_ar_cmd_t'(cmd_i.control);
+ assign hart_sel = wdata_i[HartSelLen-1:0];
+ assign debug_req_o = haltreq_i;
+ assign halted_o = halted_q;
+ assign resuming_o = resuming_q;
+
+ // reshape progbuf
+ assign progbuf = progbuf_i;
+
+ typedef enum logic [1:0] { Idle, Go, Resume, CmdExecuting } state_e;
+ state_e state_d, state_q;
+
+ // hart ctrl queue
+ always_comb begin
+ cmderror_valid_o = 1'b0;
+ cmderror_o = dm::CmdErrNone;
+ state_d = state_q;
+ go = 1'b0;
+ resume = 1'b0;
+ cmdbusy_o = 1'b1;
+
+ case (state_q)
+ Idle: begin
+ cmdbusy_o = 1'b0;
+ if (cmd_valid_i && halted_q[hartsel_i]) begin
+ // give the go signal
+ state_d = Go;
+ end else if (cmd_valid_i) begin
+ // hart must be halted for all requests
+ cmderror_valid_o = 1'b1;
+ cmderror_o = dm::CmdErrorHaltResume;
end
-
- if (exception) begin
- cmderror_valid_o = 1'b1;
- cmderror_o = dm::CmdErrorException;
- end
-
- end
-
- // read/write logic
- always_comb begin
- automatic logic [63:0] data_bits;
-
- halted_d = halted_q;
- resuming_d = resuming_q;
- rdata_o = (BusWidth == 64) ?
- (fwd_rom_q ? rom_rdata : rdata_q) :
- (word_enable32_q ?
- (fwd_rom_q ? rom_rdata[63:32] : rdata_q[63:32]) :
- (fwd_rom_q ? rom_rdata[31: 0] : rdata_q[31: 0]));
- rdata_d = rdata_q;
- // convert the data in bits representation
- data_bits = data_i;
- // write data in csr register
- data_valid_o = 1'b0;
- exception = 1'b0;
- halted = '0;
- going = 1'b0;
- // The resume ack signal is lowered when the resume request is deasserted
- if (clear_resumeack_i) begin
- resuming_d[hartsel_i] = 1'b0;
+ // CSRs want to resume, the request is ignored when the hart is
+ // requested to halt or it didn't clear the resuming_q bit before
+ if (resumereq_i[hartsel_i] && !resuming_q[hartsel_i] &&
+ !haltreq_i[hartsel_i] && halted_q[hartsel_i]) begin
+ state_d = Resume;
end
- // we've got a new request
- if (req_i) begin
- // this is a write
- if (we_i) begin
- unique case (addr_i[DbgAddressBits-1:0]) inside
- Halted: begin
- halted[hart_sel] = 1'b1;
- halted_d[hart_sel] = 1'b1;
- end
- Going: begin
- going = 1'b1;
- end
- Resuming: begin
- // clear the halted flag as the hart resumed execution
- halted_d[hart_sel] = 1'b0;
- // set the resuming flag which needs to be cleared by the debugger
- resuming_d[hart_sel] = 1'b1;
- end
- // an exception occurred during execution
- Exception: exception = 1'b1;
- // core can write data registers
- [(dm::DataAddr):DataEnd]: begin
- data_valid_o = 1'b1;
- for (int i = 0; i < $bits(be_i); i++) begin
- if (be_i[i]) begin
- data_bits[i*8+:8] = wdata_i[i*8+:8];
- end
- end
- end
- default ;
- endcase
-
- // this is a read
- end else begin
- unique case (addr_i[DbgAddressBits-1:0]) inside
- // variable ROM content
- WhereTo: begin
- // variable jump to abstract cmd, program_buffer or resume
- if (resumereq_i[hart_sel]) begin
- rdata_d = {32'b0, dm::jal('0, dm::ResumeAddress[11:0]-WhereTo)};
- end
-
- // there is a command active so jump there
- if (cmdbusy_o) begin
- // transfer not set is shortcut to the program buffer if postexec is set
- // keep this statement narrow to not catch invalid commands
- if (cmd_i.cmdtype == dm::AccessRegister &&
- !ac_ar.transfer && ac_ar.postexec) begin
- rdata_d = {32'b0, dm::jal('0, ProgBufBase-WhereTo)};
- // this is a legit abstract cmd -> execute it
- end else begin
- rdata_d = {32'b0, dm::jal('0, AbstractCmdBase-WhereTo)};
- end
- end
- end
-
- [DataBase:DataEnd]: begin
- rdata_d = {
- data_i[(addr_i[DbgAddressBits-1:3] - DataBase[DbgAddressBits-1:3] + 1)],
- data_i[(addr_i[DbgAddressBits-1:3] - DataBase[DbgAddressBits-1:3])]
- };
- end
-
- [ProgBufBase:ProgBufEnd]: begin
- rdata_d = progbuf[(addr_i[DbgAddressBits-1:3] -
- ProgBufBase[DbgAddressBits-1:3])];
- end
-
- // two slots for abstract command
- [AbstractCmdBase:AbstractCmdEnd]: begin
- // return the correct address index
- rdata_d = abstract_cmd[(addr_i[DbgAddressBits-1:3] -
- AbstractCmdBase[DbgAddressBits-1:3])];
- end
- // harts are polling for flags here
- [FlagsBase:FlagsEnd]: begin
- automatic logic [7:0][7:0] rdata;
- rdata = '0;
- // release the corresponding hart
- if (({addr_i[DbgAddressBits-1:3], 3'b0} - FlagsBase[DbgAddressBits-1:0]) ==
- {hartsel_i[DbgAddressBits-1:3], 3'b0}) begin
- rdata[hartsel_i[2:0]] = {6'b0, resume, go};
- end
- rdata_d = rdata;
- end
- default: ;
- endcase
- end
+ end
+
+ Go: begin
+ // we are already busy here since we scheduled the execution of a program
+ cmdbusy_o = 1'b1;
+ go = 1'b1;
+ // the thread is now executing the command, track its state
+ if (going)
+ state_d = CmdExecuting;
+ end
+
+ Resume: begin
+ cmdbusy_o = 1'b1;
+ resume = 1'b1;
+ if (resuming_o[hartsel_i])
+ state_d = Idle;
+ end
+
+ CmdExecuting: begin
+ cmdbusy_o = 1'b1;
+ go = 1'b0;
+ // wait until the hart has halted again
+ if (halted[hartsel_i]) begin
+ state_d = Idle;
end
+ end
+ endcase
+
+ // only signal once that cmd is unsupported so that we can clear cmderr
+ // in subsequent writes to abstractcs
+ if (unsupported_command && cmd_valid_i) begin
+ cmderror_valid_o = 1'b1;
+ cmderror_o = dm::CmdErrNotSupported;
+ end
- data_o = data_bits;
+ if (exception) begin
+ cmderror_valid_o = 1'b1;
+ cmderror_o = dm::CmdErrorException;
end
+ end
+
+ // read/write logic
+ always_comb begin
+ automatic logic [63:0] data_bits;
+
+ halted_d = halted_q;
+ resuming_d = resuming_q;
+ rdata_o = (BusWidth == 64) ?
+ (fwd_rom_q ? rom_rdata : rdata_q) :
+ (word_enable32_q ?
+ (fwd_rom_q ? rom_rdata[63:32] : rdata_q[63:32]) :
+ (fwd_rom_q ? rom_rdata[31: 0] : rdata_q[31: 0]));
+ rdata_d = rdata_q;
+ // convert the data in bits representation
+ data_bits = data_i;
+ // write data in csr register
+ data_valid_o = 1'b0;
+ exception = 1'b0;
+ halted = '0;
+ going = 1'b0;
+ // The resume ack signal is lowered when the resume request is deasserted
+ if (clear_resumeack_i) begin
+ resuming_d[hartsel_i] = 1'b0;
+ end
+ // we've got a new request
+ if (req_i) begin
+ // this is a write
+ if (we_i) begin
+ unique case (addr_i[DbgAddressBits-1:0]) inside
+ Halted: begin
+ halted[hart_sel] = 1'b1;
+ halted_d[hart_sel] = 1'b1;
+ end
+ Going: begin
+ going = 1'b1;
+ end
+ Resuming: begin
+ // clear the halted flag as the hart resumed execution
+ halted_d[hart_sel] = 1'b0;
+ // set the resuming flag which needs to be cleared by the debugger
+ resuming_d[hart_sel] = 1'b1;
+ end
+ // an exception occurred during execution
+ Exception: exception = 1'b1;
+ // core can write data registers
+ [(dm::DataAddr):DataEnd]: begin
+ data_valid_o = 1'b1;
+ for (int i = 0; i < $bits(be_i); i++) begin
+ if (be_i[i]) begin
+ data_bits[i*8+:8] = wdata_i[i*8+:8];
+ end
+ end
+ end
+ default ;
+ endcase
- always_comb begin : abstract_cmd_rom
- // this abstract command is currently unsupported
- unsupported_command = 1'b0;
- // default memory
- // if ac_ar.transfer is not set then we can take a shortcut to the program buffer
- abstract_cmd[0][31:0] = dm::illegal();
- // load debug module base address into a0, this is shared among all commands
- abstract_cmd[0][63:32] = dm::auipc(5'd10, '0);
- abstract_cmd[1][31:0] = dm::srli(5'd10, 5'd10, 6'd12); // clr lowest 12b -> DM base offset
- abstract_cmd[1][63:32] = dm::slli(5'd10, 5'd10, 6'd12);
- abstract_cmd[2][31:0] = dm::nop();
- abstract_cmd[2][63:32] = dm::nop();
- abstract_cmd[3][31:0] = dm::nop();
- abstract_cmd[3][63:32] = dm::nop();
- abstract_cmd[4][31:0] = dm::csrr(dm::CSR_DSCRATCH1, 5'd10);
- abstract_cmd[4][63:32] = dm::ebreak();
-
- // this depends on the command being executed
- unique case (cmd_i.cmdtype)
- // --------------------
- // Access Register
- // --------------------
- dm::AccessRegister: begin
- if (ac_ar.aarsize < MaxAar && ac_ar.transfer && ac_ar.write) begin
- // store a0 in dscratch1
- abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
- // this range is reserved
- if (ac_ar.regno[15:14] != '0) begin
- abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
- unsupported_command = 1'b1;
- // A0 access needs to be handled separately, as we use A0 to load
- // the DM address offset need to access DSCRATCH1 in this case
- end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
- (ac_ar.regno[4:0] == 5'd10)) begin
- // store s0 in dscratch
- abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
- // load from data register
- abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
- // and store it in the corresponding CSR
- abstract_cmd[3][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd8);
- // restore s0 again from dscratch
- abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
- // GPR/FPR access
- end else if (ac_ar.regno[12]) begin
- // determine whether we want to access the floating point register or not
- if (ac_ar.regno[5]) begin
- abstract_cmd[2][31:0] =
- dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
- end else begin
- abstract_cmd[2][31:0] =
- dm::load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
- end
- // CSR access
- end else begin
- // data register to CSR
- // store s0 in dscratch
- abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
- // load from data register
- abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
- // and store it in the corresponding CSR
- abstract_cmd[3][31:0] = dm::csrw(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
- // restore s0 again from dscratch
- abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
- end
- end else if (ac_ar.aarsize < MaxAar && ac_ar.transfer && !ac_ar.write) begin
- // store a0 in dscratch1
- abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
- // this range is reserved
- if (ac_ar.regno[15:14] != '0) begin
- abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
- unsupported_command = 1'b1;
- // A0 access needs to be handled separately, as we use A0 to load
- // the DM address offset need to access DSCRATCH1 in this case
- end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
- (ac_ar.regno[4:0] == 5'd10)) begin
- // store s0 in dscratch
- abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
- // read value from CSR into s0
- abstract_cmd[2][63:32] = dm::csrr(dm::CSR_DSCRATCH1, 5'd8);
- // and store s0 into data section
- abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
- // restore s0 again from dscratch
- abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
- // GPR/FPR access
- end else if (ac_ar.regno[12]) begin
- // determine whether we want to access the floating point register or not
- if (ac_ar.regno[5]) begin
- abstract_cmd[2][31:0] =
- dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
- end else begin
- abstract_cmd[2][31:0] =
- dm::store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
- end
- // CSR access
- end else begin
- // CSR register to data
- // store s0 in dscratch
- abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
- // read value from CSR into s0
- abstract_cmd[2][63:32] = dm::csrr(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
- // and store s0 into data section
- abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
- // restore s0 again from dscratch
- abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
- end
- end else if (ac_ar.aarsize >= MaxAar || ac_ar.aarpostincrement == 1'b1) begin
- // this should happend when e.g. ac_ar.aarsize >= MaxAar
- // Openocd will try to do an access with aarsize=64 bits
- // first before falling back to 32 bits.
- abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
- unsupported_command = 1'b1;
-
- end
-
- // Check whether we need to execute the program buffer. When we
- // get an unsupported command we really should abort instead of
- // still trying to execute the program buffer, makes it easier
- // for the debugger to recover
- if (ac_ar.postexec && !unsupported_command) begin
- // issue a nop, we will automatically run into the program buffer
- abstract_cmd[4][63:32] = dm::nop();
- end
+ // this is a read
+ end else begin
+ unique case (addr_i[DbgAddressBits-1:0]) inside
+ // variable ROM content
+ WhereTo: begin
+ // variable jump to abstract cmd, program_buffer or resume
+ if (resumereq_i[hart_sel]) begin
+ rdata_d = {32'b0, dm::jal('0, dm::ResumeAddress[11:0]-WhereTo)};
+ end
+ // there is a command active so jump there
+ if (cmdbusy_o) begin
+ // transfer not set is shortcut to the program buffer if postexec is set
+ // keep this statement narrow to not catch invalid commands
+ if (cmd_i.cmdtype == dm::AccessRegister &&
+ !ac_ar.transfer && ac_ar.postexec) begin
+ rdata_d = {32'b0, dm::jal('0, ProgBufBase-WhereTo)};
+ // this is a legit abstract cmd -> execute it
+ end else begin
+ rdata_d = {32'b0, dm::jal('0, AbstractCmdBase-WhereTo)};
+ end
end
- // not supported at the moment
- // dm::QuickAccess:;
- // dm::AccessMemory:;
- default: begin
- abstract_cmd[0][31:0] = dm::ebreak();
- unsupported_command = 1'b1;
+ end
+
+ [DataBase:DataEnd]: begin
+ rdata_d = {
+ data_i[(addr_i[DbgAddressBits-1:3] - DataBase[DbgAddressBits-1:3] + 1)],
+ data_i[(addr_i[DbgAddressBits-1:3] - DataBase[DbgAddressBits-1:3])]
+ };
+ end
+
+ [ProgBufBase:ProgBufEnd]: begin
+ rdata_d = progbuf[(addr_i[DbgAddressBits-1:3] -
+ ProgBufBase[DbgAddressBits-1:3])];
+ end
+
+ // two slots for abstract command
+ [AbstractCmdBase:AbstractCmdEnd]: begin
+ // return the correct address index
+ rdata_d = abstract_cmd[(addr_i[DbgAddressBits-1:3] -
+ AbstractCmdBase[DbgAddressBits-1:3])];
+ end
+ // harts are polling for flags here
+ [FlagsBase:FlagsEnd]: begin
+ automatic logic [7:0][7:0] rdata;
+ rdata = '0;
+ // release the corresponding hart
+ if (({addr_i[DbgAddressBits-1:3], 3'b0} - FlagsBase[DbgAddressBits-1:0]) ==
+ {hartsel_i[DbgAddressBits-1:3], 3'b0}) begin
+ rdata[hartsel_i[2:0]] = {6'b0, resume, go};
end
+ rdata_d = rdata;
+ end
+ default: ;
endcase
+ end
end
- logic [63:0] rom_addr;
- assign rom_addr = 64'(addr_i);
- debug_rom i_debug_rom (
- .clk_i,
- .req_i,
- .addr_i ( rom_addr ),
- .rdata_o ( rom_rdata )
- );
-
- // ROM starts at the HaltAddress of the core e.g.: it immediately jumps to
- // the ROM base address
- assign fwd_rom_d = (addr_i[DbgAddressBits-1:0] >= dm::HaltAddress[DbgAddressBits-1:0]) ?
- 1'b1 : 1'b0;
-
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- fwd_rom_q <= 1'b0;
- rdata_q <= '0;
- state_q <= Idle;
- word_enable32_q <= 1'b0;
- end else begin
- fwd_rom_q <= fwd_rom_d;
- rdata_q <= rdata_d;
- state_q <= state_d;
- word_enable32_q <= addr_i[2];
- end
- end
-
- for (genvar k = 0; k < NrHarts; k++) begin : gen_halted
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- halted_q[k] <= 1'b0;
- resuming_q[k] <= 1'b0;
+ data_o = data_bits;
+ end
+
+ always_comb begin : abstract_cmd_rom
+ // this abstract command is currently unsupported
+ unsupported_command = 1'b0;
+ // default memory
+ // if ac_ar.transfer is not set then we can take a shortcut to the program buffer
+ abstract_cmd[0][31:0] = dm::illegal();
+ // load debug module base address into a0, this is shared among all commands
+ abstract_cmd[0][63:32] = dm::auipc(5'd10, '0);
+ abstract_cmd[1][31:0] = dm::srli(5'd10, 5'd10, 6'd12); // clr lowest 12b -> DM base offset
+ abstract_cmd[1][63:32] = dm::slli(5'd10, 5'd10, 6'd12);
+ abstract_cmd[2][31:0] = dm::nop();
+ abstract_cmd[2][63:32] = dm::nop();
+ abstract_cmd[3][31:0] = dm::nop();
+ abstract_cmd[3][63:32] = dm::nop();
+ abstract_cmd[4][31:0] = dm::csrr(dm::CSR_DSCRATCH1, 5'd10);
+ abstract_cmd[4][63:32] = dm::ebreak();
+
+ // this depends on the command being executed
+ unique case (cmd_i.cmdtype)
+ // --------------------
+ // Access Register
+ // --------------------
+ dm::AccessRegister: begin
+ if (ac_ar.aarsize < MaxAar && ac_ar.transfer && ac_ar.write) begin
+ // store a0 in dscratch1
+ abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
+ // this range is reserved
+ if (ac_ar.regno[15:14] != '0) begin
+ abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
+ unsupported_command = 1'b1;
+ // A0 access needs to be handled separately, as we use A0 to load
+ // the DM address offset need to access DSCRATCH1 in this case
+ end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
+ (ac_ar.regno[4:0] == 5'd10)) begin
+ // store s0 in dscratch
+ abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
+ // load from data register
+ abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ // and store it in the corresponding CSR
+ abstract_cmd[3][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd8);
+ // restore s0 again from dscratch
+ abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
+ // GPR/FPR access
+ end else if (ac_ar.regno[12]) begin
+ // determine whether we want to access the floating point register or not
+ if (ac_ar.regno[5]) begin
+ abstract_cmd[2][31:0] =
+ dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ end else begin
+ abstract_cmd[2][31:0] =
+ dm::load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ end
+ // CSR access
+ end else begin
+ // data register to CSR
+ // store s0 in dscratch
+ abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
+ // load from data register
+ abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ // and store it in the corresponding CSR
+ abstract_cmd[3][31:0] = dm::csrw(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
+ // restore s0 again from dscratch
+ abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
+ end
+ end else if (ac_ar.aarsize < MaxAar && ac_ar.transfer && !ac_ar.write) begin
+ // store a0 in dscratch1
+ abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
+ // this range is reserved
+ if (ac_ar.regno[15:14] != '0) begin
+ abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
+ unsupported_command = 1'b1;
+ // A0 access needs to be handled separately, as we use A0 to load
+ // the DM address offset need to access DSCRATCH1 in this case
+ end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
+ (ac_ar.regno[4:0] == 5'd10)) begin
+ // store s0 in dscratch
+ abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
+ // read value from CSR into s0
+ abstract_cmd[2][63:32] = dm::csrr(dm::CSR_DSCRATCH1, 5'd8);
+ // and store s0 into data section
+ abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ // restore s0 again from dscratch
+ abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
+ // GPR/FPR access
+ end else if (ac_ar.regno[12]) begin
+ // determine whether we want to access the floating point register or not
+ if (ac_ar.regno[5]) begin
+ abstract_cmd[2][31:0] =
+ dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
end else begin
- halted_q[k] <= SelectableHarts[k] ? halted_d[k] : 1'b0;
- resuming_q[k] <= SelectableHarts[k] ? resuming_d[k] : 1'b0;
+ abstract_cmd[2][31:0] =
+ dm::store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
end
+ // CSR access
+ end else begin
+ // CSR register to data
+ // store s0 in dscratch
+ abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
+ // read value from CSR into s0
+ abstract_cmd[2][63:32] = dm::csrr(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
+ // and store s0 into data section
+ abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ // restore s0 again from dscratch
+ abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
+ end
+ end else if (ac_ar.aarsize >= MaxAar || ac_ar.aarpostincrement == 1'b1) begin
+ // this should happend when e.g. ac_ar.aarsize >= MaxAar
+ // Openocd will try to do an access with aarsize=64 bits
+ // first before falling back to 32 bits.
+ abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
+ unsupported_command = 1'b1;
end
+ // Check whether we need to execute the program buffer. When we
+ // get an unsupported command we really should abort instead of
+ // still trying to execute the program buffer, makes it easier
+ // for the debugger to recover
+ if (ac_ar.postexec && !unsupported_command) begin
+ // issue a nop, we will automatically run into the program buffer
+ abstract_cmd[4][63:32] = dm::nop();
+ end
+ end
+ // not supported at the moment
+ // dm::QuickAccess:;
+ // dm::AccessMemory:;
+ default: begin
+ abstract_cmd[0][31:0] = dm::ebreak();
+ unsupported_command = 1'b1;
+ end
+ endcase
+ end
+
+ logic [63:0] rom_addr;
+ assign rom_addr = 64'(addr_i);
+ debug_rom i_debug_rom (
+ .clk_i,
+ .req_i,
+ .addr_i ( rom_addr ),
+ .rdata_o ( rom_rdata )
+ );
+
+ // ROM starts at the HaltAddress of the core e.g.: it immediately jumps to
+ // the ROM base address
+ assign fwd_rom_d = (addr_i[DbgAddressBits-1:0] >= dm::HaltAddress[DbgAddressBits-1:0]) ?
+ 1'b1 : 1'b0;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ fwd_rom_q <= 1'b0;
+ rdata_q <= '0;
+ state_q <= Idle;
+ word_enable32_q <= 1'b0;
+ end else begin
+ fwd_rom_q <= fwd_rom_d;
+ rdata_q <= rdata_d;
+ state_q <= state_d;
+ word_enable32_q <= addr_i[2];
+ end
+ end
+
+ for (genvar k = 0; k < NrHarts; k++) begin : gen_halted
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ halted_q[k] <= 1'b0;
+ resuming_q[k] <= 1'b0;
+ end else begin
+ halted_q[k] <= SelectableHarts[k] ? halted_d[k] : 1'b0;
+ resuming_q[k] <= SelectableHarts[k] ? resuming_d[k] : 1'b0;
+ end
end
+ end
endmodule
diff --git a/src/dm_pkg.sv b/src/dm_pkg.sv
index b2593d6..49e77be 100644
--- a/src/dm_pkg.sv
+++ b/src/dm_pkg.sv
@@ -17,370 +17,370 @@
*/
package dm;
- localparam logic [3:0] DbgVersion013 = 4'h2;
- // size of program buffer in junks of 32-bit words
- localparam logic [4:0] ProgBufSize = 5'h8;
-
- // amount of data count registers implemented
- localparam logic [3:0] DataCount = 4'h2;
-
- // address to which a hart should jump when it was requested to halt
- localparam logic [63:0] HaltAddress = 64'h800;
- localparam logic [63:0] ResumeAddress = HaltAddress + 4;
- localparam logic [63:0] ExceptionAddress = HaltAddress + 8;
-
- // address where data0-15 is shadowed or if shadowed in a CSR
- // address of the first CSR used for shadowing the data
- localparam logic [11:0] DataAddr = 12'h380; // we are aligned with Rocket here
-
- // debug registers
- typedef enum logic [7:0] {
- Data0 = 8'h04,
- Data1 = 8'h05,
- Data2 = 8'h06,
- Data3 = 8'h07,
- Data4 = 8'h08,
- Data5 = 8'h09,
- Data6 = 8'h0A,
- Data7 = 8'h0B,
- Data8 = 8'h0C,
- Data9 = 8'h0D,
- Data10 = 8'h0E,
- Data11 = 8'h0F,
- DMControl = 8'h10,
- DMStatus = 8'h11, // r/o
- Hartinfo = 8'h12,
- HaltSum1 = 8'h13,
- HAWindowSel = 8'h14,
- HAWindow = 8'h15,
- AbstractCS = 8'h16,
- Command = 8'h17,
- AbstractAuto = 8'h18,
- DevTreeAddr0 = 8'h19,
- DevTreeAddr1 = 8'h1A,
- DevTreeAddr2 = 8'h1B,
- DevTreeAddr3 = 8'h1C,
- NextDM = 8'h1D,
- ProgBuf0 = 8'h20,
- ProgBuf15 = 8'h2F,
- AuthData = 8'h30,
- HaltSum2 = 8'h34,
- HaltSum3 = 8'h35,
- SBAddress3 = 8'h37,
- SBCS = 8'h38,
- SBAddress0 = 8'h39,
- SBAddress1 = 8'h3A,
- SBAddress2 = 8'h3B,
- SBData0 = 8'h3C,
- SBData1 = 8'h3D,
- SBData2 = 8'h3E,
- SBData3 = 8'h3F,
- HaltSum0 = 8'h40
- } dm_csr_e;
-
- // debug causes
- localparam logic [2:0] CauseBreakpoint = 3'h1;
- localparam logic [2:0] CauseTrigger = 3'h2;
- localparam logic [2:0] CauseRequest = 3'h3;
- localparam logic [2:0] CauseSingleStep = 3'h4;
-
- typedef struct packed {
- logic [31:23] zero1;
- logic impebreak;
- logic [21:20] zero0;
- logic allhavereset;
- logic anyhavereset;
- logic allresumeack;
- logic anyresumeack;
- logic allnonexistent;
- logic anynonexistent;
- logic allunavail;
- logic anyunavail;
- logic allrunning;
- logic anyrunning;
- logic allhalted;
- logic anyhalted;
- logic authenticated;
- logic authbusy;
- logic hasresethaltreq;
- logic devtreevalid;
- logic [3:0] version;
- } dmstatus_t;
-
- typedef struct packed {
- logic haltreq;
- logic resumereq;
- logic hartreset;
- logic ackhavereset;
- logic zero1;
- logic hasel;
- logic [25:16] hartsello;
- logic [15:6] hartselhi;
- logic [5:4] zero0;
- logic setresethaltreq;
- logic clrresethaltreq;
- logic ndmreset;
- logic dmactive;
- } dmcontrol_t;
-
- typedef struct packed {
- logic [31:24] zero1;
- logic [23:20] nscratch;
- logic [19:17] zero0;
- logic dataaccess;
- logic [15:12] datasize;
- logic [11:0] dataaddr;
- } hartinfo_t;
-
- typedef enum logic [2:0] { CmdErrNone, CmdErrBusy, CmdErrNotSupported,
- CmdErrorException, CmdErrorHaltResume,
- CmdErrorBus, CmdErrorOther = 7
- } cmderr_e;
-
- typedef struct packed {
- logic [31:29] zero3;
- logic [28:24] progbufsize;
- logic [23:13] zero2;
- logic busy;
- logic zero1;
- cmderr_e cmderr;
- logic [7:4] zero0;
- logic [3:0] datacount;
- } abstractcs_t;
-
- typedef enum logic [7:0] {
- AccessRegister = 8'h0,
- QuickAccess = 8'h1,
- AccessMemory = 8'h2
- } cmd_e;
-
- typedef struct packed {
- cmd_e cmdtype;
- logic [23:0] control;
- } command_t;
-
- typedef struct packed {
- logic [31:16] autoexecprogbuf;
- logic [15:12] zero0;
- logic [11:0] autoexecdata;
- } abstractauto_t;
-
- typedef struct packed {
- logic zero1;
- logic [22:20] aarsize;
- logic aarpostincrement;
- logic postexec;
- logic transfer;
- logic write;
- logic [15:0] regno;
- } ac_ar_cmd_t;
-
- // DTM
- typedef enum logic [1:0] {
- DTM_NOP = 2'h0,
- DTM_READ = 2'h1,
- DTM_WRITE = 2'h2
- } dtm_op_e;
-
- typedef struct packed {
- logic [31:29] sbversion;
- logic [28:23] zero0;
- logic sbbusyerror;
- logic sbbusy;
- logic sbreadonaddr;
- logic [19:17] sbaccess;
- logic sbautoincrement;
- logic sbreadondata;
- logic [14:12] sberror;
- logic [11:5] sbasize;
- logic sbaccess128;
- logic sbaccess64;
- logic sbaccess32;
- logic sbaccess16;
- logic sbaccess8;
- } sbcs_t;
-
- localparam logic[1:0] DTM_SUCCESS = 2'h0;
-
- typedef struct packed {
- logic [6:0] addr;
- dtm_op_e op;
- logic [31:0] data;
- } dmi_req_t;
-
- typedef struct packed {
- logic [31:0] data;
- logic [1:0] resp;
- } dmi_resp_t;
-
- // privilege levels
- typedef enum logic[1:0] {
- PRIV_LVL_M = 2'b11,
- PRIV_LVL_S = 2'b01,
- PRIV_LVL_U = 2'b00
- } priv_lvl_t;
-
- // debugregs in core
- typedef struct packed {
- logic [31:28] xdebugver;
- logic [27:16] zero2;
- logic ebreakm;
- logic zero1;
- logic ebreaks;
- logic ebreaku;
- logic stepie;
- logic stopcount;
- logic stoptime;
- logic [8:6] cause;
- logic zero0;
- logic mprven;
- logic nmip;
- logic step;
- priv_lvl_t prv;
- } dcsr_t;
-
- // CSRs
- typedef enum logic [11:0] {
- // Floating-Point CSRs
- CSR_FFLAGS = 12'h001,
- CSR_FRM = 12'h002,
- CSR_FCSR = 12'h003,
- CSR_FTRAN = 12'h800,
- // Supervisor Mode CSRs
- CSR_SSTATUS = 12'h100,
- CSR_SIE = 12'h104,
- CSR_STVEC = 12'h105,
- CSR_SCOUNTEREN = 12'h106,
- CSR_SSCRATCH = 12'h140,
- CSR_SEPC = 12'h141,
- CSR_SCAUSE = 12'h142,
- CSR_STVAL = 12'h143,
- CSR_SIP = 12'h144,
- CSR_SATP = 12'h180,
- // Machine Mode CSRs
- CSR_MSTATUS = 12'h300,
- CSR_MISA = 12'h301,
- CSR_MEDELEG = 12'h302,
- CSR_MIDELEG = 12'h303,
- CSR_MIE = 12'h304,
- CSR_MTVEC = 12'h305,
- CSR_MCOUNTEREN = 12'h306,
- CSR_MSCRATCH = 12'h340,
- CSR_MEPC = 12'h341,
- CSR_MCAUSE = 12'h342,
- CSR_MTVAL = 12'h343,
- CSR_MIP = 12'h344,
- CSR_PMPCFG0 = 12'h3A0,
- CSR_PMPADDR0 = 12'h3B0,
- CSR_MVENDORID = 12'hF11,
- CSR_MARCHID = 12'hF12,
- CSR_MIMPID = 12'hF13,
- CSR_MHARTID = 12'hF14,
- CSR_MCYCLE = 12'hB00,
- CSR_MINSTRET = 12'hB02,
- CSR_DCACHE = 12'h701,
- CSR_ICACHE = 12'h700,
-
- CSR_TSELECT = 12'h7A0,
- CSR_TDATA1 = 12'h7A1,
- CSR_TDATA2 = 12'h7A2,
- CSR_TDATA3 = 12'h7A3,
- CSR_TINFO = 12'h7A4,
-
- // Debug CSR
- CSR_DCSR = 12'h7b0,
- CSR_DPC = 12'h7b1,
- CSR_DSCRATCH0 = 12'h7b2, // optional
- CSR_DSCRATCH1 = 12'h7b3, // optional
-
- // Counters and Timers
- CSR_CYCLE = 12'hC00,
- CSR_TIME = 12'hC01,
- CSR_INSTRET = 12'hC02
- } csr_reg_t;
-
-
- // Instruction Generation Helpers
- function automatic logic [31:0] jal (logic[4:0] rd, logic [20:0] imm);
- // OpCode Jal
- return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f};
- endfunction
-
- function automatic logic [31:0] jalr (logic[4:0] rd, logic[4:0] rs1, logic [11:0] offset);
- // OpCode Jal
- return {offset[11:0], rs1, 3'b0, rd, 7'h67};
- endfunction
-
- function automatic logic [31:0] andi (logic[4:0] rd, logic[4:0] rs1, logic [11:0] imm);
- // OpCode andi
- return {imm[11:0], rs1, 3'h7, rd, 7'h13};
- endfunction
-
- function automatic logic [31:0] slli (logic[4:0] rd, logic[4:0] rs1, logic [5:0] shamt);
- // OpCode slli
- return {6'b0, shamt[5:0], rs1, 3'h1, rd, 7'h13};
- endfunction
-
- function automatic logic [31:0] srli (logic[4:0] rd, logic[4:0] rs1, logic [5:0] shamt);
- // OpCode srli
- return {6'b0, shamt[5:0], rs1, 3'h5, rd, 7'h13};
- endfunction
-
- function automatic logic [31:0] load (logic [2:0] size, logic[4:0] dest, logic[4:0] base, logic [11:0] offset);
- // OpCode Load
- return {offset[11:0], base, size, dest, 7'h03};
- endfunction
-
- function automatic logic [31:0] auipc (logic[4:0] rd, logic [20:0] imm);
- // OpCode Auipc
- return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h17};
- endfunction
-
- function automatic logic [31:0] store (logic [2:0] size, logic[4:0] src, logic[4:0] base, logic [11:0] offset);
- // OpCode Store
- return {offset[11:5], src, base, size, offset[4:0], 7'h23};
- endfunction
-
- function automatic logic [31:0] float_load (logic [2:0] size, logic[4:0] dest, logic[4:0] base, logic [11:0] offset);
- // OpCode Load
- return {offset[11:0], base, size, dest, 7'b00_001_11};
- endfunction
-
- function automatic logic [31:0] float_store (logic [2:0] size, logic[4:0] src, logic[4:0] base, logic [11:0] offset);
- // OpCode Store
- return {offset[11:5], src, base, size, offset[4:0], 7'b01_001_11};
- endfunction
-
- function automatic logic [31:0] csrw (csr_reg_t csr, logic[4:0] rs1);
- // CSRRW, rd, OpCode System
- return {csr, rs1, 3'h1, 5'h0, 7'h73};
- endfunction
-
- function automatic logic [31:0] csrr (csr_reg_t csr, logic [4:0] dest);
- // rs1, CSRRS, rd, OpCode System
- return {csr, 5'h0, 3'h2, dest, 7'h73};
- endfunction
-
- function automatic logic [31:0] branch(logic [4:0] src2, logic [4:0] src1, logic [2:0] funct3, logic [11:0] offset);
- // OpCode Branch
- return {offset[11], offset[9:4], src2, src1, funct3, offset[3:0], offset[10], 7'b11_000_11};
- endfunction
-
- function automatic logic [31:0] ebreak ();
- return 32'h00100073;
- endfunction
-
- function automatic logic [31:0] wfi ();
- return 32'h10500073;
- endfunction
-
- function automatic logic [31:0] nop ();
- return 32'h00000013;
- endfunction
-
- function automatic logic [31:0] illegal ();
- return 32'h00000000;
- endfunction
-
+ localparam logic [3:0] DbgVersion013 = 4'h2;
+ // size of program buffer in junks of 32-bit words
+ localparam logic [4:0] ProgBufSize = 5'h8;
+
+ // amount of data count registers implemented
+ localparam logic [3:0] DataCount = 4'h2;
+
+ // address to which a hart should jump when it was requested to halt
+ localparam logic [63:0] HaltAddress = 64'h800;
+ localparam logic [63:0] ResumeAddress = HaltAddress + 4;
+ localparam logic [63:0] ExceptionAddress = HaltAddress + 8;
+
+ // address where data0-15 is shadowed or if shadowed in a CSR
+ // address of the first CSR used for shadowing the data
+ localparam logic [11:0] DataAddr = 12'h380; // we are aligned with Rocket here
+
+ // debug registers
+ typedef enum logic [7:0] {
+ Data0 = 8'h04,
+ Data1 = 8'h05,
+ Data2 = 8'h06,
+ Data3 = 8'h07,
+ Data4 = 8'h08,
+ Data5 = 8'h09,
+ Data6 = 8'h0A,
+ Data7 = 8'h0B,
+ Data8 = 8'h0C,
+ Data9 = 8'h0D,
+ Data10 = 8'h0E,
+ Data11 = 8'h0F,
+ DMControl = 8'h10,
+ DMStatus = 8'h11, // r/o
+ Hartinfo = 8'h12,
+ HaltSum1 = 8'h13,
+ HAWindowSel = 8'h14,
+ HAWindow = 8'h15,
+ AbstractCS = 8'h16,
+ Command = 8'h17,
+ AbstractAuto = 8'h18,
+ DevTreeAddr0 = 8'h19,
+ DevTreeAddr1 = 8'h1A,
+ DevTreeAddr2 = 8'h1B,
+ DevTreeAddr3 = 8'h1C,
+ NextDM = 8'h1D,
+ ProgBuf0 = 8'h20,
+ ProgBuf15 = 8'h2F,
+ AuthData = 8'h30,
+ HaltSum2 = 8'h34,
+ HaltSum3 = 8'h35,
+ SBAddress3 = 8'h37,
+ SBCS = 8'h38,
+ SBAddress0 = 8'h39,
+ SBAddress1 = 8'h3A,
+ SBAddress2 = 8'h3B,
+ SBData0 = 8'h3C,
+ SBData1 = 8'h3D,
+ SBData2 = 8'h3E,
+ SBData3 = 8'h3F,
+ HaltSum0 = 8'h40
+ } dm_csr_e;
+
+ // debug causes
+ localparam logic [2:0] CauseBreakpoint = 3'h1;
+ localparam logic [2:0] CauseTrigger = 3'h2;
+ localparam logic [2:0] CauseRequest = 3'h3;
+ localparam logic [2:0] CauseSingleStep = 3'h4;
+
+ typedef struct packed {
+ logic [31:23] zero1;
+ logic impebreak;
+ logic [21:20] zero0;
+ logic allhavereset;
+ logic anyhavereset;
+ logic allresumeack;
+ logic anyresumeack;
+ logic allnonexistent;
+ logic anynonexistent;
+ logic allunavail;
+ logic anyunavail;
+ logic allrunning;
+ logic anyrunning;
+ logic allhalted;
+ logic anyhalted;
+ logic authenticated;
+ logic authbusy;
+ logic hasresethaltreq;
+ logic devtreevalid;
+ logic [3:0] version;
+ } dmstatus_t;
+
+ typedef struct packed {
+ logic haltreq;
+ logic resumereq;
+ logic hartreset;
+ logic ackhavereset;
+ logic zero1;
+ logic hasel;
+ logic [25:16] hartsello;
+ logic [15:6] hartselhi;
+ logic [5:4] zero0;
+ logic setresethaltreq;
+ logic clrresethaltreq;
+ logic ndmreset;
+ logic dmactive;
+ } dmcontrol_t;
+
+ typedef struct packed {
+ logic [31:24] zero1;
+ logic [23:20] nscratch;
+ logic [19:17] zero0;
+ logic dataaccess;
+ logic [15:12] datasize;
+ logic [11:0] dataaddr;
+ } hartinfo_t;
+
+ typedef enum logic [2:0] {
+ CmdErrNone, CmdErrBusy, CmdErrNotSupported,
+ CmdErrorException, CmdErrorHaltResume,
+ CmdErrorBus, CmdErrorOther = 7
+ } cmderr_e;
+
+ typedef struct packed {
+ logic [31:29] zero3;
+ logic [28:24] progbufsize;
+ logic [23:13] zero2;
+ logic busy;
+ logic zero1;
+ cmderr_e cmderr;
+ logic [7:4] zero0;
+ logic [3:0] datacount;
+ } abstractcs_t;
+
+ typedef enum logic [7:0] {
+ AccessRegister = 8'h0,
+ QuickAccess = 8'h1,
+ AccessMemory = 8'h2
+ } cmd_e;
+
+ typedef struct packed {
+ cmd_e cmdtype;
+ logic [23:0] control;
+ } command_t;
+
+ typedef struct packed {
+ logic [31:16] autoexecprogbuf;
+ logic [15:12] zero0;
+ logic [11:0] autoexecdata;
+ } abstractauto_t;
+
+ typedef struct packed {
+ logic zero1;
+ logic [22:20] aarsize;
+ logic aarpostincrement;
+ logic postexec;
+ logic transfer;
+ logic write;
+ logic [15:0] regno;
+ } ac_ar_cmd_t;
+
+ // DTM
+ typedef enum logic [1:0] {
+ DTM_NOP = 2'h0,
+ DTM_READ = 2'h1,
+ DTM_WRITE = 2'h2
+ } dtm_op_e;
+
+ typedef struct packed {
+ logic [31:29] sbversion;
+ logic [28:23] zero0;
+ logic sbbusyerror;
+ logic sbbusy;
+ logic sbreadonaddr;
+ logic [19:17] sbaccess;
+ logic sbautoincrement;
+ logic sbreadondata;
+ logic [14:12] sberror;
+ logic [11:5] sbasize;
+ logic sbaccess128;
+ logic sbaccess64;
+ logic sbaccess32;
+ logic sbaccess16;
+ logic sbaccess8;
+ } sbcs_t;
+
+ localparam logic[1:0] DTM_SUCCESS = 2'h0;
+
+ typedef struct packed {
+ logic [6:0] addr;
+ dtm_op_e op;
+ logic [31:0] data;
+ } dmi_req_t;
+
+ typedef struct packed {
+ logic [31:0] data;
+ logic [1:0] resp;
+ } dmi_resp_t;
+
+ // privilege levels
+ typedef enum logic[1:0] {
+ PRIV_LVL_M = 2'b11,
+ PRIV_LVL_S = 2'b01,
+ PRIV_LVL_U = 2'b00
+ } priv_lvl_t;
+
+ // debugregs in core
+ typedef struct packed {
+ logic [31:28] xdebugver;
+ logic [27:16] zero2;
+ logic ebreakm;
+ logic zero1;
+ logic ebreaks;
+ logic ebreaku;
+ logic stepie;
+ logic stopcount;
+ logic stoptime;
+ logic [8:6] cause;
+ logic zero0;
+ logic mprven;
+ logic nmip;
+ logic step;
+ priv_lvl_t prv;
+ } dcsr_t;
+
+ // CSRs
+ typedef enum logic [11:0] {
+ // Floating-Point CSRs
+ CSR_FFLAGS = 12'h001,
+ CSR_FRM = 12'h002,
+ CSR_FCSR = 12'h003,
+ CSR_FTRAN = 12'h800,
+ // Supervisor Mode CSRs
+ CSR_SSTATUS = 12'h100,
+ CSR_SIE = 12'h104,
+ CSR_STVEC = 12'h105,
+ CSR_SCOUNTEREN = 12'h106,
+ CSR_SSCRATCH = 12'h140,
+ CSR_SEPC = 12'h141,
+ CSR_SCAUSE = 12'h142,
+ CSR_STVAL = 12'h143,
+ CSR_SIP = 12'h144,
+ CSR_SATP = 12'h180,
+ // Machine Mode CSRs
+ CSR_MSTATUS = 12'h300,
+ CSR_MISA = 12'h301,
+ CSR_MEDELEG = 12'h302,
+ CSR_MIDELEG = 12'h303,
+ CSR_MIE = 12'h304,
+ CSR_MTVEC = 12'h305,
+ CSR_MCOUNTEREN = 12'h306,
+ CSR_MSCRATCH = 12'h340,
+ CSR_MEPC = 12'h341,
+ CSR_MCAUSE = 12'h342,
+ CSR_MTVAL = 12'h343,
+ CSR_MIP = 12'h344,
+ CSR_PMPCFG0 = 12'h3A0,
+ CSR_PMPADDR0 = 12'h3B0,
+ CSR_MVENDORID = 12'hF11,
+ CSR_MARCHID = 12'hF12,
+ CSR_MIMPID = 12'hF13,
+ CSR_MHARTID = 12'hF14,
+ CSR_MCYCLE = 12'hB00,
+ CSR_MINSTRET = 12'hB02,
+ CSR_DCACHE = 12'h701,
+ CSR_ICACHE = 12'h700,
+
+ CSR_TSELECT = 12'h7A0,
+ CSR_TDATA1 = 12'h7A1,
+ CSR_TDATA2 = 12'h7A2,
+ CSR_TDATA3 = 12'h7A3,
+ CSR_TINFO = 12'h7A4,
+
+ // Debug CSR
+ CSR_DCSR = 12'h7b0,
+ CSR_DPC = 12'h7b1,
+ CSR_DSCRATCH0 = 12'h7b2, // optional
+ CSR_DSCRATCH1 = 12'h7b3, // optional
+
+ // Counters and Timers
+ CSR_CYCLE = 12'hC00,
+ CSR_TIME = 12'hC01,
+ CSR_INSTRET = 12'hC02
+ } csr_reg_t;
+
+
+ // Instruction Generation Helpers
+ function automatic logic [31:0] jal (logic[4:0] rd, logic [20:0] imm);
+ // OpCode Jal
+ return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f};
+ endfunction
+
+ function automatic logic [31:0] jalr (logic[4:0] rd, logic[4:0] rs1, logic [11:0] offset);
+ // OpCode Jal
+ return {offset[11:0], rs1, 3'b0, rd, 7'h67};
+ endfunction
+
+ function automatic logic [31:0] andi (logic[4:0] rd, logic[4:0] rs1, logic [11:0] imm);
+ // OpCode andi
+ return {imm[11:0], rs1, 3'h7, rd, 7'h13};
+ endfunction
+
+ function automatic logic [31:0] slli (logic[4:0] rd, logic[4:0] rs1, logic [5:0] shamt);
+ // OpCode slli
+ return {6'b0, shamt[5:0], rs1, 3'h1, rd, 7'h13};
+ endfunction
+
+ function automatic logic [31:0] srli (logic[4:0] rd, logic[4:0] rs1, logic [5:0] shamt);
+ // OpCode srli
+ return {6'b0, shamt[5:0], rs1, 3'h5, rd, 7'h13};
+ endfunction
+
+ function automatic logic [31:0] load (logic [2:0] size, logic[4:0] dest, logic[4:0] base, logic [11:0] offset);
+ // OpCode Load
+ return {offset[11:0], base, size, dest, 7'h03};
+ endfunction
+
+ function automatic logic [31:0] auipc (logic[4:0] rd, logic [20:0] imm);
+ // OpCode Auipc
+ return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h17};
+ endfunction
+
+ function automatic logic [31:0] store (logic [2:0] size, logic[4:0] src, logic[4:0] base, logic [11:0] offset);
+ // OpCode Store
+ return {offset[11:5], src, base, size, offset[4:0], 7'h23};
+ endfunction
+
+ function automatic logic [31:0] float_load (logic [2:0] size, logic[4:0] dest, logic[4:0] base, logic [11:0] offset);
+ // OpCode Load
+ return {offset[11:0], base, size, dest, 7'b00_001_11};
+ endfunction
+
+ function automatic logic [31:0] float_store (logic [2:0] size, logic[4:0] src, logic[4:0] base, logic [11:0] offset);
+ // OpCode Store
+ return {offset[11:5], src, base, size, offset[4:0], 7'b01_001_11};
+ endfunction
+
+ function automatic logic [31:0] csrw (csr_reg_t csr, logic[4:0] rs1);
+ // CSRRW, rd, OpCode System
+ return {csr, rs1, 3'h1, 5'h0, 7'h73};
+ endfunction
+
+ function automatic logic [31:0] csrr (csr_reg_t csr, logic [4:0] dest);
+ // rs1, CSRRS, rd, OpCode System
+ return {csr, 5'h0, 3'h2, dest, 7'h73};
+ endfunction
+
+ function automatic logic [31:0] branch(logic [4:0] src2, logic [4:0] src1, logic [2:0] funct3, logic [11:0] offset);
+ // OpCode Branch
+ return {offset[11], offset[9:4], src2, src1, funct3, offset[3:0], offset[10], 7'b11_000_11};
+ endfunction
+
+ function automatic logic [31:0] ebreak ();
+ return 32'h00100073;
+ endfunction
+
+ function automatic logic [31:0] wfi ();
+ return 32'h10500073;
+ endfunction
+
+ function automatic logic [31:0] nop ();
+ return 32'h00000013;
+ endfunction
+
+ function automatic logic [31:0] illegal ();
+ return 32'h00000000;
+ endfunction
endpackage
diff --git a/src/dm_sba.sv b/src/dm_sba.sv
index f85aa75..fa9d401 100644
--- a/src/dm_sba.sv
+++ b/src/dm_sba.sv
@@ -1,173 +1,172 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
- * Copyright and related rights are licensed under the Solderpad Hardware
- * License, Version 0.51 (the “License”); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
- * or agreed to in writing, software, hardware and materials distributed under
- * this 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.
- *
- * File: dm_sba.sv
- * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
- * Date: 1.8.2018
- *
- * Description: System Bus Access Module
- *
- */
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File: dm_sba.sv
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+* Date: 1.8.2018
+*
+* Description: System Bus Access Module
+*
+*/
module dm_sba #(
- parameter int BusWidth = -1
+ parameter int BusWidth = -1
) (
- input logic clk_i, // Clock
- input logic rst_ni,
- input logic dmactive_i, // synchronous reset active low
-
- output logic master_req_o,
- output logic [BusWidth-1:0] master_add_o,
- output logic master_we_o,
- output logic [BusWidth-1:0] master_wdata_o,
- output logic [BusWidth/8-1:0] master_be_o,
- input logic master_gnt_i,
- input logic master_r_valid_i,
- input logic [BusWidth-1:0] master_r_rdata_i,
-
- input logic [BusWidth-1:0] sbaddress_i,
- input logic sbaddress_write_valid_i,
- // control signals in
- input logic sbreadonaddr_i,
- output logic [BusWidth-1:0] sbaddress_o,
- input logic sbautoincrement_i,
- input logic [2:0] sbaccess_i,
- // data in
- input logic sbreadondata_i,
- input logic [BusWidth-1:0] sbdata_i,
- input logic sbdata_read_valid_i,
- input logic sbdata_write_valid_i,
- // read data out
- output logic [BusWidth-1:0] sbdata_o,
- output logic sbdata_valid_o,
- // control signals
- output logic sbbusy_o,
- output logic sberror_valid_o, // bus error occurred
- output logic [2:0] sberror_o // bus error occurred
+ input logic clk_i, // Clock
+ input logic rst_ni,
+ input logic dmactive_i, // synchronous reset active low
+
+ output logic master_req_o,
+ output logic [BusWidth-1:0] master_add_o,
+ output logic master_we_o,
+ output logic [BusWidth-1:0] master_wdata_o,
+ output logic [BusWidth/8-1:0] master_be_o,
+ input logic master_gnt_i,
+ input logic master_r_valid_i,
+ input logic [BusWidth-1:0] master_r_rdata_i,
+
+ input logic [BusWidth-1:0] sbaddress_i,
+ input logic sbaddress_write_valid_i,
+ // control signals in
+ input logic sbreadonaddr_i,
+ output logic [BusWidth-1:0] sbaddress_o,
+ input logic sbautoincrement_i,
+ input logic [2:0] sbaccess_i,
+ // data in
+ input logic sbreadondata_i,
+ input logic [BusWidth-1:0] sbdata_i,
+ input logic sbdata_read_valid_i,
+ input logic sbdata_write_valid_i,
+ // read data out
+ output logic [BusWidth-1:0] sbdata_o,
+ output logic sbdata_valid_o,
+ // control signals
+ output logic sbbusy_o,
+ output logic sberror_valid_o, // bus error occurred
+ output logic [2:0] sberror_o // bus error occurred
);
- typedef enum logic [2:0] { Idle, Read, Write, WaitRead, WaitWrite } state_e;
- state_e state_d, state_q;
-
- logic [BusWidth-1:0] address;
- logic req;
- logic gnt;
- logic we;
- logic [BusWidth/8-1:0] be;
-
- assign sbbusy_o = (state_q != Idle) ? 1'b1 : 1'b0;
-
- always_comb begin
- req = 1'b0;
- address = sbaddress_i;
- we = 1'b0;
- be = '0;
-
- sberror_o = '0;
- sberror_valid_o = 1'b0;
- sbaddress_o = sbaddress_i;
-
- state_d = state_q;
-
- case (state_q)
- Idle: begin
- // debugger requested a read
- if (sbaddress_write_valid_i && sbreadonaddr_i) state_d = Read;
- // debugger requested a write
- if (sbdata_write_valid_i) state_d = Write;
- // perform another read
- if (sbdata_read_valid_i && sbreadondata_i) state_d = Read;
- end
-
- Read: begin
- req = 1'b1;
- if (gnt) state_d = WaitRead;
- end
-
- Write: begin
- req = 1'b1;
- we = 1'b1;
- // generate byte enable mask
- case (sbaccess_i)
- 3'b000: begin
- if (BusWidth == 64) be[ sbaddress_i[2:0]] = '1;
- else be[ sbaddress_i[1:0]] = '1;
- end
- 3'b001: begin
- if (BusWidth == 64) be[{sbaddress_i[2:1], 1'b0} +: 2] = '1;
- else be[{sbaddress_i[1:1], 1'b0} +: 2] = '1;
- end
- 3'b010: begin
- if (BusWidth == 64) be[{sbaddress_i[2:2], 2'b0} +: 4] = '1;
- else be = '1;
- end
- 3'b011: be = '1;
- default:;
- endcase
- if (gnt) state_d = WaitWrite;
- end
-
- WaitRead: begin
- if (sbdata_valid_o) begin
- state_d = Idle;
- // auto-increment address
- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1'b1 << sbaccess_i);
- end
- end
-
- WaitWrite: begin
- if (sbdata_valid_o) begin
- state_d = Idle;
- // auto-increment address
- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1'b1 << sbaccess_i);
- end
- end
-
- default:;
+ typedef enum logic [2:0] { Idle, Read, Write, WaitRead, WaitWrite } state_e;
+ state_e state_d, state_q;
+
+ logic [BusWidth-1:0] address;
+ logic req;
+ logic gnt;
+ logic we;
+ logic [BusWidth/8-1:0] be;
+
+ assign sbbusy_o = (state_q != Idle) ? 1'b1 : 1'b0;
+
+ always_comb begin
+ req = 1'b0;
+ address = sbaddress_i;
+ we = 1'b0;
+ be = '0;
+
+ sberror_o = '0;
+ sberror_valid_o = 1'b0;
+ sbaddress_o = sbaddress_i;
+
+ state_d = state_q;
+
+ case (state_q)
+ Idle: begin
+ // debugger requested a read
+ if (sbaddress_write_valid_i && sbreadonaddr_i) state_d = Read;
+ // debugger requested a write
+ if (sbdata_write_valid_i) state_d = Write;
+ // perform another read
+ if (sbdata_read_valid_i && sbreadondata_i) state_d = Read;
+ end
+
+ Read: begin
+ req = 1'b1;
+ if (gnt) state_d = WaitRead;
+ end
+
+ Write: begin
+ req = 1'b1;
+ we = 1'b1;
+ // generate byte enable mask
+ case (sbaccess_i)
+ 3'b000: begin
+ if (BusWidth == 64) be[ sbaddress_i[2:0]] = '1;
+ else be[ sbaddress_i[1:0]] = '1;
+ end
+ 3'b001: begin
+ if (BusWidth == 64) be[{sbaddress_i[2:1], 1'b0} +: 2] = '1;
+ else be[{sbaddress_i[1:1], 1'b0} +: 2] = '1;
+ end
+ 3'b010: begin
+ if (BusWidth == 64) be[{sbaddress_i[2:2], 2'b0} +: 4] = '1;
+ else be = '1;
+ end
+ 3'b011: be = '1;
+ default:;
endcase
-
- // handle error case
- if (sbaccess_i > 3 && state_q != Idle) begin
- req = 1'b0;
- state_d = Idle;
- sberror_valid_o = 1'b1;
- sberror_o = 3'd3;
+ if (gnt) state_d = WaitWrite;
+ end
+
+ WaitRead: begin
+ if (sbdata_valid_o) begin
+ state_d = Idle;
+ // auto-increment address
+ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1'b1 << sbaccess_i);
end
- // further error handling should go here ...
- end
+ end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- state_q <= Idle;
- end else begin
- state_q <= state_d;
+ WaitWrite: begin
+ if (sbdata_valid_o) begin
+ state_d = Idle;
+ // auto-increment address
+ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1'b1 << sbaccess_i);
end
- end
+ end
- assign master_req_o = req;
- assign master_add_o = address[BusWidth-1:0];
- assign master_we_o = we;
- assign master_wdata_o = sbdata_i[BusWidth-1:0];
- assign master_be_o = be[BusWidth/8-1:0];
- assign gnt = master_gnt_i;
- assign sbdata_valid_o = master_r_valid_i;
- assign sbdata_o = master_r_rdata_i[BusWidth-1:0];
-
-
- //pragma translate_off
- `ifndef VERILATOR
- // maybe bump severity to $error if not handled at runtime
- dm_sba_access_size: assert property(@(posedge clk_i) disable iff (dmactive_i !== 1'b0)
- (state_d != Idle) |-> (sbaccess_i < 4))
- else
- $warning ("accesses > 8 byte not supported at the moment");
- `endif
- //pragma translate_on
+ default:;
+ endcase
+
+ // handle error case
+ if (sbaccess_i > 3 && state_q != Idle) begin
+ req = 1'b0;
+ state_d = Idle;
+ sberror_valid_o = 1'b1;
+ sberror_o = 3'd3;
+ end
+ // further error handling should go here ...
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ state_q <= Idle;
+ end else begin
+ state_q <= state_d;
+ end
+ end
+
+ assign master_req_o = req;
+ assign master_add_o = address[BusWidth-1:0];
+ assign master_we_o = we;
+ assign master_wdata_o = sbdata_i[BusWidth-1:0];
+ assign master_be_o = be[BusWidth/8-1:0];
+ assign gnt = master_gnt_i;
+ assign sbdata_valid_o = master_r_valid_i;
+ assign sbdata_o = master_r_rdata_i[BusWidth-1:0];
+
+
+ //pragma translate_off
+ `ifndef VERILATOR
+ // maybe bump severity to $error if not handled at runtime
+ dm_sba_access_size: assert property(@(posedge clk_i) disable iff (dmactive_i !== 1'b0)
+ (state_d != Idle) |-> (sbaccess_i < 4))
+ else $warning ("accesses > 8 byte not supported at the moment");
+ `endif
+ //pragma translate_on
endmodule
diff --git a/src/dm_top.sv b/src/dm_top.sv
index ad20535..03ac112 100644
--- a/src/dm_top.sv
+++ b/src/dm_top.sv
@@ -1,222 +1,222 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
- * Copyright and related rights are licensed under the Solderpad Hardware
- * License, Version 0.51 (the “License”); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
- * or agreed to in writing, software, hardware and materials distributed under
- * this 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.
- *
- * File: dm_top.sv
- * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
- * Date: 30.6.2018
- *
- * Description: Top-level of debug module (DM). This is an AXI-Slave.
- * DTM protocol is equal to SiFives debug protocol to leverage
- * SW infrastructure re-use. As of version 0.13
- */
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File: dm_top.sv
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+* Date: 30.6.2018
+*
+* Description: Top-level of debug module (DM). This is an AXI-Slave.
+* DTM protocol is equal to SiFives debug protocol to leverage
+* SW infrastructure re-use. As of version 0.13
+*/
module dm_top #(
- parameter int NrHarts = 1,
- parameter int BusWidth = 32,
- parameter logic [NrHarts-1:0] SelectableHarts = 1 // Bitmask to select physically available harts for systems
- // that don't use hart numbers in a contiguous fashion.
+ parameter int NrHarts = 1,
+ parameter int BusWidth = 32,
+ parameter logic [NrHarts-1:0] SelectableHarts = 1 // Bitmask to select physically available harts for systems
+ // that don't use hart numbers in a contiguous fashion.
) (
- input logic clk_i, // clock
- input logic rst_ni, // asynchronous reset active low, connect PoR here, not the system reset
- input logic testmode_i,
- output logic ndmreset_o, // non-debug module reset
- output logic dmactive_o, // debug module is active
- output logic [NrHarts-1:0] debug_req_o, // async debug request
- input logic [NrHarts-1:0] unavailable_i, // communicate whether the hart is unavailable (e.g.: power down)
- dm::hartinfo_t [NrHarts-1:0] hartinfo_i,
-
- input logic slave_req_i,
- input logic slave_we_i,
- input logic [BusWidth-1:0] slave_addr_i,
- input logic [BusWidth/8-1:0] slave_be_i,
- input logic [BusWidth-1:0] slave_wdata_i,
- output logic [BusWidth-1:0] slave_rdata_o,
-
- output logic master_req_o,
- output logic [BusWidth-1:0] master_add_o,
- output logic master_we_o,
- output logic [BusWidth-1:0] master_wdata_o,
- output logic [BusWidth/8-1:0] master_be_o,
- input logic master_gnt_i,
- input logic master_r_valid_i,
- input logic [BusWidth-1:0] master_r_rdata_i,
-
- // Connection to DTM - compatible to RocketChip Debug Module
- input logic dmi_rst_ni,
- input logic dmi_req_valid_i,
- output logic dmi_req_ready_o,
- input dm::dmi_req_t dmi_req_i,
-
- output logic dmi_resp_valid_o,
- input logic dmi_resp_ready_i,
- output dm::dmi_resp_t dmi_resp_o
+ input logic clk_i, // clock
+ input logic rst_ni, // asynchronous reset active low, connect PoR here, not the system reset
+ input logic testmode_i,
+ output logic ndmreset_o, // non-debug module reset
+ output logic dmactive_o, // debug module is active
+ output logic [NrHarts-1:0] debug_req_o, // async debug request
+ input logic [NrHarts-1:0] unavailable_i, // communicate whether the hart is unavailable (e.g.: power down)
+ dm::hartinfo_t [NrHarts-1:0] hartinfo_i,
+
+ input logic slave_req_i,
+ input logic slave_we_i,
+ input logic [BusWidth-1:0] slave_addr_i,
+ input logic [BusWidth/8-1:0] slave_be_i,
+ input logic [BusWidth-1:0] slave_wdata_i,
+ output logic [BusWidth-1:0] slave_rdata_o,
+
+ output logic master_req_o,
+ output logic [BusWidth-1:0] master_add_o,
+ output logic master_we_o,
+ output logic [BusWidth-1:0] master_wdata_o,
+ output logic [BusWidth/8-1:0] master_be_o,
+ input logic master_gnt_i,
+ input logic master_r_valid_i,
+ input logic [BusWidth-1:0] master_r_rdata_i,
+
+ // Connection to DTM - compatible to RocketChip Debug Module
+ input logic dmi_rst_ni,
+ input logic dmi_req_valid_i,
+ output logic dmi_req_ready_o,
+ input dm::dmi_req_t dmi_req_i,
+
+ output logic dmi_resp_valid_o,
+ input logic dmi_resp_ready_i,
+ output dm::dmi_resp_t dmi_resp_o
);
- // Debug CSRs
- logic [NrHarts-1:0] halted;
- // logic [NrHarts-1:0] running;
- logic [NrHarts-1:0] resumeack;
- logic [NrHarts-1:0] haltreq;
- logic [NrHarts-1:0] resumereq;
- logic clear_resumeack;
- logic cmd_valid;
- dm::command_t cmd;
-
- logic cmderror_valid;
- dm::cmderr_e cmderror;
- logic cmdbusy;
- logic [dm::ProgBufSize-1:0][31:0] progbuf;
- logic [dm::DataCount-1:0][31:0] data_csrs_mem;
- logic [dm::DataCount-1:0][31:0] data_mem_csrs;
- logic data_valid;
- logic [19:0] hartsel;
- // System Bus Access Module
- logic [BusWidth-1:0] sbaddress_csrs_sba;
- logic [BusWidth-1:0] sbaddress_sba_csrs;
- logic sbaddress_write_valid;
- logic sbreadonaddr;
- logic sbautoincrement;
- logic [2:0] sbaccess;
- logic sbreadondata;
- logic [BusWidth-1:0] sbdata_write;
- logic sbdata_read_valid;
- logic sbdata_write_valid;
- logic [BusWidth-1:0] sbdata_read;
- logic sbdata_valid;
- logic sbbusy;
- logic sberror_valid;
- logic [2:0] sberror;
-
-
- dm_csrs #(
- .NrHarts(NrHarts),
- .BusWidth(BusWidth),
- .SelectableHarts(SelectableHarts)
- ) i_dm_csrs (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
- .testmode_i ( testmode_i ),
- .dmi_rst_ni,
- .dmi_req_valid_i,
- .dmi_req_ready_o,
- .dmi_req_i,
- .dmi_resp_valid_o,
- .dmi_resp_ready_i,
- .dmi_resp_o,
- .ndmreset_o ( ndmreset_o ),
- .dmactive_o ( dmactive_o ),
- .hartsel_o ( hartsel ),
- .hartinfo_i ( hartinfo_i ),
- .halted_i ( halted ),
- .unavailable_i,
- .resumeack_i ( resumeack ),
- .haltreq_o ( haltreq ),
- .resumereq_o ( resumereq ),
- .clear_resumeack_o ( clear_resumeack ),
- .cmd_valid_o ( cmd_valid ),
- .cmd_o ( cmd ),
- .cmderror_valid_i ( cmderror_valid ),
- .cmderror_i ( cmderror ),
- .cmdbusy_i ( cmdbusy ),
- .progbuf_o ( progbuf ),
- .data_i ( data_mem_csrs ),
- .data_valid_i ( data_valid ),
- .data_o ( data_csrs_mem ),
- .sbaddress_o ( sbaddress_csrs_sba ),
- .sbaddress_i ( sbaddress_sba_csrs ),
- .sbaddress_write_valid_o ( sbaddress_write_valid ),
- .sbreadonaddr_o ( sbreadonaddr ),
- .sbautoincrement_o ( sbautoincrement ),
- .sbaccess_o ( sbaccess ),
- .sbreadondata_o ( sbreadondata ),
- .sbdata_o ( sbdata_write ),
- .sbdata_read_valid_o ( sbdata_read_valid ),
- .sbdata_write_valid_o ( sbdata_write_valid ),
- .sbdata_i ( sbdata_read ),
- .sbdata_valid_i ( sbdata_valid ),
- .sbbusy_i ( sbbusy ),
- .sberror_valid_i ( sberror_valid ),
- .sberror_i ( sberror )
- );
-
- dm_sba #(
- .BusWidth(BusWidth)
- ) i_dm_sba (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
- .dmactive_i ( dmactive_o ),
-
- .master_req_o ( master_req_o ),
- .master_add_o ( master_add_o ),
- .master_we_o ( master_we_o ),
- .master_wdata_o ( master_wdata_o ),
- .master_be_o ( master_be_o ),
- .master_gnt_i ( master_gnt_i ),
- .master_r_valid_i ( master_r_valid_i ),
- .master_r_rdata_i ( master_r_rdata_i ),
-
- .sbaddress_i ( sbaddress_csrs_sba ),
- .sbaddress_o ( sbaddress_sba_csrs ),
- .sbaddress_write_valid_i ( sbaddress_write_valid ),
- .sbreadonaddr_i ( sbreadonaddr ),
- .sbautoincrement_i ( sbautoincrement ),
- .sbaccess_i ( sbaccess ),
- .sbreadondata_i ( sbreadondata ),
- .sbdata_i ( sbdata_write ),
- .sbdata_read_valid_i ( sbdata_read_valid ),
- .sbdata_write_valid_i ( sbdata_write_valid ),
- .sbdata_o ( sbdata_read ),
- .sbdata_valid_o ( sbdata_valid ),
- .sbbusy_o ( sbbusy ),
- .sberror_valid_o ( sberror_valid ),
- .sberror_o ( sberror )
- );
-
- dm_mem #(
- .NrHarts(NrHarts),
- .BusWidth(BusWidth),
- .SelectableHarts(SelectableHarts)
- ) i_dm_mem (
- .clk_i ( clk_i ),
- .rst_ni ( rst_ni ),
- .debug_req_o ( debug_req_o ),
- .hartsel_i ( hartsel ),
- .haltreq_i ( haltreq ),
- .resumereq_i ( resumereq ),
- .clear_resumeack_i ( clear_resumeack ),
- .halted_o ( halted ),
- .resuming_o ( resumeack ),
- .cmd_valid_i ( cmd_valid ),
- .cmd_i ( cmd ),
- .cmderror_valid_o ( cmderror_valid ),
- .cmderror_o ( cmderror ),
- .cmdbusy_o ( cmdbusy ),
- .progbuf_i ( progbuf ),
- .data_i ( data_csrs_mem ),
- .data_o ( data_mem_csrs ),
- .data_valid_o ( data_valid ),
- .req_i ( slave_req_i ),
- .we_i ( slave_we_i ),
- .addr_i ( slave_addr_i ),
- .wdata_i ( slave_wdata_i ),
- .be_i ( slave_be_i ),
- .rdata_o ( slave_rdata_o )
- );
+ // Debug CSRs
+ logic [NrHarts-1:0] halted;
+ // logic [NrHarts-1:0] running;
+ logic [NrHarts-1:0] resumeack;
+ logic [NrHarts-1:0] haltreq;
+ logic [NrHarts-1:0] resumereq;
+ logic clear_resumeack;
+ logic cmd_valid;
+ dm::command_t cmd;
+
+ logic cmderror_valid;
+ dm::cmderr_e cmderror;
+ logic cmdbusy;
+ logic [dm::ProgBufSize-1:0][31:0] progbuf;
+ logic [dm::DataCount-1:0][31:0] data_csrs_mem;
+ logic [dm::DataCount-1:0][31:0] data_mem_csrs;
+ logic data_valid;
+ logic [19:0] hartsel;
+ // System Bus Access Module
+ logic [BusWidth-1:0] sbaddress_csrs_sba;
+ logic [BusWidth-1:0] sbaddress_sba_csrs;
+ logic sbaddress_write_valid;
+ logic sbreadonaddr;
+ logic sbautoincrement;
+ logic [2:0] sbaccess;
+ logic sbreadondata;
+ logic [BusWidth-1:0] sbdata_write;
+ logic sbdata_read_valid;
+ logic sbdata_write_valid;
+ logic [BusWidth-1:0] sbdata_read;
+ logic sbdata_valid;
+ logic sbbusy;
+ logic sberror_valid;
+ logic [2:0] sberror;
+
+
+ dm_csrs #(
+ .NrHarts(NrHarts),
+ .BusWidth(BusWidth),
+ .SelectableHarts(SelectableHarts)
+ ) i_dm_csrs (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( testmode_i ),
+ .dmi_rst_ni,
+ .dmi_req_valid_i,
+ .dmi_req_ready_o,
+ .dmi_req_i,
+ .dmi_resp_valid_o,
+ .dmi_resp_ready_i,
+ .dmi_resp_o,
+ .ndmreset_o ( ndmreset_o ),
+ .dmactive_o ( dmactive_o ),
+ .hartsel_o ( hartsel ),
+ .hartinfo_i ( hartinfo_i ),
+ .halted_i ( halted ),
+ .unavailable_i,
+ .resumeack_i ( resumeack ),
+ .haltreq_o ( haltreq ),
+ .resumereq_o ( resumereq ),
+ .clear_resumeack_o ( clear_resumeack ),
+ .cmd_valid_o ( cmd_valid ),
+ .cmd_o ( cmd ),
+ .cmderror_valid_i ( cmderror_valid ),
+ .cmderror_i ( cmderror ),
+ .cmdbusy_i ( cmdbusy ),
+ .progbuf_o ( progbuf ),
+ .data_i ( data_mem_csrs ),
+ .data_valid_i ( data_valid ),
+ .data_o ( data_csrs_mem ),
+ .sbaddress_o ( sbaddress_csrs_sba ),
+ .sbaddress_i ( sbaddress_sba_csrs ),
+ .sbaddress_write_valid_o ( sbaddress_write_valid ),
+ .sbreadonaddr_o ( sbreadonaddr ),
+ .sbautoincrement_o ( sbautoincrement ),
+ .sbaccess_o ( sbaccess ),
+ .sbreadondata_o ( sbreadondata ),
+ .sbdata_o ( sbdata_write ),
+ .sbdata_read_valid_o ( sbdata_read_valid ),
+ .sbdata_write_valid_o ( sbdata_write_valid ),
+ .sbdata_i ( sbdata_read ),
+ .sbdata_valid_i ( sbdata_valid ),
+ .sbbusy_i ( sbbusy ),
+ .sberror_valid_i ( sberror_valid ),
+ .sberror_i ( sberror )
+ );
+
+ dm_sba #(
+ .BusWidth(BusWidth)
+ ) i_dm_sba (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .dmactive_i ( dmactive_o ),
+
+ .master_req_o ( master_req_o ),
+ .master_add_o ( master_add_o ),
+ .master_we_o ( master_we_o ),
+ .master_wdata_o ( master_wdata_o ),
+ .master_be_o ( master_be_o ),
+ .master_gnt_i ( master_gnt_i ),
+ .master_r_valid_i ( master_r_valid_i ),
+ .master_r_rdata_i ( master_r_rdata_i ),
+
+ .sbaddress_i ( sbaddress_csrs_sba ),
+ .sbaddress_o ( sbaddress_sba_csrs ),
+ .sbaddress_write_valid_i ( sbaddress_write_valid ),
+ .sbreadonaddr_i ( sbreadonaddr ),
+ .sbautoincrement_i ( sbautoincrement ),
+ .sbaccess_i ( sbaccess ),
+ .sbreadondata_i ( sbreadondata ),
+ .sbdata_i ( sbdata_write ),
+ .sbdata_read_valid_i ( sbdata_read_valid ),
+ .sbdata_write_valid_i ( sbdata_write_valid ),
+ .sbdata_o ( sbdata_read ),
+ .sbdata_valid_o ( sbdata_valid ),
+ .sbbusy_o ( sbbusy ),
+ .sberror_valid_o ( sberror_valid ),
+ .sberror_o ( sberror )
+ );
+
+ dm_mem #(
+ .NrHarts(NrHarts),
+ .BusWidth(BusWidth),
+ .SelectableHarts(SelectableHarts)
+ ) i_dm_mem (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .debug_req_o ( debug_req_o ),
+ .hartsel_i ( hartsel ),
+ .haltreq_i ( haltreq ),
+ .resumereq_i ( resumereq ),
+ .clear_resumeack_i ( clear_resumeack ),
+ .halted_o ( halted ),
+ .resuming_o ( resumeack ),
+ .cmd_valid_i ( cmd_valid ),
+ .cmd_i ( cmd ),
+ .cmderror_valid_o ( cmderror_valid ),
+ .cmderror_o ( cmderror ),
+ .cmdbusy_o ( cmdbusy ),
+ .progbuf_i ( progbuf ),
+ .data_i ( data_csrs_mem ),
+ .data_o ( data_mem_csrs ),
+ .data_valid_o ( data_valid ),
+ .req_i ( slave_req_i ),
+ .we_i ( slave_we_i ),
+ .addr_i ( slave_addr_i ),
+ .wdata_i ( slave_wdata_i ),
+ .be_i ( slave_be_i ),
+ .rdata_o ( slave_rdata_o )
+ );
`ifndef VERILATOR
- initial begin
- assert (BusWidth == 32 || BusWidth == 64)
- else $fatal(1, "DM needs a bus width of either 32 or 64 bits");
- end
+ initial begin
+ assert (BusWidth == 32 || BusWidth == 64)
+ else $fatal(1, "DM needs a bus width of either 32 or 64 bits");
+ end
`endif
endmodule
diff --git a/src/dmi_cdc.sv b/src/dmi_cdc.sv
index 98b15a8..ba856df 100644
--- a/src/dmi_cdc.sv
+++ b/src/dmi_cdc.sv
@@ -1,46 +1,46 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
- * Copyright and related rights are licensed under the Solderpad Hardware
- * License, Version 0.51 (the “License”); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
- * or agreed to in writing, software, hardware and materials distributed under
- * this 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.
- *
- * File: axi_riscv_debug_module.sv
- * Author: Andreas Traber <atraber@iis.ee.ethz.ch>
- * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
- *
- * Description: Clock domain crossings for JTAG to DMI very heavily based
- * on previous work by Andreas Traber for the PULP project.
- * This is mainly a wrapper around the existing CDCs.
- */
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File: axi_riscv_debug_module.sv
+* Author: Andreas Traber <atraber@iis.ee.ethz.ch>
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+*
+* Description: Clock domain crossings for JTAG to DMI very heavily based
+* on previous work by Andreas Traber for the PULP project.
+* This is mainly a wrapper around the existing CDCs.
+*/
module dmi_cdc (
- // JTAG side (master side)
- input logic tck_i,
- input logic trst_ni,
+ // JTAG side (master side)
+ input logic tck_i,
+ input logic trst_ni,
- input dm::dmi_req_t jtag_dmi_req_i,
- output logic jtag_dmi_ready_o,
- input logic jtag_dmi_valid_i,
+ input dm::dmi_req_t jtag_dmi_req_i,
+ output logic jtag_dmi_ready_o,
+ input logic jtag_dmi_valid_i,
- output dm::dmi_resp_t jtag_dmi_resp_o,
- output logic jtag_dmi_valid_o,
- input logic jtag_dmi_ready_i,
+ output dm::dmi_resp_t jtag_dmi_resp_o,
+ output logic jtag_dmi_valid_o,
+ input logic jtag_dmi_ready_i,
- // core side (slave side)
- input logic clk_i,
- input logic rst_ni,
+ // core side (slave side)
+ input logic clk_i,
+ input logic rst_ni,
- output dm::dmi_req_t core_dmi_req_o,
- output logic core_dmi_valid_o,
- input logic core_dmi_ready_i,
+ output dm::dmi_req_t core_dmi_req_o,
+ output logic core_dmi_valid_o,
+ input logic core_dmi_ready_i,
- input dm::dmi_resp_t core_dmi_resp_i,
- output logic core_dmi_ready_o,
- input logic core_dmi_valid_i
- );
+ input dm::dmi_resp_t core_dmi_resp_i,
+ output logic core_dmi_ready_o,
+ input logic core_dmi_valid_i
+);
cdc_2phase #(.T(dm::dmi_req_t)) i_cdc_req (
.src_rst_ni ( trst_ni ),
diff --git a/src/dmi_jtag.sv b/src/dmi_jtag.sv
index f177551..083ed59 100644
--- a/src/dmi_jtag.sv
+++ b/src/dmi_jtag.sv
@@ -1,262 +1,262 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
- * Copyright and related rights are licensed under the Solderpad Hardware
- * License, Version 0.51 (the “License”); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
- * or agreed to in writing, software, hardware and materials distributed under
- * this 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.
- *
- * File: axi_riscv_debug_module.sv
- * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
- * Date: 19.7.2018
- *
- * Description: JTAG DMI (debug module interface)
- *
- */
+* Copyright and related rights are licensed under the Solderpad Hardware
+* License, Version 0.51 (the “License”); you may not use this file except in
+* compliance with the License. You may obtain a copy of the License at
+* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+* or agreed to in writing, software, hardware and materials distributed under
+* this 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.
+*
+* File: axi_riscv_debug_module.sv
+* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+* Date: 19.7.2018
+*
+* Description: JTAG DMI (debug module interface)
+*
+*/
module dmi_jtag #(
- parameter logic [31:0] IdcodeValue = 32'h00000001
+ parameter logic [31:0] IdcodeValue = 32'h00000001
) (
- input logic clk_i, // DMI Clock
- input logic rst_ni, // Asynchronous reset active low
- input logic testmode_i,
-
- output logic dmi_rst_no, // hard reset
- output dm::dmi_req_t dmi_req_o,
- output logic dmi_req_valid_o,
- input logic dmi_req_ready_i,
-
- input dm::dmi_resp_t dmi_resp_i,
- output logic dmi_resp_ready_o,
- input logic dmi_resp_valid_i,
-
- input logic tck_i, // JTAG test clock pad
- input logic tms_i, // JTAG test mode select pad
- input logic trst_ni, // JTAG test reset pad
- input logic td_i, // JTAG test data input pad
- output logic td_o, // JTAG test data output pad
- output logic tdo_oe_o // Data out output enable
+ input logic clk_i, // DMI Clock
+ input logic rst_ni, // Asynchronous reset active low
+ input logic testmode_i,
+
+ output logic dmi_rst_no, // hard reset
+ output dm::dmi_req_t dmi_req_o,
+ output logic dmi_req_valid_o,
+ input logic dmi_req_ready_i,
+
+ input dm::dmi_resp_t dmi_resp_i,
+ output logic dmi_resp_ready_o,
+ input logic dmi_resp_valid_i,
+
+ input logic tck_i, // JTAG test clock pad
+ input logic tms_i, // JTAG test mode select pad
+ input logic trst_ni, // JTAG test reset pad
+ input logic td_i, // JTAG test data input pad
+ output logic td_o, // JTAG test data output pad
+ output logic tdo_oe_o // Data out output enable
);
- assign dmi_rst_no = rst_ni;
-
- logic test_logic_reset;
- logic shift_dr;
- logic update_dr;
- logic capture_dr;
- logic dmi_access;
- logic dtmcs_select;
- logic dmi_reset;
- logic dmi_tdi;
- logic dmi_tdo;
-
- dm::dmi_req_t dmi_req;
- logic dmi_req_ready;
- logic dmi_req_valid;
-
- dm::dmi_resp_t dmi_resp;
- logic dmi_resp_valid;
- logic dmi_resp_ready;
-
- typedef struct packed {
- logic [6:0] address;
- logic [31:0] data;
- logic [1:0] op;
- } dmi_t;
-
- typedef enum logic [1:0] {
- DMINoError = 2'h0, DMIReservedError = 2'h1,
- DMIOPFailed = 2'h2, DMIBusy = 2'h3
- } dmi_error_e;
-
- typedef enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_e;
- state_e state_d, state_q;
-
- logic [$bits(dmi_t)-1:0] dr_d, dr_q;
- logic [6:0] address_d, address_q;
- logic [31:0] data_d, data_q;
-
- dmi_t dmi;
- assign dmi = dmi_t'(dr_q);
- assign dmi_req.addr = address_q;
- assign dmi_req.data = data_q;
- assign dmi_req.op = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ;
- // we'will always be ready to accept the data we requested
- assign dmi_resp_ready = 1'b1;
-
- logic error_dmi_busy;
- dmi_error_e error_d, error_q;
-
- always_comb begin
- error_dmi_busy = 1'b0;
- // default assignments
- state_d = state_q;
- address_d = address_q;
- data_d = data_q;
- error_d = error_q;
-
- dmi_req_valid = 1'b0;
-
- case (state_q)
- Idle: begin
- // make sure that no error is sticky
- if (dmi_access && update_dr && (error_q == DMINoError)) begin
- // save address and value
- address_d = dmi.address;
- data_d = dmi.data;
- if (dm::dtm_op_e'(dmi.op) == dm::DTM_READ) begin
- state_d = Read;
- end else if (dm::dtm_op_e'(dmi.op) == dm::DTM_WRITE) begin
- state_d = Write;
- end
- // else this is a nop and we can stay here
- end
- end
-
- Read: begin
- dmi_req_valid = 1'b1;
- if (dmi_req_ready) begin
- state_d = WaitReadValid;
- end
- end
-
- WaitReadValid: begin
- // load data into register and shift out
- if (dmi_resp_valid) begin
- data_d = dmi_resp.data;
- state_d = Idle;
- end
- end
-
- Write: begin
- dmi_req_valid = 1'b1;
- // got a valid answer go back to idle
- if (dmi_req_ready) begin
- state_d = Idle;
- end
- end
-
- default: begin
- // just wait for idle here
- if (dmi_resp_valid) begin
- state_d = Idle;
- end
- end
- endcase
-
- // update_dr means we got another request but we didn't finish
- // the one in progress, this state is sticky
- if (update_dr && state_q != Idle) begin
- error_dmi_busy = 1'b1;
+ assign dmi_rst_no = rst_ni;
+
+ logic test_logic_reset;
+ logic shift_dr;
+ logic update_dr;
+ logic capture_dr;
+ logic dmi_access;
+ logic dtmcs_select;
+ logic dmi_reset;
+ logic dmi_tdi;
+ logic dmi_tdo;
+
+ dm::dmi_req_t dmi_req;
+ logic dmi_req_ready;
+ logic dmi_req_valid;
+
+ dm::dmi_resp_t dmi_resp;
+ logic dmi_resp_valid;
+ logic dmi_resp_ready;
+
+ typedef struct packed {
+ logic [6:0] address;
+ logic [31:0] data;
+ logic [1:0] op;
+ } dmi_t;
+
+ typedef enum logic [1:0] {
+ DMINoError = 2'h0, DMIReservedError = 2'h1,
+ DMIOPFailed = 2'h2, DMIBusy = 2'h3
+ } dmi_error_e;
+
+ typedef enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_e;
+ state_e state_d, state_q;
+
+ logic [$bits(dmi_t)-1:0] dr_d, dr_q;
+ logic [6:0] address_d, address_q;
+ logic [31:0] data_d, data_q;
+
+ dmi_t dmi;
+ assign dmi = dmi_t'(dr_q);
+ assign dmi_req.addr = address_q;
+ assign dmi_req.data = data_q;
+ assign dmi_req.op = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ;
+ // we'will always be ready to accept the data we requested
+ assign dmi_resp_ready = 1'b1;
+
+ logic error_dmi_busy;
+ dmi_error_e error_d, error_q;
+
+ always_comb begin
+ error_dmi_busy = 1'b0;
+ // default assignments
+ state_d = state_q;
+ address_d = address_q;
+ data_d = data_q;
+ error_d = error_q;
+
+ dmi_req_valid = 1'b0;
+
+ case (state_q)
+ Idle: begin
+ // make sure that no error is sticky
+ if (dmi_access && update_dr && (error_q == DMINoError)) begin
+ // save address and value
+ address_d = dmi.address;
+ data_d = dmi.data;
+ if (dm::dtm_op_e'(dmi.op) == dm::DTM_READ) begin
+ state_d = Read;
+ end else if (dm::dtm_op_e'(dmi.op) == dm::DTM_WRITE) begin
+ state_d = Write;
+ end
+ // else this is a nop and we can stay here
end
+ end
- // if capture_dr goes high while we are in the read state
- // or in the corresponding wait state we are not giving back a valid word
- // -> throw an error
- if (capture_dr && state_q inside {Read, WaitReadValid}) begin
- error_dmi_busy = 1'b1;
+ Read: begin
+ dmi_req_valid = 1'b1;
+ if (dmi_req_ready) begin
+ state_d = WaitReadValid;
end
+ end
- if (error_dmi_busy) begin
- error_d = DMIBusy;
+ WaitReadValid: begin
+ // load data into register and shift out
+ if (dmi_resp_valid) begin
+ data_d = dmi_resp.data;
+ state_d = Idle;
end
- // clear sticky error flag
- if (dmi_reset && dtmcs_select) begin
- error_d = DMINoError;
- end
- end
+ end
- // shift register
- assign dmi_tdo = dr_q[0];
-
- always_comb begin
- dr_d = dr_q;
-
- if (capture_dr) begin
- if (dmi_access) begin
- if (error_q == DMINoError && !error_dmi_busy) begin
- dr_d = {address_q, data_q, DMINoError};
- // DMI was busy, report an error
- end else if (error_q == DMIBusy || error_dmi_busy) begin
- dr_d = {address_q, data_q, DMIBusy};
- end
- end
+ Write: begin
+ dmi_req_valid = 1'b1;
+ // got a valid answer go back to idle
+ if (dmi_req_ready) begin
+ state_d = Idle;
end
+ end
- if (shift_dr) begin
- if (dmi_access) dr_d = {dmi_tdi, dr_q[$bits(dr_q)-1:1]};
+ default: begin
+ // just wait for idle here
+ if (dmi_resp_valid) begin
+ state_d = Idle;
end
+ end
+ endcase
- if (test_logic_reset) begin
- dr_d = '0;
- end
+ // update_dr means we got another request but we didn't finish
+ // the one in progress, this state is sticky
+ if (update_dr && state_q != Idle) begin
+ error_dmi_busy = 1'b1;
+ end
+
+ // if capture_dr goes high while we are in the read state
+ // or in the corresponding wait state we are not giving back a valid word
+ // -> throw an error
+ if (capture_dr && state_q inside {Read, WaitReadValid}) begin
+ error_dmi_busy = 1'b1;
+ end
+
+ if (error_dmi_busy) begin
+ error_d = DMIBusy;
end
+ // clear sticky error flag
+ if (dmi_reset && dtmcs_select) begin
+ error_d = DMINoError;
+ end
+ end
+
+ // shift register
+ assign dmi_tdo = dr_q[0];
- always_ff @(posedge tck_i or negedge trst_ni) begin
- if (!trst_ni) begin
- dr_q <= '0;
- state_q <= Idle;
- address_q <= '0;
- data_q <= '0;
- error_q <= DMINoError;
- end else begin
- dr_q <= dr_d;
- state_q <= state_d;
- address_q <= address_d;
- data_q <= data_d;
- error_q <= error_d;
+ always_comb begin
+ dr_d = dr_q;
+
+ if (capture_dr) begin
+ if (dmi_access) begin
+ if (error_q == DMINoError && !error_dmi_busy) begin
+ dr_d = {address_q, data_q, DMINoError};
+ // DMI was busy, report an error
+ end else if (error_q == DMIBusy || error_dmi_busy) begin
+ dr_d = {address_q, data_q, DMIBusy};
end
+ end
end
- // ---------
- // TAP
- // ---------
- dmi_jtag_tap #(
- .IrLength (5),
- .IdcodeValue(IdcodeValue)
- ) i_dmi_jtag_tap (
- .tck_i,
- .tms_i,
- .trst_ni,
- .td_i,
- .td_o,
- .tdo_oe_o,
- .testmode_i ( testmode_i ),
- .test_logic_reset_o ( test_logic_reset ),
- .shift_dr_o ( shift_dr ),
- .update_dr_o ( update_dr ),
- .capture_dr_o ( capture_dr ),
- .dmi_access_o ( dmi_access ),
- .dtmcs_select_o ( dtmcs_select ),
- .dmi_reset_o ( dmi_reset ),
- .dmi_error_i ( error_q ),
- .dmi_tdi_o ( dmi_tdi ),
- .dmi_tdo_i ( dmi_tdo )
- );
-
- // ---------
- // CDC
- // ---------
- dmi_cdc i_dmi_cdc (
- // JTAG side (master side)
- .tck_i,
- .trst_ni,
- .jtag_dmi_req_i ( dmi_req ),
- .jtag_dmi_ready_o ( dmi_req_ready ),
- .jtag_dmi_valid_i ( dmi_req_valid ),
- .jtag_dmi_resp_o ( dmi_resp ),
- .jtag_dmi_valid_o ( dmi_resp_valid ),
- .jtag_dmi_ready_i ( dmi_resp_ready ),
- // core side
- .clk_i,
- .rst_ni,
- .core_dmi_req_o ( dmi_req_o ),
- .core_dmi_valid_o ( dmi_req_valid_o ),
- .core_dmi_ready_i ( dmi_req_ready_i ),
- .core_dmi_resp_i ( dmi_resp_i ),
- .core_dmi_ready_o ( dmi_resp_ready_o ),
- .core_dmi_valid_i ( dmi_resp_valid_i )
- );
+ if (shift_dr) begin
+ if (dmi_access) dr_d = {dmi_tdi, dr_q[$bits(dr_q)-1:1]};
+ end
+
+ if (test_logic_reset) begin
+ dr_d = '0;
+ end
+ end
+
+ always_ff @(posedge tck_i or negedge trst_ni) begin
+ if (!trst_ni) begin
+ dr_q <= '0;
+ state_q <= Idle;
+ address_q <= '0;
+ data_q <= '0;
+ error_q <= DMINoError;
+ end else begin
+ dr_q <= dr_d;
+ state_q <= state_d;
+ address_q <= address_d;
+ data_q <= data_d;
+ error_q <= error_d;
+ end
+ end
+
+ // ---------
+ // TAP
+ // ---------
+ dmi_jtag_tap #(
+ .IrLength (5),
+ .IdcodeValue(IdcodeValue)
+ ) i_dmi_jtag_tap (
+ .tck_i,
+ .tms_i,
+ .trst_ni,
+ .td_i,
+ .td_o,
+ .tdo_oe_o,
+ .testmode_i ( testmode_i ),
+ .test_logic_reset_o ( test_logic_reset ),
+ .shift_dr_o ( shift_dr ),
+ .update_dr_o ( update_dr ),
+ .capture_dr_o ( capture_dr ),
+ .dmi_access_o ( dmi_access ),
+ .dtmcs_select_o ( dtmcs_select ),
+ .dmi_reset_o ( dmi_reset ),
+ .dmi_error_i ( error_q ),
+ .dmi_tdi_o ( dmi_tdi ),
+ .dmi_tdo_i ( dmi_tdo )
+ );
+
+ // ---------
+ // CDC
+ // ---------
+ dmi_cdc i_dmi_cdc (
+ // JTAG side (master side)
+ .tck_i,
+ .trst_ni,
+ .jtag_dmi_req_i ( dmi_req ),
+ .jtag_dmi_ready_o ( dmi_req_ready ),
+ .jtag_dmi_valid_i ( dmi_req_valid ),
+ .jtag_dmi_resp_o ( dmi_resp ),
+ .jtag_dmi_valid_o ( dmi_resp_valid ),
+ .jtag_dmi_ready_i ( dmi_resp_ready ),
+ // core side
+ .clk_i,
+ .rst_ni,
+ .core_dmi_req_o ( dmi_req_o ),
+ .core_dmi_valid_o ( dmi_req_valid_o ),
+ .core_dmi_ready_i ( dmi_req_ready_i ),
+ .core_dmi_resp_i ( dmi_resp_i ),
+ .core_dmi_ready_o ( dmi_resp_ready_o ),
+ .core_dmi_valid_i ( dmi_resp_valid_i )
+ );
endmodule
diff --git a/src/dmi_jtag_tap.sv b/src/dmi_jtag_tap.sv
index cab01ca..19d876f 100644
--- a/src/dmi_jtag_tap.sv
+++ b/src/dmi_jtag_tap.sv
@@ -17,327 +17,328 @@
*/
module dmi_jtag_tap #(
- parameter int IrLength = 5,
- // JTAG IDCODE Value
- parameter logic [31:0] IdcodeValue = 32'h00000001
- // xxxx version
- // xxxxxxxxxxxxxxxx part number
- // xxxxxxxxxxx manufacturer id
- // 1 required by standard
-)(
- input logic tck_i, // JTAG test clock pad
- input logic tms_i, // JTAG test mode select pad
- input logic trst_ni, // JTAG test reset pad
- input logic td_i, // JTAG test data input pad
- output logic td_o, // JTAG test data output pad
- output logic tdo_oe_o, // Data out output enable
- input logic testmode_i,
- output logic test_logic_reset_o,
- output logic shift_dr_o,
- output logic update_dr_o,
- output logic capture_dr_o,
-
- // we want to access DMI register
- output logic dmi_access_o,
- // JTAG is interested in writing the DTM CSR register
- output logic dtmcs_select_o,
- // clear error state
- output logic dmi_reset_o,
- input logic [1:0] dmi_error_i,
- // test data to submodule
- output logic dmi_tdi_o,
- // test data in from submodule
- input logic dmi_tdo_i
-
+ parameter int IrLength = 5,
+ // JTAG IDCODE Value
+ parameter logic [31:0] IdcodeValue = 32'h00000001
+ // xxxx version
+ // xxxxxxxxxxxxxxxx part number
+ // xxxxxxxxxxx manufacturer id
+ // 1 required by standard
+) (
+ input logic tck_i, // JTAG test clock pad
+ input logic tms_i, // JTAG test mode select pad
+ input logic trst_ni, // JTAG test reset pad
+ input logic td_i, // JTAG test data input pad
+ output logic td_o, // JTAG test data output pad
+ output logic tdo_oe_o, // Data out output enable
+ input logic testmode_i,
+ output logic test_logic_reset_o,
+ output logic shift_dr_o,
+ output logic update_dr_o,
+ output logic capture_dr_o,
+
+ // we want to access DMI register
+ output logic dmi_access_o,
+ // JTAG is interested in writing the DTM CSR register
+ output logic dtmcs_select_o,
+ // clear error state
+ output logic dmi_reset_o,
+ input logic [1:0] dmi_error_i,
+ // test data to submodule
+ output logic dmi_tdi_o,
+ // test data in from submodule
+ input logic dmi_tdo_i
);
- // to submodule
- assign dmi_tdi_o = td_i;
-
- typedef enum logic [3:0] { TestLogicReset, RunTestIdle, SelectDrScan,
- CaptureDr, ShiftDr, Exit1Dr, PauseDr, Exit2Dr,
- UpdateDr, SelectIrScan, CaptureIr, ShiftIr,
- Exit1Ir, PauseIr, Exit2Ir, UpdateIr } tap_state_e;
- tap_state_e tap_state_q, tap_state_d;
-
- typedef enum logic [IrLength-1:0] {
- BYPASS0 = 'h0,
- IDCODE = 'h1,
- DTMCSR = 'h10,
- DMIACCESS = 'h11,
- BYPASS1 = 'h1f
- } ir_reg_e;
-
- typedef struct packed {
- logic [31:18] zero1;
- logic dmihardreset;
- logic dmireset;
- logic zero0;
- logic [14:12] idle;
- logic [11:10] dmistat;
- logic [9:4] abits;
- logic [3:0] version;
- } dtmcs_t;
-
- // ----------------
- // IR logic
- // ----------------
- logic [IrLength-1:0] jtag_ir_shift_d, jtag_ir_shift_q; // shift register
- ir_reg_e jtag_ir_d, jtag_ir_q; // IR register -> this gets captured from shift register upon update_ir
- logic capture_ir, shift_ir, pause_ir, update_ir;
-
- always_comb begin
- jtag_ir_shift_d = jtag_ir_shift_q;
- jtag_ir_d = jtag_ir_q;
-
- // IR shift register
- if (shift_ir) begin
- jtag_ir_shift_d = {td_i, jtag_ir_shift_q[IrLength-1:1]};
- end
-
- // capture IR register
- if (capture_ir) begin
- jtag_ir_shift_d = 'b0101;
- end
-
- // update IR register
- if (update_ir) begin
- jtag_ir_d = ir_reg_e'(jtag_ir_shift_q);
- end
-
- // synchronous test-logic reset
- if (test_logic_reset_o) begin
- jtag_ir_shift_d = '0;
- jtag_ir_d = IDCODE;
- end
+ // to submodule
+ assign dmi_tdi_o = td_i;
+
+ typedef enum logic [3:0] {
+ TestLogicReset, RunTestIdle, SelectDrScan,
+ CaptureDr, ShiftDr, Exit1Dr, PauseDr, Exit2Dr,
+ UpdateDr, SelectIrScan, CaptureIr, ShiftIr,
+ Exit1Ir, PauseIr, Exit2Ir, UpdateIr
+ } tap_state_e;
+
+ tap_state_e tap_state_q, tap_state_d;
+
+ typedef enum logic [IrLength-1:0] {
+ BYPASS0 = 'h0,
+ IDCODE = 'h1,
+ DTMCSR = 'h10,
+ DMIACCESS = 'h11,
+ BYPASS1 = 'h1f
+ } ir_reg_e;
+
+ typedef struct packed {
+ logic [31:18] zero1;
+ logic dmihardreset;
+ logic dmireset;
+ logic zero0;
+ logic [14:12] idle;
+ logic [11:10] dmistat;
+ logic [9:4] abits;
+ logic [3:0] version;
+ } dtmcs_t;
+
+ // ----------------
+ // IR logic
+ // ----------------
+ logic [IrLength-1:0] jtag_ir_shift_d, jtag_ir_shift_q; // shift register
+ ir_reg_e jtag_ir_d, jtag_ir_q; // IR register -> this gets captured from shift register upon update_ir
+ logic capture_ir, shift_ir, pause_ir, update_ir;
+
+ always_comb begin
+ jtag_ir_shift_d = jtag_ir_shift_q;
+ jtag_ir_d = jtag_ir_q;
+
+ // IR shift register
+ if (shift_ir) begin
+ jtag_ir_shift_d = {td_i, jtag_ir_shift_q[IrLength-1:1]};
end
- always_ff @(posedge tck_i, negedge trst_ni) begin
- if (!trst_ni) begin
- jtag_ir_shift_q <= '0;
- jtag_ir_q <= IDCODE;
- end else begin
- jtag_ir_shift_q <= jtag_ir_shift_d;
- jtag_ir_q <= jtag_ir_d;
- end
+ // capture IR register
+ if (capture_ir) begin
+ jtag_ir_shift_d = 'b0101;
end
- // ----------------
- // TAP DR Regs
- // ----------------
- // - Bypass
- // - IDCODE
- // - DTM CS
- logic [31:0] idcode_d, idcode_q;
- logic idcode_select;
- logic bypass_select;
- dtmcs_t dtmcs_d, dtmcs_q;
- logic bypass_d, bypass_q; // this is a 1-bit register
-
- assign dmi_reset_o = dtmcs_q.dmireset;
-
- always_comb begin
- idcode_d = idcode_q;
- bypass_d = bypass_q;
- dtmcs_d = dtmcs_q;
-
- if (capture_dr_o) begin
- if (idcode_select) idcode_d = IdcodeValue;
- if (bypass_select) bypass_d = 1'b0;
- if (dtmcs_select_o) begin
- dtmcs_d = '{
- zero1 : '0,
- dmihardreset : 1'b0,
- dmireset : 1'b0,
- zero0 : '0,
- idle : 'd1, // 1: Enter Run-Test/Idle and leave it immediately
- dmistat : dmi_error_i, // 0: No error, 1: Op failed, 2: too fast
- abits : 'd7, // The size of address in dmi
- version : 'd1 // Version described in spec version 0.13 (and later?)
- };
- end
- end
-
- if (shift_dr_o) begin
- if (idcode_select) idcode_d = {td_i, idcode_q[31:1]};
- if (bypass_select) bypass_d = td_i;
- if (dtmcs_select_o) dtmcs_d = {td_i, dtmcs_q[31:1]};
- end
-
- if (test_logic_reset_o) begin
- idcode_d = IdcodeValue;
- bypass_d = 1'b0;
- end
+ // update IR register
+ if (update_ir) begin
+ jtag_ir_d = ir_reg_e'(jtag_ir_shift_q);
end
- // ----------------
- // Data reg select
- // ----------------
- always_comb begin
- dmi_access_o = 1'b0;
- dtmcs_select_o = 1'b0;
- idcode_select = 1'b0;
- bypass_select = 1'b0;
- case (jtag_ir_q)
- BYPASS0: bypass_select = 1'b1;
- IDCODE: idcode_select = 1'b1;
- DTMCSR: dtmcs_select_o = 1'b1;
- DMIACCESS: dmi_access_o = 1'b1;
- BYPASS1: bypass_select = 1'b1;
- default: bypass_select = 1'b1;
- endcase
+ // synchronous test-logic reset
+ if (test_logic_reset_o) begin
+ jtag_ir_shift_d = '0;
+ jtag_ir_d = IDCODE;
+ end
+ end
+
+ always_ff @(posedge tck_i, negedge trst_ni) begin
+ if (!trst_ni) begin
+ jtag_ir_shift_q <= '0;
+ jtag_ir_q <= IDCODE;
+ end else begin
+ jtag_ir_shift_q <= jtag_ir_shift_d;
+ jtag_ir_q <= jtag_ir_d;
+ end
+ end
+
+ // ----------------
+ // TAP DR Regs
+ // ----------------
+ // - Bypass
+ // - IDCODE
+ // - DTM CS
+ logic [31:0] idcode_d, idcode_q;
+ logic idcode_select;
+ logic bypass_select;
+ dtmcs_t dtmcs_d, dtmcs_q;
+ logic bypass_d, bypass_q; // this is a 1-bit register
+
+ assign dmi_reset_o = dtmcs_q.dmireset;
+
+ always_comb begin
+ idcode_d = idcode_q;
+ bypass_d = bypass_q;
+ dtmcs_d = dtmcs_q;
+
+ if (capture_dr_o) begin
+ if (idcode_select) idcode_d = IdcodeValue;
+ if (bypass_select) bypass_d = 1'b0;
+ if (dtmcs_select_o) begin
+ dtmcs_d = '{
+ zero1 : '0,
+ dmihardreset : 1'b0,
+ dmireset : 1'b0,
+ zero0 : '0,
+ idle : 'd1, // 1: Enter Run-Test/Idle and leave it immediately
+ dmistat : dmi_error_i, // 0: No error, 1: Op failed, 2: too fast
+ abits : 'd7, // The size of address in dmi
+ version : 'd1 // Version described in spec version 0.13 (and later?)
+ };
+ end
end
- // ----------------
- // Output select
- // ----------------
- logic tdo_mux;
-
- always_comb begin
- // we are shifting out the IR register
- if (shift_ir) begin
- tdo_mux = jtag_ir_shift_q[0];
- // here we are shifting the DR register
- end else begin
- case (jtag_ir_q) // synthesis parallel_case
- IDCODE: tdo_mux = idcode_q[0]; // Reading ID code
- DTMCSR: tdo_mux = dtmcs_q[0];
- DMIACCESS: tdo_mux = dmi_tdo_i; // Read from DMI TDO
- default: tdo_mux = bypass_q; // BYPASS instruction
- endcase
- end
-
+ if (shift_dr_o) begin
+ if (idcode_select) idcode_d = {td_i, idcode_q[31:1]};
+ if (bypass_select) bypass_d = td_i;
+ if (dtmcs_select_o) dtmcs_d = {td_i, dtmcs_q[31:1]};
end
- // DFT
- logic tck_n, tck_ni;
-
- cluster_clock_inverter i_tck_inv (
- .clk_i ( tck_i ),
- .clk_o ( tck_ni )
- );
-
- pulp_clock_mux2 i_dft_tck_mux (
- .clk0_i ( tck_ni ),
- .clk1_i ( tck_i ), // bypass the inverted clock for testing
- .clk_sel_i ( testmode_i ),
- .clk_o ( tck_n )
- );
-
- // TDO changes state at negative edge of TCK
- always_ff @(posedge tck_n, negedge trst_ni) begin
- if (!trst_ni) begin
- td_o <= 1'b0;
- tdo_oe_o <= 1'b0;
- end else begin
- td_o <= tdo_mux;
- tdo_oe_o <= (shift_ir | shift_dr_o);
- end
+ if (test_logic_reset_o) begin
+ idcode_d = IdcodeValue;
+ bypass_d = 1'b0;
end
- // ----------------
- // TAP FSM
- // ----------------
- // Determination of next state; purely combinatorial
- always_comb begin
- test_logic_reset_o = 1'b0;
-
- capture_dr_o = 1'b0;
- shift_dr_o = 1'b0;
- update_dr_o = 1'b0;
-
- capture_ir = 1'b0;
- shift_ir = 1'b0;
- pause_ir = 1'b0;
- update_ir = 1'b0;
-
- case (tap_state_q)
- TestLogicReset: begin
- tap_state_d = (tms_i) ? TestLogicReset : RunTestIdle;
- test_logic_reset_o = 1'b1;
- end
- RunTestIdle: begin
- tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
- end
- // DR Path
- SelectDrScan: begin
- tap_state_d = (tms_i) ? SelectIrScan : CaptureDr;
- end
- CaptureDr: begin
- capture_dr_o = 1'b1;
- tap_state_d = (tms_i) ? Exit1Dr : ShiftDr;
- end
- ShiftDr: begin
- shift_dr_o = 1'b1;
- tap_state_d = (tms_i) ? Exit1Dr : ShiftDr;
- end
- Exit1Dr: begin
- tap_state_d = (tms_i) ? UpdateDr : PauseDr;
- end
- PauseDr: begin
- tap_state_d = (tms_i) ? Exit2Dr : PauseDr;
- end
- Exit2Dr: begin
- tap_state_d = (tms_i) ? UpdateDr : ShiftDr;
- end
- UpdateDr: begin
- update_dr_o = 1'b1;
- tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
- end
- // IR Path
- SelectIrScan: begin
- tap_state_d = (tms_i) ? TestLogicReset : CaptureIr;
- end
- // In this controller state, the shift register bank in the
- // Instruction Register parallel loads a pattern of fixed values on
- // the rising edge of TCK. The last two significant bits must always
- // be "01".
- CaptureIr: begin
- capture_ir = 1'b1;
- tap_state_d = (tms_i) ? Exit1Ir : ShiftIr;
- end
- // In this controller state, the instruction register gets connected
- // between TDI and TDO, and the captured pattern gets shifted on
- // each rising edge of TCK. The instruction available on the TDI
- // pin is also shifted in to the instruction register.
- ShiftIr: begin
- shift_ir = 1'b1;
- tap_state_d = (tms_i) ? Exit1Ir : ShiftIr;
- end
- Exit1Ir: begin
- tap_state_d = (tms_i) ? UpdateIr : PauseIr;
- end
- PauseIr: begin
- pause_ir = 1'b1;
- tap_state_d = (tms_i) ? Exit2Ir : PauseIr;
- end
- Exit2Ir: begin
- tap_state_d = (tms_i) ? UpdateIr : ShiftIr;
- end
- // In this controller state, the instruction in the instruction
- // shift register is latched to the latch bank of the Instruction
- // Register on every falling edge of TCK. This instruction becomes
- // the current instruction once it is latched.
- UpdateIr: begin
- update_ir = 1'b1;
- tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
- end
- default: tap_state_d = TestLogicReset; // can't actually happen
+ end
+
+ // ----------------
+ // Data reg select
+ // ----------------
+ always_comb begin
+ dmi_access_o = 1'b0;
+ dtmcs_select_o = 1'b0;
+ idcode_select = 1'b0;
+ bypass_select = 1'b0;
+ case (jtag_ir_q)
+ BYPASS0: bypass_select = 1'b1;
+ IDCODE: idcode_select = 1'b1;
+ DTMCSR: dtmcs_select_o = 1'b1;
+ DMIACCESS: dmi_access_o = 1'b1;
+ BYPASS1: bypass_select = 1'b1;
+ default: bypass_select = 1'b1;
+ endcase
+ end
+
+ // ----------------
+ // Output select
+ // ----------------
+ logic tdo_mux;
+
+ always_comb begin
+ // we are shifting out the IR register
+ if (shift_ir) begin
+ tdo_mux = jtag_ir_shift_q[0];
+ // here we are shifting the DR register
+ end else begin
+ case (jtag_ir_q) // synthesis parallel_case
+ IDCODE: tdo_mux = idcode_q[0]; // Reading ID code
+ DTMCSR: tdo_mux = dtmcs_q[0];
+ DMIACCESS: tdo_mux = dmi_tdo_i; // Read from DMI TDO
+ default: tdo_mux = bypass_q; // BYPASS instruction
endcase
end
-
- always_ff @(posedge tck_i or negedge trst_ni) begin
- if (!trst_ni) begin
- tap_state_q <= RunTestIdle;
- idcode_q <= IdcodeValue;
- bypass_q <= 1'b0;
- dtmcs_q <= '0;
- end else begin
- tap_state_q <= tap_state_d;
- idcode_q <= idcode_d;
- bypass_q <= bypass_d;
- dtmcs_q <= dtmcs_d;
- end
+ end
+
+ // DFT
+ logic tck_n, tck_ni;
+
+ cluster_clock_inverter i_tck_inv (
+ .clk_i ( tck_i ),
+ .clk_o ( tck_ni )
+ );
+
+ pulp_clock_mux2 i_dft_tck_mux (
+ .clk0_i ( tck_ni ),
+ .clk1_i ( tck_i ), // bypass the inverted clock for testing
+ .clk_sel_i ( testmode_i ),
+ .clk_o ( tck_n )
+ );
+
+ // TDO changes state at negative edge of TCK
+ always_ff @(posedge tck_n, negedge trst_ni) begin
+ if (!trst_ni) begin
+ td_o <= 1'b0;
+ tdo_oe_o <= 1'b0;
+ end else begin
+ td_o <= tdo_mux;
+ tdo_oe_o <= (shift_ir | shift_dr_o);
end
-
+ end
+ // ----------------
+ // TAP FSM
+ // ----------------
+ // Determination of next state; purely combinatorial
+ always_comb begin
+ test_logic_reset_o = 1'b0;
+
+ capture_dr_o = 1'b0;
+ shift_dr_o = 1'b0;
+ update_dr_o = 1'b0;
+
+ capture_ir = 1'b0;
+ shift_ir = 1'b0;
+ pause_ir = 1'b0;
+ update_ir = 1'b0;
+
+ case (tap_state_q)
+ TestLogicReset: begin
+ tap_state_d = (tms_i) ? TestLogicReset : RunTestIdle;
+ test_logic_reset_o = 1'b1;
+ end
+ RunTestIdle: begin
+ tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
+ end
+ // DR Path
+ SelectDrScan: begin
+ tap_state_d = (tms_i) ? SelectIrScan : CaptureDr;
+ end
+ CaptureDr: begin
+ capture_dr_o = 1'b1;
+ tap_state_d = (tms_i) ? Exit1Dr : ShiftDr;
+ end
+ ShiftDr: begin
+ shift_dr_o = 1'b1;
+ tap_state_d = (tms_i) ? Exit1Dr : ShiftDr;
+ end
+ Exit1Dr: begin
+ tap_state_d = (tms_i) ? UpdateDr : PauseDr;
+ end
+ PauseDr: begin
+ tap_state_d = (tms_i) ? Exit2Dr : PauseDr;
+ end
+ Exit2Dr: begin
+ tap_state_d = (tms_i) ? UpdateDr : ShiftDr;
+ end
+ UpdateDr: begin
+ update_dr_o = 1'b1;
+ tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
+ end
+ // IR Path
+ SelectIrScan: begin
+ tap_state_d = (tms_i) ? TestLogicReset : CaptureIr;
+ end
+ // In this controller state, the shift register bank in the
+ // Instruction Register parallel loads a pattern of fixed values on
+ // the rising edge of TCK. The last two significant bits must always
+ // be "01".
+ CaptureIr: begin
+ capture_ir = 1'b1;
+ tap_state_d = (tms_i) ? Exit1Ir : ShiftIr;
+ end
+ // In this controller state, the instruction register gets connected
+ // between TDI and TDO, and the captured pattern gets shifted on
+ // each rising edge of TCK. The instruction available on the TDI
+ // pin is also shifted in to the instruction register.
+ ShiftIr: begin
+ shift_ir = 1'b1;
+ tap_state_d = (tms_i) ? Exit1Ir : ShiftIr;
+ end
+ Exit1Ir: begin
+ tap_state_d = (tms_i) ? UpdateIr : PauseIr;
+ end
+ PauseIr: begin
+ pause_ir = 1'b1;
+ tap_state_d = (tms_i) ? Exit2Ir : PauseIr;
+ end
+ Exit2Ir: begin
+ tap_state_d = (tms_i) ? UpdateIr : ShiftIr;
+ end
+ // In this controller state, the instruction in the instruction
+ // shift register is latched to the latch bank of the Instruction
+ // Register on every falling edge of TCK. This instruction becomes
+ // the current instruction once it is latched.
+ UpdateIr: begin
+ update_ir = 1'b1;
+ tap_state_d = (tms_i) ? SelectDrScan : RunTestIdle;
+ end
+ default: tap_state_d = TestLogicReset; // can't actually happen
+ endcase
+ end
+
+
+ always_ff @(posedge tck_i or negedge trst_ni) begin
+ if (!trst_ni) begin
+ tap_state_q <= RunTestIdle;
+ idcode_q <= IdcodeValue;
+ bypass_q <= 1'b0;
+ dtmcs_q <= '0;
+ end else begin
+ tap_state_q <= tap_state_d;
+ idcode_q <= idcode_d;
+ bypass_q <= bypass_d;
+ dtmcs_q <= dtmcs_d;
+ end
+ end
endmodule
--
2.24.0.rc0.303.g954a862665-goog