blob: edb621e7dd3e346f4d3cd97541d9abea69c06576 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Syntacore LLC © 2016-2021
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Syntacore LLC
// //////////////////////////////////////////////////////////////////////////
/// @file <scr1_dmi.sv>
/// @brief Debug Module Interface (DMI)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Provides TAPC with access to Debug Module (DM) and DTMCS
//
// Structure:
// - DMI <-> TAP interface
// - DMI <-> DM interface
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_dm.svh"
module scr1_dmi (
// System
input logic rst_n, // DMI unit reset
input logic clk, // DMI unit clock
// TAP interface
input logic tapcsync2dmi_ch_sel_i, // Debug Transport Module Chain Select
input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2dmi_ch_id_i, // Debug Transport Module Chain ID
input logic tapcsync2dmi_ch_capture_i, // Debug Transport Module Chain Capture
input logic tapcsync2dmi_ch_shift_i, // Debug Transport Module Chain Shift
input logic tapcsync2dmi_ch_update_i, // Debug Transport Module Chain Update
input logic tapcsync2dmi_ch_tdi_i, // Debug Transport Module Chain TDI
output logic dmi2tapcsync_ch_tdo_o, // Debug Transport Module Chain TDO
// DM interface
input logic dm2dmi_resp_i, // DMI response
input logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm2dmi_rdata_i, // DMI read data
output logic dmi2dm_req_o, // DMI request
output logic dmi2dm_wr_o, // DMI write
output logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi2dm_addr_o, // DMI address
output logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi2dm_wdata_o // DMI write data
);
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
// Debug Transport Module Status parameters
//------------------------------------------------------------------------------
localparam DTMCS_RESERVEDB_HI = 5'd31;
localparam DTMCS_RESERVEDB_LO = 5'd18;
localparam DTMCS_DMIHARDRESET = 5'd17;
localparam DTMCS_DMIRESET = 5'd16;
localparam DTMCS_RESERVEDA = 5'd15;
localparam DTMCS_IDLE_HI = 5'd14;
localparam DTMCS_IDLE_LO = 5'd12;
localparam DTMCS_DMISTAT_HI = 5'd11;
localparam DTMCS_DMISTAT_LO = 5'd10;
localparam DTMCS_ABITS_HI = 5'd9;
localparam DTMCS_ABITS_LO = 5'd4;
localparam DTMCS_VERSION_HI = 5'd3;
localparam DTMCS_VERSION_LO = 5'd0;
// Debug Module Interface parameters
//------------------------------------------------------------------------------
localparam DMI_OP_LO = 5'd0;
localparam DMI_OP_HI = DMI_OP_LO + SCR1_DBG_DMI_OP_WIDTH - 1;
localparam DMI_DATA_LO = DMI_OP_HI + 1;
localparam DMI_DATA_HI = DMI_DATA_LO + SCR1_DBG_DMI_DATA_WIDTH - 1;
localparam DMI_ADDR_LO = DMI_DATA_HI + 1;
localparam DMI_ADDR_HI = DMI_ADDR_LO + SCR1_DBG_DMI_ADDR_WIDTH - 1;
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// TAP data register
logic tap_dr_upd;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_ff;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_shift;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_rdata;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_next;
// DM read data register
logic dm_rdata_upd;
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm_rdata_ff;
logic tapc_dmi_access_req;
logic tapc_dtmcs_sel;
//------------------------------------------------------------------------------
// DMI <-> TAP interface
//------------------------------------------------------------------------------
// TAPC read data multiplexer
//------------------------------------------------------------------------------
assign tapc_dtmcs_sel = (tapcsync2dmi_ch_id_i == 1'd1);
// DMI operation is always successful in the current implementation
always_comb begin
tap_dr_rdata = '0;
if(tapc_dtmcs_sel) begin
tap_dr_rdata[DTMCS_RESERVEDB_HI:DTMCS_RESERVEDB_LO] = 'b0;
tap_dr_rdata[DTMCS_DMIHARDRESET] = 'b0;
tap_dr_rdata[DTMCS_DMIRESET] = 'b0;
tap_dr_rdata[DTMCS_RESERVEDA] = 'b0;
tap_dr_rdata[DTMCS_IDLE_HI:DTMCS_IDLE_LO] = 'b0;
tap_dr_rdata[DTMCS_DMISTAT_HI:DTMCS_DMISTAT_LO] = 'b0;
tap_dr_rdata[DTMCS_ABITS_HI :DTMCS_ABITS_LO] = SCR1_DBG_DMI_ADDR_WIDTH;
tap_dr_rdata[DTMCS_VERSION_LO] = 1'b1;
end else begin
tap_dr_rdata[DMI_ADDR_HI:DMI_ADDR_LO] = 'b0;
tap_dr_rdata[DMI_DATA_HI:DMI_DATA_LO] = dm_rdata_ff;
tap_dr_rdata[DMI_OP_HI :DMI_OP_LO] = 'b0;
end
end
assign tap_dr_shift = tapc_dtmcs_sel
? {9'b0, tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DTMCS_WIDTH-1:1]}
: {tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:1]};
// TAP data register
//------------------------------------------------------------------------------
assign tap_dr_upd = tapcsync2dmi_ch_capture_i | tapcsync2dmi_ch_shift_i;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
tap_dr_ff <= '0;
end else if(tap_dr_upd) begin
tap_dr_ff <= tap_dr_next;
end
end
assign tap_dr_next = tapcsync2dmi_ch_capture_i ? tap_dr_rdata
: tapcsync2dmi_ch_shift_i ? tap_dr_shift
: tap_dr_ff;
assign dmi2tapcsync_ch_tdo_o = tap_dr_ff[0];
//------------------------------------------------------------------------------
// DMI <-> DM interface
//------------------------------------------------------------------------------
assign tapc_dmi_access_req = tapcsync2dmi_ch_update_i & tapcsync2dmi_ch_sel_i
& (tapcsync2dmi_ch_id_i == 2'd2);
always_comb begin
dmi2dm_req_o = 1'b0;
dmi2dm_wr_o = 1'b0;
dmi2dm_addr_o = 1'b0;
dmi2dm_wdata_o = 1'b0;
if(tapc_dmi_access_req) begin
dmi2dm_req_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] != 2'b00;
dmi2dm_wr_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] == 2'b10;
dmi2dm_addr_o = tap_dr_ff[DMI_ADDR_HI:DMI_ADDR_LO];
dmi2dm_wdata_o = tap_dr_ff[DMI_DATA_HI:DMI_DATA_LO];
end
end
// DM read data register
//------------------------------------------------------------------------------
assign dm_rdata_upd = dmi2dm_req_o & dm2dmi_resp_i & ~dmi2dm_wr_o;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
dm_rdata_ff <= '0;
end else if (dm_rdata_upd) begin
dm_rdata_ff <= dm2dmi_rdata_i;
end
end
endmodule : scr1_dmi
`endif // SCR1_DBG_EN