hw/vendor/pulp_riscv_dbg/src/dmi_jtag.sv Cov: 100%

   1: /* Copyright 2018 ETH Zurich and University of Bologna.
   2: * Copyright and related rights are licensed under the Solderpad Hardware
   3: * License, Version 0.51 (the “License”); you may not use this file except in
   4: * compliance with the License.  You may obtain a copy of the License at
   5: * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
   6: * or agreed to in writing, software, hardware and materials distributed under
   7: * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
   8: * CONDITIONS OF ANY KIND, either express or implied. See the License for the
   9: * specific language governing permissions and limitations under the License.
  10: *
  11: * File:   axi_riscv_debug_module.sv
  12: * Author: Florian Zaruba 
  13: * Date:   19.7.2018
  14: *
  15: * Description: JTAG DMI (debug module interface)
  16: *
  17: */
  18: 
  19: module dmi_jtag #(
  20:   parameter logic [31:0] IdcodeValue = 32'h00000001
  21: ) (
  22:   input  logic         clk_i,      // DMI Clock
  23:   input  logic         rst_ni,     // Asynchronous reset active low
  24:   input  logic         testmode_i,
  25: 
  26:   output logic         dmi_rst_no, // hard reset
  27:   output dm::dmi_req_t dmi_req_o,
  28:   output logic         dmi_req_valid_o,
  29:   input  logic         dmi_req_ready_i,
  30: 
  31:   input dm::dmi_resp_t dmi_resp_i,
  32:   output logic         dmi_resp_ready_o,
  33:   input  logic         dmi_resp_valid_i,
  34: 
  35:   input  logic         tck_i,    // JTAG test clock pad
  36:   input  logic         tms_i,    // JTAG test mode select pad
  37:   input  logic         trst_ni,  // JTAG test reset pad
  38:   input  logic         td_i,     // JTAG test data input pad
  39:   output logic         td_o,     // JTAG test data output pad
  40:   output logic         tdo_oe_o  // Data out output enable
  41: );
  42:   assign       dmi_rst_no = rst_ni;
  43: 
  44:   logic        test_logic_reset;
  45:   logic        shift_dr;
  46:   logic        update_dr;
  47:   logic        capture_dr;
  48:   logic        dmi_access;
  49:   logic        dtmcs_select;
  50:   logic        dmi_reset;
  51:   logic        dmi_tdi;
  52:   logic        dmi_tdo;
  53: 
  54:   dm::dmi_req_t  dmi_req;
  55:   logic          dmi_req_ready;
  56:   logic          dmi_req_valid;
  57: 
  58:   dm::dmi_resp_t dmi_resp;
  59:   logic          dmi_resp_valid;
  60:   logic          dmi_resp_ready;
  61: 
  62:   typedef struct packed {
  63:     logic [6:0]  address;
  64:     logic [31:0] data;
  65:     logic [1:0]  op;
  66:   } dmi_t;
  67: 
  68:   typedef enum logic [1:0] {
  69:     DMINoError = 2'h0, DMIReservedError = 2'h1,
  70:     DMIOPFailed = 2'h2, DMIBusy = 2'h3
  71:   } dmi_error_e;
  72: 
  73:   typedef enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_e;
  74:   state_e state_d, state_q;
  75: 
  76:   logic [$bits(dmi_t)-1:0] dr_d, dr_q;
  77:   logic [6:0] address_d, address_q;
  78:   logic [31:0] data_d, data_q;
  79: 
  80:   dmi_t  dmi;
  81:   assign dmi          = dmi_t'(dr_q);
  82:   assign dmi_req.addr = address_q;
  83:   assign dmi_req.data = data_q;
  84:   assign dmi_req.op   = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ;
  85:   // we'will always be ready to accept the data we requested
  86:   assign dmi_resp_ready = 1'b1;
  87: 
  88:   logic error_dmi_busy;
  89:   dmi_error_e error_d, error_q;
  90: 
  91:   always_comb begin : p_fsm
  92:     error_dmi_busy = 1'b0;
  93:     // default assignments
  94:     state_d   = state_q;
  95:     address_d = address_q;
  96:     data_d    = data_q;
  97:     error_d   = error_q;
  98: 
  99:     dmi_req_valid = 1'b0;
 100: 
 101:     unique case (state_q)
 102:       Idle: begin
 103:         // make sure that no error is sticky
 104:         if (dmi_access && update_dr && (error_q == DMINoError)) begin
 105:           // save address and value
 106:           address_d = dmi.address;
 107:           data_d = dmi.data;
 108:           if (dm::dtm_op_e'(dmi.op) == dm::DTM_READ) begin
 109:             state_d = Read;
 110:           end else if (dm::dtm_op_e'(dmi.op) == dm::DTM_WRITE) begin
 111:             state_d = Write;
 112:           end
 113:           // else this is a nop and we can stay here
 114:         end
 115:       end
 116: 
 117:       Read: begin
 118:         dmi_req_valid = 1'b1;
 119:         if (dmi_req_ready) begin
 120:           state_d = WaitReadValid;
 121:         end
 122:       end
 123: 
 124:       WaitReadValid: begin
 125:         // load data into register and shift out
 126:         if (dmi_resp_valid) begin
 127:           data_d = dmi_resp.data;
 128:           state_d = Idle;
 129:         end
 130:       end
 131: 
 132:       Write: begin
 133:         dmi_req_valid = 1'b1;
 134:         // got a valid answer go back to idle
 135:         if (dmi_req_ready) begin
 136:           state_d = Idle;
 137:         end
 138:       end
 139: 
 140:       default: begin
 141:         // just wait for idle here
 142:         if (dmi_resp_valid) begin
 143:           state_d = Idle;
 144:         end
 145:       end
 146:     endcase
 147: 
 148:     // update_dr means we got another request but we didn't finish
 149:     // the one in progress, this state is sticky
 150:     if (update_dr && state_q != Idle) begin
 151:       error_dmi_busy = 1'b1;
 152:     end
 153: 
 154:     // if capture_dr goes high while we are in the read state
 155:     // or in the corresponding wait state we are not giving back a valid word
 156:     // -> throw an error
 157:     if (capture_dr && state_q inside {Read, WaitReadValid}) begin
 158:       error_dmi_busy = 1'b1;
 159:     end
 160: 
 161:     if (error_dmi_busy) begin
 162:       error_d = DMIBusy;
 163:     end
 164:     // clear sticky error flag
 165:     if (dmi_reset && dtmcs_select) begin
 166:       error_d = DMINoError;
 167:     end
 168:   end
 169: 
 170:   // shift register
 171:   assign dmi_tdo = dr_q[0];
 172: 
 173:   always_comb begin : p_shift
 174:     dr_d    = dr_q;
 175: 
 176:     if (capture_dr) begin
 177:       if (dmi_access) begin
 178:         if (error_q == DMINoError && !error_dmi_busy) begin
 179:           dr_d = {address_q, data_q, DMINoError};
 180:         // DMI was busy, report an error
 181:         end else if (error_q == DMIBusy || error_dmi_busy) begin
 182:           dr_d = {address_q, data_q, DMIBusy};
 183:         end
 184:       end
 185:     end
 186: 
 187:     if (shift_dr) begin
 188:       if (dmi_access) begin
 189:         dr_d = {dmi_tdi, dr_q[$bits(dr_q)-1:1]};
 190:       end
 191:     end
 192: 
 193:     if (test_logic_reset) begin
 194:       dr_d = '0;
 195:     end
 196:   end
 197: 
 198:   always_ff @(posedge tck_i or negedge trst_ni) begin : p_regs
 199:     if (!trst_ni) begin
 200:       dr_q      <= '0;
 201:       state_q   <= Idle;
 202:       address_q <= '0;
 203:       data_q    <= '0;
 204:       error_q   <= DMINoError;
 205:     end else begin
 206:       dr_q      <= dr_d;
 207:       state_q   <= state_d;
 208:       address_q <= address_d;
 209:       data_q    <= data_d;
 210:       error_q   <= error_d;
 211:     end
 212:   end
 213: 
 214:   // ---------
 215:   // TAP
 216:   // ---------
 217:   dmi_jtag_tap #(
 218:     .IrLength (5),
 219:     .IdcodeValue(IdcodeValue)
 220:   ) i_dmi_jtag_tap (
 221:     .tck_i,
 222:     .tms_i,
 223:     .trst_ni,
 224:     .td_i,
 225:     .td_o,
 226:     .tdo_oe_o,
 227:     .testmode_i,
 228:     .test_logic_reset_o ( test_logic_reset ),
 229:     .shift_dr_o         ( shift_dr         ),
 230:     .update_dr_o        ( update_dr        ),
 231:     .capture_dr_o       ( capture_dr       ),
 232:     .dmi_access_o       ( dmi_access       ),
 233:     .dtmcs_select_o     ( dtmcs_select     ),
 234:     .dmi_reset_o        ( dmi_reset        ),
 235:     .dmi_error_i        ( error_q          ),
 236:     .dmi_tdi_o          ( dmi_tdi          ),
 237:     .dmi_tdo_i          ( dmi_tdo          )
 238:   );
 239: 
 240:   // ---------
 241:   // CDC
 242:   // ---------
 243:   dmi_cdc i_dmi_cdc (
 244:     // JTAG side (master side)
 245:     .tck_i,
 246:     .trst_ni,
 247:     .jtag_dmi_req_i    ( dmi_req          ),
 248:     .jtag_dmi_ready_o  ( dmi_req_ready    ),
 249:     .jtag_dmi_valid_i  ( dmi_req_valid    ),
 250:     .jtag_dmi_resp_o   ( dmi_resp         ),
 251:     .jtag_dmi_valid_o  ( dmi_resp_valid   ),
 252:     .jtag_dmi_ready_i  ( dmi_resp_ready   ),
 253:     // core side
 254:     .clk_i,
 255:     .rst_ni,
 256:     .core_dmi_req_o    ( dmi_req_o        ),
 257:     .core_dmi_valid_o  ( dmi_req_valid_o  ),
 258:     .core_dmi_ready_i  ( dmi_req_ready_i  ),
 259:     .core_dmi_resp_i   ( dmi_resp_i       ),
 260:     .core_dmi_ready_o  ( dmi_resp_ready_o ),
 261:     .core_dmi_valid_i  ( dmi_resp_valid_i )
 262:   );
 263: 
 264: endmodule : dmi_jtag
 265: