Folder rename
This commit is contained in:
605
src_ref/core/pipeline/scr1_ipic.sv
Normal file
605
src_ref/core/pipeline/scr1_ipic.sv
Normal file
@@ -0,0 +1,605 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_ipic.sv>
|
||||
/// @brief Integrated Programmable Interrupt Controller (IPIC)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Synchronizes IRQ lines (optional)
|
||||
// - Detects level and edge (with optional lines inversion) of IRQ lines
|
||||
// - Setups interrupts handling (mode, inversion, enable)
|
||||
// - Provides information about pending interrupts and interrupts currently in
|
||||
// service
|
||||
// - Generates interrupt request to CSR
|
||||
//
|
||||
// Structure:
|
||||
// - IRQ lines handling (synchronization, level and edge detection) logic
|
||||
// - IPIC registers:
|
||||
// - CISV
|
||||
// - CICSR
|
||||
// - EOI
|
||||
// - SOI
|
||||
// - IDX
|
||||
// - IPR
|
||||
// - ISVR
|
||||
// - IER
|
||||
// - IMR
|
||||
// - IINVR
|
||||
// - ICSR
|
||||
// - Priority interrupt generation logic
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_IPIC_EN
|
||||
|
||||
`include "scr1_ipic.svh"
|
||||
|
||||
module scr1_ipic
|
||||
(
|
||||
// Common
|
||||
input logic rst_n, // IPIC reset
|
||||
input logic clk, // IPIC clock
|
||||
|
||||
// External Interrupt lines
|
||||
input logic [SCR1_IRQ_LINES_NUM-1:0] soc2ipic_irq_lines_i, // External IRQ lines
|
||||
|
||||
// CSR <-> IPIC interface
|
||||
input logic csr2ipic_r_req_i, // IPIC read request
|
||||
input logic csr2ipic_w_req_i, // IPIC write request
|
||||
input logic [2:0] csr2ipic_addr_i, // IPIC address
|
||||
input logic [`SCR1_XLEN-1:0] csr2ipic_wdata_i, // IPIC write data
|
||||
output logic [`SCR1_XLEN-1:0] ipic2csr_rdata_o, // IPIC read data
|
||||
output logic ipic2csr_irq_m_req_o // IRQ request from IPIC
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
logic vd;
|
||||
logic idx;
|
||||
} type_scr1_search_one_2_s;
|
||||
|
||||
typedef struct {
|
||||
logic vd;
|
||||
logic [SCR1_IRQ_IDX_WIDTH-1:0] idx;
|
||||
} type_scr1_search_one_16_s;
|
||||
|
||||
typedef struct packed {
|
||||
logic ip;
|
||||
logic ie;
|
||||
logic im;
|
||||
logic inv;
|
||||
logic isv;
|
||||
logic [SCR1_IRQ_LINES_WIDTH-1:0] line;
|
||||
} type_scr1_icsr_m_s;
|
||||
|
||||
typedef struct packed {
|
||||
logic ip;
|
||||
logic ie;
|
||||
} type_scr1_cicsr_s;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local functions declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
function automatic type_scr1_search_one_2_s scr1_search_one_2(
|
||||
input logic [1:0] din
|
||||
);
|
||||
type_scr1_search_one_2_s tmp;
|
||||
begin
|
||||
tmp.vd = |din;
|
||||
tmp.idx = ~din[0];
|
||||
return tmp;
|
||||
end
|
||||
endfunction : scr1_search_one_2
|
||||
|
||||
function automatic type_scr1_search_one_16_s scr1_search_one_16(
|
||||
input logic [15:0] din
|
||||
);
|
||||
begin
|
||||
logic [7:0] stage1_vd;
|
||||
logic [3:0] stage2_vd;
|
||||
logic [1:0] stage3_vd;
|
||||
|
||||
logic stage1_idx [7:0];
|
||||
logic [1:0] stage2_idx [3:0];
|
||||
logic [2:0] stage3_idx [1:0];
|
||||
type_scr1_search_one_16_s result;
|
||||
|
||||
// Stage 1
|
||||
for (int unsigned i=0; i<8; ++i) begin
|
||||
type_scr1_search_one_2_s tmp;
|
||||
tmp = scr1_search_one_2(din[(i+1)*2-1-:2]);
|
||||
stage1_vd[i] = tmp.vd;
|
||||
stage1_idx[i] = tmp.idx;
|
||||
end
|
||||
|
||||
// Stage 2
|
||||
for (int unsigned i=0; i<4; ++i) begin
|
||||
type_scr1_search_one_2_s tmp;
|
||||
tmp = scr1_search_one_2(stage1_vd[(i+1)*2-1-:2]);
|
||||
stage2_vd[i] = tmp.vd;
|
||||
stage2_idx[i] = (~tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]};
|
||||
end
|
||||
|
||||
// Stage 3
|
||||
for (int unsigned i=0; i<2; ++i) begin
|
||||
type_scr1_search_one_2_s tmp;
|
||||
tmp = scr1_search_one_2(stage2_vd[(i+1)*2-1-:2]);
|
||||
stage3_vd[i] = tmp.vd;
|
||||
stage3_idx[i] = (~tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]};
|
||||
end
|
||||
|
||||
// Stage 4
|
||||
result.vd = |stage3_vd;
|
||||
result.idx = (stage3_vd[0]) ? {1'b0, stage3_idx[0]} : {1'b1, stage3_idx[1]};
|
||||
|
||||
return result;
|
||||
end
|
||||
endfunction : scr1_search_one_16
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// IRQ lines handling signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines; // Internal IRQ lines
|
||||
`ifdef SCR1_IPIC_SYNC_EN
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_sync;
|
||||
`endif // SCR1_IPIC_SYNC_EN
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_dly; // Internal IRQ lines delayed for 1 cycle
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_edge_detected; // IRQ lines edge detected flags
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lvl; // IRQ lines level
|
||||
|
||||
// IPIC registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// CISV register
|
||||
logic ipic_cisv_upd; // Current Interrupt Vecotr in Service register update
|
||||
logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_ff; // Current Interrupt Vector in Service register
|
||||
logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_next; // Current Interrupt Vector in Service register next value
|
||||
|
||||
// CICS register (CICSR)
|
||||
logic cicsr_wr_req; // Write request to Current Interrupt Control Status register
|
||||
type_scr1_cicsr_s ipic_cicsr; // Current Interrupt Control Status register
|
||||
|
||||
// EOI register
|
||||
logic eoi_wr_req; // Write request to End of Interrupt register
|
||||
logic ipic_eoi_req; // Request to end the interrupt that is currently in service
|
||||
|
||||
// SOI register
|
||||
logic soi_wr_req; // Write request to Start of Interrupt register
|
||||
logic ipic_soi_req; // Request to start the interrupt
|
||||
|
||||
// IDX register (IDXR)
|
||||
logic idxr_wr_req; // Write request to Index register
|
||||
logic [SCR1_IRQ_IDX_WIDTH-1:0] ipic_idxr_ff; // Index register
|
||||
|
||||
// IP register (IPR)
|
||||
logic ipic_ipr_upd; // Interrupt pending register update
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_ff; // Interrupt pending register
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_next; // Interrupt pending register next value
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_cond; // Interrupt pending clear condition
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_req; // Interrupt pending clear request
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr; // Interrupt pending clear operation
|
||||
|
||||
// ISV register (ISVR)
|
||||
logic ipic_isvr_upd; // Interrupt Serviced register update
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_ff; // Interrupt Serviced register
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_next; // Interrupt Serviced register next value
|
||||
|
||||
// IE register (IER)
|
||||
logic ipic_ier_upd; // Interrupt enable register update
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_ff; // Interrupt enable register
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_next; // Interrupt enable register next value
|
||||
|
||||
// IM register (IMR)
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_ff; // Interrupt mode register
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_next; // Interrupt mode register next value
|
||||
|
||||
// IINV register (IINVR)
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_ff; // Interrupt Inversion register
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_next; // Interrupt Inversion register next value
|
||||
|
||||
// ICS register (ICSR)
|
||||
logic icsr_wr_req; // Write request to Interrupt Control Status register
|
||||
type_scr1_icsr_m_s ipic_icsr; // Interrupt Control Status register
|
||||
|
||||
// Priority interrupt generation signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Serviced interrupt signals
|
||||
logic irq_serv_vd; // There is an interrupt in service
|
||||
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_serv_idx; // Index of an interrupt that is currently in service
|
||||
|
||||
// Requested interrupt signals
|
||||
logic irq_req_vd; // There is a requested interrupt
|
||||
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_req_idx; // Index of a requested interrupt
|
||||
|
||||
// Interrupt requested on "end of the previous interrupt" signals
|
||||
logic irq_eoi_req_vd; // There is a requested interrupt when the previous one has ended
|
||||
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_eoi_req_idx; // Index of an interrupt requested when the previous one has ended
|
||||
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] irq_req_v; // Vector of interrupts that are pending and enabled
|
||||
|
||||
logic irq_start_vd; // Request to start an interrupt is valid
|
||||
logic irq_hi_prior_pnd; // There is a pending IRQ with a priority higher than of the interrupt that is currently in service
|
||||
|
||||
type_scr1_search_one_16_s irr_priority; // Structure for vd and idx of the requested interrupt
|
||||
type_scr1_search_one_16_s isvr_priority_eoi; // Structure for vd and idx of the interrupt requested when the previous interrupt has ended
|
||||
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_eoi; // Interrupt Serviced register when the previous interrupt has ended
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IRQ lines handling
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`ifdef SCR1_IPIC_SYNC_EN
|
||||
// IRQ lines synchronization
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
irq_lines_sync <= '0;
|
||||
irq_lines <= '0;
|
||||
end else begin
|
||||
irq_lines_sync <= soc2ipic_irq_lines_i;
|
||||
irq_lines <= irq_lines_sync;
|
||||
end
|
||||
end
|
||||
`else // SCR1_IPIC_SYNC_EN
|
||||
assign irq_lines = soc2ipic_irq_lines_i;
|
||||
`endif // SCR1_IPIC_SYNC_EN
|
||||
|
||||
// IRQ lines level detection
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign irq_lvl = irq_lines ^ ipic_iinvr_next;
|
||||
|
||||
// IRQ lines edge detection
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
irq_lines_dly <= '0;
|
||||
end else begin
|
||||
irq_lines_dly <= irq_lines;
|
||||
end
|
||||
end
|
||||
|
||||
assign irq_edge_detected = (irq_lines_dly ^ irq_lines) & irq_lvl;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IPIC registers read/write interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Read Logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Read data multiplexer
|
||||
always_comb begin
|
||||
ipic2csr_rdata_o = '0;
|
||||
|
||||
if (csr2ipic_r_req_i) begin
|
||||
case (csr2ipic_addr_i)
|
||||
SCR1_IPIC_CISV : begin
|
||||
ipic2csr_rdata_o[SCR1_IRQ_VECT_WIDTH-1:0] = irq_serv_vd
|
||||
? ipic_cisv_ff
|
||||
: SCR1_IRQ_VOID_VECT_NUM;
|
||||
end
|
||||
SCR1_IPIC_CICSR : begin
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_cicsr.ip;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_cicsr.ie;
|
||||
end
|
||||
SCR1_IPIC_IPR : begin
|
||||
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_ipr_ff);
|
||||
end
|
||||
SCR1_IPIC_ISVR : begin
|
||||
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_isvr_ff);
|
||||
end
|
||||
SCR1_IPIC_EOI,
|
||||
SCR1_IPIC_SOI : begin
|
||||
ipic2csr_rdata_o = '0;
|
||||
end
|
||||
SCR1_IPIC_IDX : begin
|
||||
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_idxr_ff);
|
||||
end
|
||||
SCR1_IPIC_ICSR : begin
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_icsr.ip;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_icsr.ie;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IM] = ipic_icsr.im;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_INV] = ipic_icsr.inv;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_PRV_MSB:
|
||||
SCR1_IPIC_ICSR_PRV_LSB] = SCR1_IPIC_PRV_M;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IS] = ipic_icsr.isv;
|
||||
ipic2csr_rdata_o[SCR1_IPIC_ICSR_LN_MSB-1:
|
||||
SCR1_IPIC_ICSR_LN_LSB] = ipic_icsr.line;
|
||||
end
|
||||
default : begin
|
||||
ipic2csr_rdata_o = 'x;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// Write logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Register selection
|
||||
always_comb begin
|
||||
cicsr_wr_req = 1'b0;
|
||||
eoi_wr_req = 1'b0;
|
||||
soi_wr_req = 1'b0;
|
||||
idxr_wr_req = 1'b0;
|
||||
icsr_wr_req = 1'b0;
|
||||
if (csr2ipic_w_req_i) begin
|
||||
case (csr2ipic_addr_i)
|
||||
SCR1_IPIC_CISV : begin end // Quiet Read-Only
|
||||
SCR1_IPIC_CICSR: cicsr_wr_req = 1'b1;
|
||||
SCR1_IPIC_IPR : begin end
|
||||
SCR1_IPIC_ISVR : begin end // Quiet Read-Only
|
||||
SCR1_IPIC_EOI : eoi_wr_req = 1'b1;
|
||||
SCR1_IPIC_SOI : soi_wr_req = 1'b1;
|
||||
SCR1_IPIC_IDX : idxr_wr_req = 1'b1;
|
||||
SCR1_IPIC_ICSR : icsr_wr_req = 1'b1;
|
||||
default : begin // Illegal IPIC register address
|
||||
cicsr_wr_req = 'x;
|
||||
eoi_wr_req = 'x;
|
||||
soi_wr_req = 'x;
|
||||
idxr_wr_req = 'x;
|
||||
icsr_wr_req = 'x;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IPIC registers
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Registers:
|
||||
// - Current Interrupt Vector in Service (CISV) register
|
||||
// - Current Interrupt Control Status (CICSR) register
|
||||
// - End of Interrupt (EOI) register
|
||||
// - Start of Interrupt (SOI) register
|
||||
// - Index (IDX) register
|
||||
// - Interrupt Pending Register (IPR)
|
||||
// - Interrupt Serviced Register (ISVR)
|
||||
// - Interrupt Enable Register (IER)
|
||||
// - Interrupt Mode Register (IMR)
|
||||
// - Interrupt Inversion Register (IINVR)
|
||||
// - Interrupt Control Status Register (ICSR)
|
||||
//
|
||||
|
||||
// CISV register
|
||||
//------------------------------------------------------------------------------
|
||||
// Contains number of the interrupt vector currently in service. When no
|
||||
// interrupts are in service, contains number of the void interrupt vector (0x10).
|
||||
// The register cannot contain all 0's
|
||||
|
||||
assign ipic_cisv_upd = irq_start_vd | ipic_eoi_req;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_cisv_ff <= SCR1_IRQ_VOID_VECT_NUM;
|
||||
end else if (ipic_cisv_upd) begin
|
||||
ipic_cisv_ff <= ipic_cisv_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign ipic_cisv_next = irq_start_vd ? {1'b0, irq_req_idx}
|
||||
: ipic_eoi_req ? irq_eoi_req_vd ? {1'b0, irq_eoi_req_idx}
|
||||
: SCR1_IRQ_VOID_VECT_NUM
|
||||
: 1'b0;
|
||||
|
||||
assign irq_serv_idx = ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-2:0];
|
||||
assign irq_serv_vd = ~ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-1];
|
||||
|
||||
// CICSR register
|
||||
//------------------------------------------------------------------------------
|
||||
// Shows whether the interrupt currently in service is pending and enabled
|
||||
|
||||
assign ipic_cicsr.ip = ipic_ipr_ff[irq_serv_idx] & irq_serv_vd;
|
||||
assign ipic_cicsr.ie = ipic_ier_ff[irq_serv_idx] & irq_serv_vd;
|
||||
|
||||
// EOI register
|
||||
//------------------------------------------------------------------------------
|
||||
// Writing any value to EOI register ends the interrupt which is currently in service
|
||||
|
||||
assign ipic_eoi_req = eoi_wr_req & irq_serv_vd;
|
||||
|
||||
// SOI register
|
||||
//------------------------------------------------------------------------------
|
||||
// Writing any value to SOI activates start of interrupt if one of the following
|
||||
// conditions is true:
|
||||
// - There is at least one pending interrupt with IE and ISR is zero
|
||||
// - There is at least one pending interrupt with IE and higher priority than the
|
||||
// interrupts currently in service
|
||||
|
||||
assign ipic_soi_req = soi_wr_req & irq_req_vd;
|
||||
|
||||
// IDX register
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines the number of interrupt vector which is accessed through the IPIC_ICSR
|
||||
// register
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_idxr_ff <= '0;
|
||||
end else if (idxr_wr_req) begin
|
||||
ipic_idxr_ff <= csr2ipic_wdata_i[SCR1_IRQ_IDX_WIDTH-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
// IPR
|
||||
//------------------------------------------------------------------------------
|
||||
// For every IRQ line shows whether there is a pending interrupt
|
||||
|
||||
assign ipic_ipr_upd = (ipic_ipr_next != ipic_ipr_ff);
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_ipr_ff <= '0;
|
||||
end else if (ipic_ipr_upd) begin
|
||||
ipic_ipr_ff <= ipic_ipr_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_ipr_clr_req = '0;
|
||||
if (csr2ipic_w_req_i) begin
|
||||
case (csr2ipic_addr_i)
|
||||
SCR1_IPIC_CICSR: ipic_ipr_clr_req[irq_serv_idx] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP]
|
||||
& irq_serv_vd;
|
||||
SCR1_IPIC_IPR : ipic_ipr_clr_req = csr2ipic_wdata_i[SCR1_IRQ_VECT_NUM-1:0];
|
||||
SCR1_IPIC_SOI : ipic_ipr_clr_req[irq_req_idx] = irq_req_vd;
|
||||
SCR1_IPIC_ICSR : ipic_ipr_clr_req[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP];
|
||||
default : begin end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign ipic_ipr_clr_cond = ~irq_lvl | ipic_imr_next;
|
||||
assign ipic_ipr_clr = ipic_ipr_clr_req & ipic_ipr_clr_cond;
|
||||
|
||||
always_comb begin
|
||||
ipic_ipr_next = '0;
|
||||
for (int unsigned i=0; i<SCR1_IRQ_VECT_NUM; ++i) begin
|
||||
ipic_ipr_next[i] = ipic_ipr_clr[i] ? 1'b0
|
||||
: ~ipic_imr_ff[i] ? irq_lvl[i]
|
||||
: ipic_ipr_ff[i] | irq_edge_detected[i];
|
||||
end
|
||||
end
|
||||
|
||||
// ISVR
|
||||
//------------------------------------------------------------------------------
|
||||
// For every IRQ line shows whether the interrupt is in service or not
|
||||
|
||||
assign ipic_isvr_upd = irq_start_vd | ipic_eoi_req;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_isvr_ff <= '0;
|
||||
end else if (ipic_isvr_upd) begin
|
||||
ipic_isvr_ff <= ipic_isvr_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_isvr_eoi = ipic_isvr_ff;
|
||||
if (irq_serv_vd) begin
|
||||
ipic_isvr_eoi[irq_serv_idx] = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_isvr_next = ipic_isvr_ff;
|
||||
if (irq_start_vd) begin
|
||||
ipic_isvr_next[irq_req_idx] = 1'b1;
|
||||
end else if (ipic_eoi_req) begin
|
||||
ipic_isvr_next = ipic_isvr_eoi;
|
||||
end
|
||||
end
|
||||
|
||||
// IER
|
||||
//------------------------------------------------------------------------------
|
||||
// Enables/disables interrupt for every IRQ line
|
||||
|
||||
assign ipic_ier_upd = cicsr_wr_req | icsr_wr_req;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_ier_ff <= '0;
|
||||
end else if (ipic_ier_upd) begin
|
||||
ipic_ier_ff <= ipic_ier_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_ier_next = ipic_ier_ff;
|
||||
if (cicsr_wr_req) begin
|
||||
ipic_ier_next[irq_serv_idx] = irq_serv_vd
|
||||
? csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE]
|
||||
: ipic_ier_ff[irq_serv_idx];
|
||||
end else if (icsr_wr_req) begin
|
||||
ipic_ier_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE];
|
||||
end
|
||||
end
|
||||
|
||||
// IMR
|
||||
//------------------------------------------------------------------------------
|
||||
// For every IRQ line sets either Level (0) or Edge (1) detection
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_imr_ff <= '0;
|
||||
end else if (icsr_wr_req) begin
|
||||
ipic_imr_ff <= ipic_imr_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_imr_next = ipic_imr_ff;
|
||||
if (icsr_wr_req) begin
|
||||
ipic_imr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IM];
|
||||
end
|
||||
end
|
||||
|
||||
// IINVR
|
||||
//------------------------------------------------------------------------------
|
||||
// For every IRQ line defines whether it should be inverted or not
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
ipic_iinvr_ff <= '0;
|
||||
end else if (icsr_wr_req) begin
|
||||
ipic_iinvr_ff <= ipic_iinvr_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
ipic_iinvr_next = ipic_iinvr_ff;
|
||||
if (icsr_wr_req) begin
|
||||
ipic_iinvr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_INV];
|
||||
end
|
||||
end
|
||||
|
||||
// ICSR
|
||||
//------------------------------------------------------------------------------
|
||||
// Holds control and status information about the interrupt defined by Index Register
|
||||
|
||||
assign ipic_icsr.ip = ipic_ipr_ff [ipic_idxr_ff];
|
||||
assign ipic_icsr.ie = ipic_ier_ff [ipic_idxr_ff];
|
||||
assign ipic_icsr.im = ipic_imr_ff [ipic_idxr_ff];
|
||||
assign ipic_icsr.inv = ipic_iinvr_ff[ipic_idxr_ff];
|
||||
assign ipic_icsr.isv = ipic_isvr_ff [ipic_idxr_ff];
|
||||
assign ipic_icsr.line = SCR1_IRQ_LINES_WIDTH'(ipic_idxr_ff);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Priority IRQ generation logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign irq_req_v = ipic_ipr_ff & ipic_ier_ff;
|
||||
|
||||
assign irr_priority = scr1_search_one_16(irq_req_v);
|
||||
assign irq_req_vd = irr_priority.vd;
|
||||
assign irq_req_idx = irr_priority.idx;
|
||||
|
||||
assign isvr_priority_eoi = scr1_search_one_16(ipic_isvr_eoi);
|
||||
assign irq_eoi_req_vd = isvr_priority_eoi.vd;
|
||||
assign irq_eoi_req_idx = isvr_priority_eoi.idx;
|
||||
|
||||
assign irq_hi_prior_pnd = irq_req_idx < irq_serv_idx;
|
||||
|
||||
assign ipic2csr_irq_m_req_o = irq_req_vd & (~irq_serv_vd | irq_hi_prior_pnd);
|
||||
|
||||
assign irq_start_vd = ipic2csr_irq_m_req_o & ipic_soi_req;
|
||||
|
||||
endmodule : scr1_ipic
|
||||
|
||||
`endif // SCR1_IPIC_EN
|
||||
1169
src_ref/core/pipeline/scr1_pipe_csr.sv
Normal file
1169
src_ref/core/pipeline/scr1_pipe_csr.sv
Normal file
File diff suppressed because it is too large
Load Diff
1086
src_ref/core/pipeline/scr1_pipe_exu.sv
Normal file
1086
src_ref/core/pipeline/scr1_pipe_exu.sv
Normal file
File diff suppressed because it is too large
Load Diff
904
src_ref/core/pipeline/scr1_pipe_hdu.sv
Normal file
904
src_ref/core/pipeline/scr1_pipe_hdu.sv
Normal file
@@ -0,0 +1,904 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_hdu.sv>
|
||||
/// @brief HART Debug Unit (HDU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Functionality:
|
||||
// - Controls HART state (RUN, Debug RUN, Debug HALTED)
|
||||
// - Setups Debug Mode execution
|
||||
// - Provides status information about Debug Mode execution
|
||||
// - Provides Program Buffer functionality (a few instructions execution while
|
||||
// in Debug Mode)
|
||||
// - Provides access to Debug CSRs
|
||||
//
|
||||
// Structure:
|
||||
// - Debug state FSM
|
||||
// - HART Control logic
|
||||
// - HART Status logic
|
||||
// - Program Buffer
|
||||
// - Debug CSRs
|
||||
// - HDU <-> DM interface
|
||||
// - HDU <-> EXU interface
|
||||
// - HDU <-> IFU interface
|
||||
// - HDU <-> CSR interface
|
||||
// - HDU <-> TDU interface
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_arch_types.svh"
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`include "scr1_hdu.svh"
|
||||
|
||||
module scr1_pipe_hdu #(parameter HART_PBUF_INSTR_REGOUT_EN = 1'b1) (
|
||||
// Common signals
|
||||
input logic rst_n, // HDU reset
|
||||
input logic clk, // HDU clock
|
||||
input logic clk_en, // HDU clock enable
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
input logic clk_pipe_en, // Pipeline clock enable
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
input logic pipe2hdu_rdc_qlfy_i, // Pipeline RDC qualifier
|
||||
|
||||
// HDU <-> CSR i/f
|
||||
input logic csr2hdu_req_i, // CSR i/f request
|
||||
input type_scr1_csr_cmd_sel_e csr2hdu_cmd_i, // CSR i/f command
|
||||
input logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr_i, // CSR i/f address
|
||||
input logic [`SCR1_XLEN-1:0] csr2hdu_wdata_i, // CSR i/f write data
|
||||
output type_scr1_csr_resp_e hdu2csr_resp_o, // CSR i/f response
|
||||
output logic [`SCR1_XLEN-1:0] hdu2csr_rdata_o, // CSR i/f read data
|
||||
|
||||
// HDU <-> DM i/f
|
||||
// HART Run Control i/f
|
||||
input logic dm2hdu_cmd_req_i, // DM-HART Command request
|
||||
input type_scr1_hdu_dbgstates_e dm2hdu_cmd_i, // DM-HART Command
|
||||
output logic hdu2dm_cmd_resp_o, // DM-HART Command response
|
||||
output logic hdu2dm_cmd_rcode_o, // DM-HART Command return code: 0 - Ok; 1 - Error
|
||||
output logic hdu2dm_hart_event_o, // DM-HART Event: 1 if HART debug state changed
|
||||
output type_scr1_hdu_hartstatus_s hdu2dm_hart_status_o, // DM-HART Status
|
||||
|
||||
// Program Buffer i/f
|
||||
output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] hdu2dm_pbuf_addr_o, // Program Buffer address - so far request only for 1 instruction
|
||||
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2hdu_pbuf_instr_i, // Program Buffer instruction
|
||||
|
||||
// HART Abstract Data regs i/f
|
||||
output logic hdu2dm_dreg_req_o, // Abstract Data Register request
|
||||
output logic hdu2dm_dreg_wr_o, // Abstract Data Register write
|
||||
output logic [`SCR1_XLEN-1:0] hdu2dm_dreg_wdata_o, // Abstract Data Register write data
|
||||
input logic dm2hdu_dreg_resp_i, // Abstract Data Register response
|
||||
input logic dm2hdu_dreg_fail_i, // Abstract Data Register fail
|
||||
input logic [`SCR1_XLEN-1:0] dm2hdu_dreg_rdata_i, // Abstract Data Register read data
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
// HDU <-> TDU interface
|
||||
output logic hdu2tdu_hwbrk_dsbl_o, // Disables BRKM
|
||||
input logic tdu2hdu_dmode_req_i, // Trigger Module requests transition to debug mode
|
||||
input logic exu2hdu_ibrkpt_hw_i, // Hardware breakpoint on current instruction
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
// HART Run Status
|
||||
input logic pipe2hdu_exu_busy_i, // EXU busy
|
||||
input logic pipe2hdu_instret_i, // Instruction retired (with or without exception)
|
||||
input logic pipe2hdu_init_pc_i, // Reset exit
|
||||
|
||||
// HART Halt Status
|
||||
input logic pipe2hdu_exu_exc_req_i, // Exception request
|
||||
input logic pipe2hdu_brkpt_i, // Software Breakpoint (EBREAK)
|
||||
|
||||
// HDU <-> EXU i/f
|
||||
// HART Run Control
|
||||
output logic hdu2exu_pbuf_fetch_o, // Fetch instruction from Program Buffer
|
||||
output logic hdu2exu_no_commit_o, // Forbid instruction commitment
|
||||
output logic hdu2exu_irq_dsbl_o, // Disable IRQ
|
||||
output logic hdu2exu_pc_advmt_dsbl_o, // Forbid PC advancement
|
||||
output logic hdu2exu_dmode_sstep_en_o, // Enable single-step
|
||||
|
||||
// HART state
|
||||
output logic hdu2exu_dbg_halted_o, // Debug halted state
|
||||
output logic hdu2exu_dbg_run2halt_o, // Transition to debug halted state
|
||||
output logic hdu2exu_dbg_halt2run_o, // Transition to run state
|
||||
output logic hdu2exu_dbg_run_start_o, // First cycle of run state
|
||||
|
||||
// PC interface
|
||||
input logic [`SCR1_XLEN-1:0] pipe2hdu_pc_curr_i, // Current PC
|
||||
output logic [`SCR1_XLEN-1:0] hdu2exu_dbg_new_pc_o, // New PC for resume
|
||||
|
||||
// HDU <-> IFU i/f
|
||||
// Program Buffer Instruction interface
|
||||
input logic ifu2hdu_pbuf_instr_rdy_i, // Program Buffer Instruction i/f ready
|
||||
output logic hdu2ifu_pbuf_instr_vd_o, // Program Buffer Instruction valid
|
||||
output logic hdu2ifu_pbuf_instr_err_o, // Program Buffer Instruction i/f error
|
||||
output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_o // Program Buffer Instruction itself
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local Parameters
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
localparam int unsigned SCR1_HDU_TIMEOUT = 64; // must be power of 2
|
||||
localparam int unsigned SCR1_HDU_TIMEOUT_WIDTH = $clog2(SCR1_HDU_TIMEOUT);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local Signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Debug FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// FSM control signals
|
||||
logic dm_dhalt_req;
|
||||
logic dm_run_req;
|
||||
|
||||
logic dm_cmd_run;
|
||||
logic dm_cmd_dhalted;
|
||||
logic dm_cmd_drun;
|
||||
|
||||
// Debug state FSM signals
|
||||
type_scr1_hdu_dbgstates_e dbg_state;
|
||||
type_scr1_hdu_dbgstates_e dbg_state_next;
|
||||
logic dbg_state_dhalted;
|
||||
logic dbg_state_drun;
|
||||
logic dbg_state_run;
|
||||
logic dbg_state_reset;
|
||||
|
||||
// FSM transition, update and event registers
|
||||
logic dfsm_trans;
|
||||
logic dfsm_trans_next;
|
||||
logic dfsm_update;
|
||||
logic dfsm_update_next;
|
||||
logic dfsm_event;
|
||||
logic dfsm_event_next;
|
||||
|
||||
// HART Control signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
logic hart_resume_req;
|
||||
logic hart_halt_req;
|
||||
logic hart_cmd_req;
|
||||
|
||||
// HART Run Control register
|
||||
logic hart_runctrl_upd;
|
||||
logic hart_runctrl_clr;
|
||||
type_scr1_hdu_runctrl_s hart_runctrl;
|
||||
|
||||
// HART halt request timeout counter signals
|
||||
logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt;
|
||||
logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt_next;
|
||||
logic halt_req_timeout_cnt_en;
|
||||
logic halt_req_timeout_flag;
|
||||
|
||||
// HART Status signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type_scr1_hdu_haltstatus_s hart_haltstatus;
|
||||
type_scr1_hdu_haltcause_e hart_haltcause;
|
||||
|
||||
logic hart_halt_pnd;
|
||||
logic hart_halt_ack;
|
||||
|
||||
// Debug mode cause decoder signals
|
||||
logic dmode_cause_sstep;
|
||||
logic dmode_cause_except;
|
||||
logic dmode_cause_ebreak;
|
||||
logic dmode_cause_any;
|
||||
`ifdef SCR1_TDU_EN
|
||||
logic dmode_cause_tmreq;
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
// Program Buffer FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// PBUF FSM control signals
|
||||
logic ifu_handshake_done;
|
||||
logic pbuf_exc_inj_req;
|
||||
logic pbuf_exc_inj_end;
|
||||
logic pbuf_start_fetch;
|
||||
|
||||
// PBUF FSM signals
|
||||
type_scr1_hdu_pbufstates_e pbuf_fsm_curr;
|
||||
type_scr1_hdu_pbufstates_e pbuf_fsm_next;
|
||||
logic pbuf_fsm_idle;
|
||||
logic pbuf_fsm_fetch;
|
||||
logic pbuf_fsm_excinj;
|
||||
|
||||
// PBUF address signals
|
||||
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_ff;
|
||||
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_next;
|
||||
logic pbuf_addr_end;
|
||||
logic pbuf_addr_next_vd;
|
||||
|
||||
logic pbuf_instr_wait_latching;
|
||||
|
||||
// Debugs CSRs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// CSRs write/read interface signals
|
||||
logic csr_upd_on_halt;
|
||||
logic csr_wr;
|
||||
logic [`SCR1_XLEN-1:0] csr_wr_data;
|
||||
logic [`SCR1_XLEN-1:0] csr_rd_data;
|
||||
|
||||
// Debug Control and Status register (DCSR)
|
||||
logic csr_dcsr_sel;
|
||||
logic csr_dcsr_wr;
|
||||
type_scr1_hdu_dcsr_s csr_dcsr_in;
|
||||
type_scr1_hdu_dcsr_s csr_dcsr_out;
|
||||
logic csr_dcsr_ebreakm;
|
||||
logic csr_dcsr_stepie;
|
||||
logic csr_dcsr_step;
|
||||
logic [SCR1_HDU_DCSR_CAUSE_BIT_L-
|
||||
SCR1_HDU_DCSR_CAUSE_BIT_R:0] csr_dcsr_cause;
|
||||
|
||||
// Debug Program Counter register (DPC)
|
||||
logic csr_dpc_sel;
|
||||
logic csr_dpc_wr;
|
||||
logic [`SCR1_XLEN-1:0] csr_dpc_ff;
|
||||
logic [`SCR1_XLEN-1:0] csr_dpc_next;
|
||||
logic [`SCR1_XLEN-1:0] csr_dpc_out;
|
||||
|
||||
// Debug Scratch register 0 (DSCRATCH0)
|
||||
logic csr_addr_dscratch0;
|
||||
logic csr_dscratch0_sel;
|
||||
logic csr_dscratch0_wr;
|
||||
logic [`SCR1_XLEN-1:0] csr_dscratch0_out;
|
||||
type_scr1_csr_resp_e csr_dscratch0_resp;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Debug state FSM logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Debug state FSM logic consists of the following functional units:
|
||||
// - FSM control logic
|
||||
// - Debug state FSM
|
||||
// - FSM transition, update and event registers
|
||||
//
|
||||
|
||||
// FSM control logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign dm_cmd_dhalted = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DHALTED);
|
||||
assign dm_cmd_run = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_RUN);
|
||||
assign dm_cmd_drun = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DRUN);
|
||||
|
||||
assign dm_dhalt_req = dm2hdu_cmd_req_i & dm_cmd_dhalted;
|
||||
assign dm_run_req = dm2hdu_cmd_req_i & (dm_cmd_run | dm_cmd_drun);
|
||||
|
||||
// Debug state FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
dbg_state <= SCR1_HDU_DBGSTATE_RESET;
|
||||
end else begin
|
||||
dbg_state <= dbg_state_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if (~pipe2hdu_rdc_qlfy_i) begin
|
||||
dbg_state_next = SCR1_HDU_DBGSTATE_RESET;
|
||||
end else begin
|
||||
case (dbg_state)
|
||||
SCR1_HDU_DBGSTATE_RESET: begin
|
||||
dbg_state_next = ~pipe2hdu_init_pc_i ? SCR1_HDU_DBGSTATE_RESET
|
||||
: dm_dhalt_req ? SCR1_HDU_DBGSTATE_DHALTED
|
||||
: SCR1_HDU_DBGSTATE_RUN;
|
||||
end
|
||||
SCR1_HDU_DBGSTATE_RUN: begin
|
||||
dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
|
||||
: SCR1_HDU_DBGSTATE_RUN;
|
||||
end
|
||||
SCR1_HDU_DBGSTATE_DHALTED: begin
|
||||
dbg_state_next = ~dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
|
||||
: dm_cmd_drun ? SCR1_HDU_DBGSTATE_DRUN
|
||||
: SCR1_HDU_DBGSTATE_RUN;
|
||||
end
|
||||
SCR1_HDU_DBGSTATE_DRUN: begin
|
||||
dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
|
||||
: SCR1_HDU_DBGSTATE_DRUN;
|
||||
end
|
||||
default: begin
|
||||
`ifdef SCR1_XPROP_EN
|
||||
dbg_state_next = SCR1_HDU_DBGSTATE_XXX;
|
||||
`else // SCR1_XPROP_EN
|
||||
dbg_state_next = dbg_state;
|
||||
`endif // SCR1_XPROP_EN
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign dbg_state_dhalted = (dbg_state == SCR1_HDU_DBGSTATE_DHALTED);
|
||||
assign dbg_state_drun = (dbg_state == SCR1_HDU_DBGSTATE_DRUN);
|
||||
assign dbg_state_run = (dbg_state == SCR1_HDU_DBGSTATE_RUN);
|
||||
assign dbg_state_reset = (dbg_state == SCR1_HDU_DBGSTATE_RESET);
|
||||
|
||||
// FSM transition, update and event registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
dfsm_trans <= 1'b0;
|
||||
dfsm_update <= 1'b0;
|
||||
dfsm_event <= 1'b0;
|
||||
end else begin
|
||||
dfsm_trans <= dfsm_trans_next;
|
||||
dfsm_update <= dfsm_update_next;
|
||||
dfsm_event <= dfsm_event_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
dfsm_trans_next = 1'b0;
|
||||
dfsm_update_next = 1'b0;
|
||||
dfsm_event_next = 1'b0;
|
||||
|
||||
if (~pipe2hdu_rdc_qlfy_i) begin
|
||||
dfsm_trans_next = 1'b0;
|
||||
dfsm_update_next = 1'b0;
|
||||
dfsm_event_next = 1'b1;
|
||||
end else begin
|
||||
case (dbg_state)
|
||||
SCR1_HDU_DBGSTATE_RESET: begin
|
||||
dfsm_trans_next = 1'b0;
|
||||
dfsm_update_next = 1'b0;
|
||||
dfsm_event_next = pipe2hdu_init_pc_i & ~dm2hdu_cmd_req_i;
|
||||
end
|
||||
|
||||
SCR1_HDU_DBGSTATE_RUN,
|
||||
SCR1_HDU_DBGSTATE_DRUN: begin
|
||||
dfsm_trans_next = ~dfsm_update ? hart_halt_pnd : dfsm_trans;
|
||||
dfsm_update_next = ~dfsm_update & hart_halt_ack;
|
||||
dfsm_event_next = dfsm_update;
|
||||
end
|
||||
|
||||
SCR1_HDU_DBGSTATE_DHALTED: begin
|
||||
dfsm_trans_next = ~dfsm_update ? ~dfsm_trans & dm_run_req
|
||||
: dfsm_trans;
|
||||
dfsm_update_next = ~dfsm_update & dfsm_trans;
|
||||
dfsm_event_next = dfsm_update;
|
||||
end
|
||||
|
||||
default : begin
|
||||
dfsm_trans_next = 'X;
|
||||
dfsm_update_next = 'X;
|
||||
dfsm_event_next = 'X;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HART Control logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// HART Control logic consists of the following functional units:
|
||||
// - Control signals
|
||||
// - HART Run Control register
|
||||
// - HART Halt Request Time-Out counter
|
||||
//
|
||||
|
||||
// Control logic
|
||||
always_comb begin
|
||||
hart_cmd_req = 1'b0;
|
||||
|
||||
if (~pipe2hdu_rdc_qlfy_i) begin
|
||||
hart_cmd_req = 1'b0;
|
||||
end else begin
|
||||
case (dbg_state)
|
||||
SCR1_HDU_DBGSTATE_RESET : hart_cmd_req = dm2hdu_cmd_req_i;
|
||||
SCR1_HDU_DBGSTATE_DHALTED: hart_cmd_req = (dfsm_update | dfsm_trans);
|
||||
SCR1_HDU_DBGSTATE_RUN,
|
||||
SCR1_HDU_DBGSTATE_DRUN : hart_cmd_req = ~dfsm_update & dfsm_trans;
|
||||
default : hart_cmd_req = 'X;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign hart_halt_req = dm_cmd_dhalted & hart_cmd_req;
|
||||
assign hart_resume_req = (dm_cmd_run | dm_cmd_drun) & hart_cmd_req;
|
||||
|
||||
// HART Run Control register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign hart_runctrl_clr = (dbg_state_run | dbg_state_drun)
|
||||
& (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED);
|
||||
assign hart_runctrl_upd = dbg_state_dhalted & dfsm_trans_next;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
hart_runctrl.irq_dsbl <= 1'b0;
|
||||
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL;
|
||||
hart_runctrl.pc_advmt_dsbl <= 1'b0;
|
||||
hart_runctrl.hwbrkpt_dsbl <= 1'b0;
|
||||
hart_runctrl.redirect <= '0;
|
||||
end else if(clk_en) begin
|
||||
if (hart_runctrl_clr) begin
|
||||
hart_runctrl <= '0;
|
||||
end else begin
|
||||
if (hart_runctrl_upd) begin
|
||||
if (~dm_cmd_drun) begin
|
||||
// Case : resume to RUN state
|
||||
hart_runctrl.irq_dsbl <= csr_dcsr_step ? ~csr_dcsr_stepie : 1'b0;
|
||||
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL;
|
||||
hart_runctrl.pc_advmt_dsbl <= 1'b0;
|
||||
hart_runctrl.hwbrkpt_dsbl <= 1'b0;
|
||||
hart_runctrl.redirect.sstep <= csr_dcsr_step;
|
||||
hart_runctrl.redirect.ebreak <= csr_dcsr_ebreakm;
|
||||
end else begin
|
||||
// Case : resume to DRUN state
|
||||
hart_runctrl.irq_dsbl <= 1'b1;
|
||||
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_PBUF;
|
||||
hart_runctrl.pc_advmt_dsbl <= 1'b1;
|
||||
hart_runctrl.hwbrkpt_dsbl <= 1'b1;
|
||||
hart_runctrl.redirect.sstep <= 1'b0;
|
||||
hart_runctrl.redirect.ebreak <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// HART Halt Request Time-Out counter
|
||||
//------------------------------------------------------------------------------
|
||||
// HART goes into halt state only if the halt request is present for timeout period
|
||||
// of time
|
||||
|
||||
assign halt_req_timeout_cnt_en = hdu2exu_dbg_halt2run_o
|
||||
| (hart_halt_req & ~hdu2exu_dbg_run2halt_o);
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
halt_req_timeout_cnt <= '1;
|
||||
end else if (halt_req_timeout_cnt_en) begin
|
||||
halt_req_timeout_cnt <= halt_req_timeout_cnt_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign halt_req_timeout_cnt_next = hdu2exu_dbg_halt2run_o ? '1
|
||||
: (hart_halt_req & ~hdu2exu_dbg_run2halt_o) ? halt_req_timeout_cnt - 1'b1
|
||||
: halt_req_timeout_cnt;
|
||||
|
||||
assign halt_req_timeout_flag = ~|halt_req_timeout_cnt;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HART Status logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// HART Status logic consists of the following functional units:
|
||||
// - Debug mode cause decoder
|
||||
// - Hart halt status cause encoder
|
||||
// - Hart halt status register
|
||||
//
|
||||
|
||||
// Debug mode cause decoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign dmode_cause_sstep = hart_runctrl.redirect.sstep & pipe2hdu_instret_i;
|
||||
assign dmode_cause_except = dbg_state_drun & pipe2hdu_exu_exc_req_i
|
||||
& ~pipe2hdu_brkpt_i
|
||||
`ifdef SCR1_TDU_EN
|
||||
& ~exu2hdu_ibrkpt_hw_i
|
||||
`endif // SCR1_TDU_EN
|
||||
;
|
||||
assign dmode_cause_ebreak = hart_runctrl.redirect.ebreak & pipe2hdu_brkpt_i;
|
||||
`ifdef SCR1_TDU_EN
|
||||
assign dmode_cause_tmreq = tdu2hdu_dmode_req_i & exu2hdu_ibrkpt_hw_i;
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
assign dmode_cause_any = dmode_cause_sstep | dmode_cause_ebreak | dmode_cause_except
|
||||
| hart_halt_req
|
||||
`ifdef SCR1_TDU_EN
|
||||
| dmode_cause_tmreq
|
||||
`endif // SCR1_TDU_EN
|
||||
;
|
||||
|
||||
// HART halt cause encoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
case (1'b1)
|
||||
`ifdef SCR1_TDU_EN
|
||||
dmode_cause_tmreq : hart_haltcause = SCR1_HDU_HALTCAUSE_TMREQ;
|
||||
`endif // SCR1_TDU_EN
|
||||
dmode_cause_ebreak : hart_haltcause = SCR1_HDU_HALTCAUSE_EBREAK;
|
||||
hart_halt_req : hart_haltcause = SCR1_HDU_HALTCAUSE_DMREQ;
|
||||
dmode_cause_sstep : hart_haltcause = SCR1_HDU_HALTCAUSE_SSTEP;
|
||||
default : hart_haltcause = SCR1_HDU_HALTCAUSE_NONE;
|
||||
endcase
|
||||
end
|
||||
|
||||
// HART halt status register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
hart_haltstatus <= '0;
|
||||
end else if (hart_halt_ack) begin
|
||||
hart_haltstatus.except <= dmode_cause_except;
|
||||
hart_haltstatus.cause <= hart_haltcause;
|
||||
end
|
||||
end
|
||||
|
||||
assign hart_halt_pnd = (dfsm_trans | dm_dhalt_req) & ~hart_halt_ack;
|
||||
assign hart_halt_ack = ~hdu2exu_dbg_halted_o
|
||||
& (halt_req_timeout_flag | (~pipe2hdu_exu_busy_i & dmode_cause_any));
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Program Buffer (PBUF) logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Program Buffer allows to execute small programs in debug mode
|
||||
//
|
||||
|
||||
// To terminate Program Buffer execution exception should be raised. There are 2
|
||||
// cases:
|
||||
// - One of PBUF instructions raise an exception
|
||||
// - No PBUF instruction raise an exception before the last PBUF instruction has
|
||||
// been issued. In this case FSM goes into EXCINJECT state and an "Instruction
|
||||
// fetch access fault" exception is injected
|
||||
|
||||
// PBUF FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign ifu_handshake_done = hdu2ifu_pbuf_instr_vd_o & ifu2hdu_pbuf_instr_rdy_i;
|
||||
assign pbuf_addr_end = (pbuf_addr_ff == (SCR1_HDU_PBUF_ADDR_SPAN-1));
|
||||
|
||||
assign pbuf_start_fetch = dbg_state_dhalted & (dbg_state_next == SCR1_HDU_DBGSTATE_DRUN);
|
||||
assign pbuf_exc_inj_req = ifu_handshake_done & pbuf_addr_end;
|
||||
assign pbuf_exc_inj_end = pipe2hdu_exu_exc_req_i | ifu_handshake_done;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
pbuf_fsm_curr <= SCR1_HDU_PBUFSTATE_IDLE;
|
||||
end else if(clk_en) begin
|
||||
pbuf_fsm_curr <= pbuf_fsm_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
case (pbuf_fsm_curr)
|
||||
SCR1_HDU_PBUFSTATE_IDLE: begin
|
||||
pbuf_fsm_next = pbuf_start_fetch ? SCR1_HDU_PBUFSTATE_FETCH
|
||||
: SCR1_HDU_PBUFSTATE_IDLE;
|
||||
end
|
||||
SCR1_HDU_PBUFSTATE_FETCH: begin
|
||||
pbuf_fsm_next = pipe2hdu_exu_exc_req_i ? SCR1_HDU_PBUFSTATE_WAIT4END
|
||||
: pbuf_exc_inj_req ? SCR1_HDU_PBUFSTATE_EXCINJECT
|
||||
: SCR1_HDU_PBUFSTATE_FETCH;
|
||||
end
|
||||
SCR1_HDU_PBUFSTATE_EXCINJECT: begin
|
||||
pbuf_fsm_next = pbuf_exc_inj_end ? SCR1_HDU_PBUFSTATE_WAIT4END
|
||||
: SCR1_HDU_PBUFSTATE_EXCINJECT;
|
||||
end
|
||||
SCR1_HDU_PBUFSTATE_WAIT4END: begin
|
||||
pbuf_fsm_next = hdu2exu_dbg_halted_o ? SCR1_HDU_PBUFSTATE_IDLE
|
||||
: SCR1_HDU_PBUFSTATE_WAIT4END;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign pbuf_fsm_idle = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_IDLE);
|
||||
assign pbuf_fsm_fetch = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_FETCH);
|
||||
assign pbuf_fsm_excinj = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_EXCINJECT);
|
||||
|
||||
// Program Buffer address register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign pbuf_addr_next_vd = pbuf_fsm_fetch & ifu_handshake_done
|
||||
& ~pipe2hdu_exu_exc_req_i & ~pbuf_addr_end;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
pbuf_addr_ff <= '0;
|
||||
end else if(clk_en) begin
|
||||
pbuf_addr_ff <= pbuf_addr_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign pbuf_addr_next = pbuf_fsm_idle ? '0
|
||||
: pbuf_addr_next_vd ? pbuf_addr_ff + 1'b1
|
||||
: pbuf_addr_ff;
|
||||
|
||||
// Pass instruction from debug program buffer to cpu pipeline with two options:
|
||||
// - through register, better for frequency
|
||||
// - through wires, better for area
|
||||
generate if (HART_PBUF_INSTR_REGOUT_EN) begin
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
pbuf_instr_wait_latching <= 1'b0;
|
||||
end else begin
|
||||
pbuf_instr_wait_latching <= ifu_handshake_done;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
assign pbuf_instr_wait_latching = 1'b0;
|
||||
end endgenerate
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Debug CSRs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_upd_on_halt = (dbg_state_reset | dbg_state_run)
|
||||
& (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED);
|
||||
|
||||
// CSRs select logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin : csr_if_regsel
|
||||
csr_dcsr_sel = 1'b0;
|
||||
csr_dpc_sel = 1'b0;
|
||||
csr_dscratch0_sel = 1'b0;
|
||||
//csr_dscratch1_sel = 1'b0;
|
||||
|
||||
if (csr2hdu_req_i) begin
|
||||
case (csr2hdu_addr_i)
|
||||
SCR1_HDU_DBGCSR_OFFS_DCSR : csr_dcsr_sel = 1'b1;
|
||||
SCR1_HDU_DBGCSR_OFFS_DPC : csr_dpc_sel = 1'b1;
|
||||
SCR1_HDU_DBGCSR_OFFS_DSCRATCH0: csr_dscratch0_sel = 1'b1;
|
||||
default : begin
|
||||
csr_dcsr_sel = 1'bX;
|
||||
csr_dpc_sel = 1'bX;
|
||||
csr_dscratch0_sel = 1'bX;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end : csr_if_regsel
|
||||
|
||||
// CSRs read interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_rd_data = csr_dcsr_out | csr_dpc_out | csr_dscratch0_out;
|
||||
|
||||
// CSRs write interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_wr = csr2hdu_req_i;
|
||||
|
||||
always_comb begin : csr_if_write
|
||||
csr_wr_data = '0;
|
||||
|
||||
if (csr2hdu_req_i) begin
|
||||
case (csr2hdu_cmd_i)
|
||||
SCR1_CSR_CMD_WRITE : csr_wr_data = csr2hdu_wdata_i;
|
||||
SCR1_CSR_CMD_SET : csr_wr_data = csr_rd_data | csr2hdu_wdata_i;
|
||||
SCR1_CSR_CMD_CLEAR : csr_wr_data = csr_rd_data & (~csr2hdu_wdata_i);
|
||||
default : csr_wr_data = 'X;
|
||||
endcase
|
||||
end
|
||||
end : csr_if_write
|
||||
|
||||
// Debug Control and Status register
|
||||
//------------------------------------------------------------------------------
|
||||
// Setups the HART behaviour in Debug Mode and holds Debug status information
|
||||
|
||||
always_comb begin
|
||||
csr_dcsr_in = csr_wr_data;
|
||||
csr_dcsr_wr = csr_wr & csr_dcsr_sel;
|
||||
|
||||
csr_dcsr_out = '0;
|
||||
if (csr_dcsr_sel) begin
|
||||
csr_dcsr_out.xdebugver = SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER;
|
||||
csr_dcsr_out.ebreakm = csr_dcsr_ebreakm;
|
||||
csr_dcsr_out.stepie = csr_dcsr_stepie;
|
||||
csr_dcsr_out.step = csr_dcsr_step;
|
||||
csr_dcsr_out.prv = 2'b11;
|
||||
csr_dcsr_out.cause = csr_dcsr_cause;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
csr_dcsr_ebreakm <= 1'b0;
|
||||
csr_dcsr_stepie <= 1'b0;
|
||||
csr_dcsr_step <= 1'b0;
|
||||
end else if(clk_en) begin
|
||||
if (csr_dcsr_wr) begin
|
||||
csr_dcsr_ebreakm <= csr_dcsr_in.ebreakm;
|
||||
csr_dcsr_stepie <= csr_dcsr_in.stepie;
|
||||
csr_dcsr_step <= csr_dcsr_in.step;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
csr_dcsr_cause <= 1'b0;
|
||||
end else if(clk_en) begin
|
||||
if(csr_upd_on_halt) begin
|
||||
csr_dcsr_cause <= hart_haltstatus.cause;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Debug PC register
|
||||
//------------------------------------------------------------------------------
|
||||
// Saves the virtual address of the next instruction to be executed when Debug
|
||||
// Mode is entered. Could be changed by debugger
|
||||
|
||||
assign csr_dpc_wr = csr_wr & csr_dpc_sel;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
csr_dpc_ff <= '0;
|
||||
end else if(clk_en) begin
|
||||
csr_dpc_ff <= csr_dpc_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign csr_dpc_next = csr_upd_on_halt ? pipe2hdu_pc_curr_i
|
||||
: csr_dpc_wr ? csr_wr_data
|
||||
: csr_dpc_ff;
|
||||
assign csr_dpc_out = csr_dpc_sel ? csr_dpc_ff : '0;
|
||||
|
||||
// Debug Scratch 0 register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_dscratch0_resp = (~dm2hdu_dreg_resp_i | dm2hdu_dreg_fail_i)
|
||||
? SCR1_CSR_RESP_ER
|
||||
: SCR1_CSR_RESP_OK;
|
||||
assign csr_dscratch0_out = csr_dscratch0_sel ? dm2hdu_dreg_rdata_i : '0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HDU <-> DM interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign hdu2dm_hart_event_o = dfsm_event;
|
||||
|
||||
// HART status
|
||||
always_comb begin
|
||||
hdu2dm_hart_status_o = '0;
|
||||
hdu2dm_hart_status_o.dbg_state = dbg_state;
|
||||
hdu2dm_hart_status_o.except = dbg_state_dhalted & hart_haltstatus.except;
|
||||
hdu2dm_hart_status_o.ebreak = dbg_state_dhalted & (hart_haltstatus.cause == SCR1_HDU_HALTCAUSE_EBREAK);
|
||||
end
|
||||
|
||||
assign hdu2dm_cmd_rcode_o = dbg_state_reset
|
||||
? ~pipe2hdu_rdc_qlfy_i | ~pipe2hdu_init_pc_i | ~dm2hdu_cmd_req_i
|
||||
: ~pipe2hdu_rdc_qlfy_i | ~dfsm_update;
|
||||
|
||||
always_comb begin
|
||||
hdu2dm_cmd_resp_o = 1'b0;
|
||||
|
||||
case (dbg_state)
|
||||
SCR1_HDU_DBGSTATE_RESET: begin
|
||||
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & pipe2hdu_init_pc_i & dm2hdu_cmd_req_i;
|
||||
end
|
||||
|
||||
SCR1_HDU_DBGSTATE_RUN: begin
|
||||
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & dfsm_update & dm2hdu_cmd_req_i;
|
||||
end
|
||||
|
||||
SCR1_HDU_DBGSTATE_DHALTED: begin
|
||||
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i ? dfsm_update : dm2hdu_cmd_req_i;
|
||||
end
|
||||
|
||||
SCR1_HDU_DBGSTATE_DRUN: begin
|
||||
hdu2dm_cmd_resp_o = (~pipe2hdu_rdc_qlfy_i | dfsm_update) & dm2hdu_cmd_req_i;
|
||||
end
|
||||
|
||||
default: begin
|
||||
hdu2dm_cmd_resp_o = 'X;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign hdu2dm_pbuf_addr_o = pbuf_addr_ff;
|
||||
assign hdu2dm_dreg_req_o = csr_dscratch0_sel;
|
||||
assign hdu2dm_dreg_wr_o = csr_wr & csr_dscratch0_sel;
|
||||
assign hdu2dm_dreg_wdata_o = csr_wr_data;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HDU <-> EXU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign hdu2exu_dbg_halted_o = (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED)
|
||||
| (~pipe2hdu_rdc_qlfy_i & ~dbg_state_run);
|
||||
assign hdu2exu_dbg_run_start_o = dbg_state_dhalted & pipe2hdu_rdc_qlfy_i & dfsm_update;
|
||||
assign hdu2exu_dbg_halt2run_o = hdu2exu_dbg_halted_o & hart_resume_req
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
& clk_pipe_en
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
;
|
||||
assign hdu2exu_dbg_run2halt_o = hart_halt_ack;
|
||||
|
||||
assign hdu2exu_pbuf_fetch_o = hart_runctrl.fetch_src;
|
||||
assign hdu2exu_irq_dsbl_o = hart_runctrl.irq_dsbl;
|
||||
assign hdu2exu_pc_advmt_dsbl_o = hart_runctrl.pc_advmt_dsbl;
|
||||
// No change in arch. state if dmode caused by breakpoint
|
||||
assign hdu2exu_no_commit_o = dmode_cause_ebreak
|
||||
`ifdef SCR1_TDU_EN
|
||||
| dmode_cause_tmreq
|
||||
`endif // SCR1_TDU_EN
|
||||
;
|
||||
assign hdu2exu_dmode_sstep_en_o = hart_runctrl.redirect.sstep;
|
||||
assign hdu2exu_dbg_new_pc_o = csr_dpc_ff;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HDU <-> IFU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign hdu2ifu_pbuf_instr_vd_o = (pbuf_fsm_fetch | pbuf_fsm_excinj)
|
||||
& ~pbuf_instr_wait_latching;
|
||||
assign hdu2ifu_pbuf_instr_err_o = pbuf_fsm_excinj;
|
||||
|
||||
generate if (HART_PBUF_INSTR_REGOUT_EN) begin
|
||||
always_ff @(posedge clk) begin
|
||||
hdu2ifu_pbuf_instr_o <= dm2hdu_pbuf_instr_i;
|
||||
end
|
||||
end else begin
|
||||
assign hdu2ifu_pbuf_instr_o = dm2hdu_pbuf_instr_i;
|
||||
end endgenerate
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// HDU <-> CSR interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_addr_dscratch0 = (csr2hdu_addr_i == SCR1_HDU_DBGCSR_OFFS_DSCRATCH0);
|
||||
|
||||
assign hdu2csr_resp_o = ~dbg_state_drun ? SCR1_CSR_RESP_ER
|
||||
: csr_addr_dscratch0 ? csr_dscratch0_resp
|
||||
: csr2hdu_req_i ? SCR1_CSR_RESP_OK
|
||||
: SCR1_CSR_RESP_ER;
|
||||
assign hdu2csr_rdata_o = csr_rd_data;
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
//------------------------------------------------------------------------------
|
||||
// HDU <-> TDU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign hdu2tdu_hwbrk_dsbl_o = hart_runctrl.hwbrkpt_dsbl;
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
SVA_HDU_XCHECK_COMMON :
|
||||
assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown( {rst_n,clk,clk_en,csr2hdu_req_i,pipe2hdu_rdc_qlfy_i} )
|
||||
)
|
||||
else $error("HDU Error: common signals are in X state");
|
||||
|
||||
SVA_HDU_XCHECK_CSR_INTF :
|
||||
assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
csr2hdu_req_i |-> !$isunknown( {csr2hdu_cmd_i,csr2hdu_addr_i,csr2hdu_wdata_i} )
|
||||
)
|
||||
else $error("HDU Error: CSR i/f is in X state");
|
||||
|
||||
SVA_HDU_XCHECK_DM_INTF :
|
||||
assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown( {dm2hdu_cmd_req_i,dm2hdu_cmd_i,dm2hdu_dreg_resp_i,
|
||||
dm2hdu_dreg_fail_i} )
|
||||
)
|
||||
else $error("HDU Error: DM i/f is in X state");
|
||||
|
||||
SVA_HDU_XCHECK_TDU_INTF :
|
||||
assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown( {tdu2hdu_dmode_req_i,exu2hdu_ibrkpt_hw_i} )
|
||||
)
|
||||
else $error("HDU Error: TDU i/f is in X state");
|
||||
|
||||
SVA_HDU_XCHECK_HART_INTF :
|
||||
assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown( {pipe2hdu_exu_busy_i,pipe2hdu_instret_i,pipe2hdu_init_pc_i,pipe2hdu_exu_exc_req_i,pipe2hdu_brkpt_i,
|
||||
pipe2hdu_pc_curr_i,ifu2hdu_pbuf_instr_rdy_i} )
|
||||
)
|
||||
else $error("HDU Error: HART i/f is in X state");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_hdu
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
720
src_ref/core/pipeline/scr1_pipe_ialu.sv
Normal file
720
src_ref/core/pipeline/scr1_pipe_ialu.sv
Normal file
@@ -0,0 +1,720 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_ialu.sv>
|
||||
/// @brief Integer Arithmetic Logic Unit (IALU)
|
||||
///
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Performs addition/subtraction and arithmetic and branch comparisons
|
||||
// - Performs logical operations (AND(I), OR(I), XOR(I))
|
||||
// - Performs address calculation for branch, jump, DMEM load and store and AUIPC
|
||||
// instructions
|
||||
// - Performs shift operations
|
||||
// - Performs MUL/DIV operations
|
||||
//
|
||||
// Structure:
|
||||
// - Main adder
|
||||
// - Address adder
|
||||
// - Shift logic
|
||||
// - MUL/DIV logic
|
||||
// - Output result multiplexer
|
||||
//
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`include "scr1_search_ms1.svh"
|
||||
|
||||
|
||||
module scr1_pipe_ialu (
|
||||
`ifdef SCR1_RVM_EXT
|
||||
// Common
|
||||
input logic clk, // IALU clock
|
||||
input logic rst_n, // IALU reset
|
||||
input logic exu2ialu_rvm_cmd_vd_i, // MUL/DIV command valid
|
||||
output logic ialu2exu_rvm_res_rdy_o, // MUL/DIV result ready
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
// Main adder
|
||||
input logic [`SCR1_XLEN-1:0] exu2ialu_main_op1_i, // main ALU 1st operand
|
||||
input logic [`SCR1_XLEN-1:0] exu2ialu_main_op2_i, // main ALU 2nd operand
|
||||
input type_scr1_ialu_cmd_sel_e exu2ialu_cmd_i, // IALU command
|
||||
output logic [`SCR1_XLEN-1:0] ialu2exu_main_res_o, // main ALU result
|
||||
output logic ialu2exu_cmp_res_o, // IALU comparison result
|
||||
|
||||
// Address adder
|
||||
input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op1_i, // Address adder 1st operand
|
||||
input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op2_i, // Address adder 2nd operand
|
||||
output logic [`SCR1_XLEN-1:0] ialu2exu_addr_res_o // Address adder result
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local parameters declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
`ifdef SCR1_RVM_EXT
|
||||
`ifdef SCR1_FAST_MUL
|
||||
localparam SCR1_MUL_WIDTH = `SCR1_XLEN;
|
||||
localparam SCR1_MUL_RES_WIDTH = 2 * `SCR1_XLEN;
|
||||
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + 1;
|
||||
`else
|
||||
localparam SCR1_MUL_STG_NUM = 32;
|
||||
localparam SCR1_MUL_WIDTH = 32 / SCR1_MUL_STG_NUM;
|
||||
localparam SCR1_MUL_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_MUL_WIDTH - 2);
|
||||
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + SCR1_MUL_WIDTH;
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
localparam SCR1_DIV_WIDTH = 1;
|
||||
localparam SCR1_DIV_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_DIV_WIDTH - 2);
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
typedef struct packed {
|
||||
logic z; // Zero
|
||||
logic s; // Sign
|
||||
logic o; // Overflow
|
||||
logic c; // Carry
|
||||
} type_scr1_ialu_flags_s;
|
||||
|
||||
`ifdef SCR1_RVM_EXT
|
||||
typedef enum logic [1:0] {
|
||||
SCR1_IALU_MDU_FSM_IDLE,
|
||||
SCR1_IALU_MDU_FSM_ITER,
|
||||
SCR1_IALU_MDU_FSM_CORR
|
||||
} type_scr1_ialu_fsm_state;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
SCR1_IALU_MDU_NONE,
|
||||
SCR1_IALU_MDU_MUL,
|
||||
SCR1_IALU_MDU_DIV
|
||||
} type_scr1_ialu_mdu_cmd;
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// Main adder signals
|
||||
logic [`SCR1_XLEN:0] main_sum_res; // Main adder result
|
||||
type_scr1_ialu_flags_s main_sum_flags; // Main adder flags
|
||||
logic main_sum_pos_ovflw; // Main adder positive overflow
|
||||
logic main_sum_neg_ovflw; // Main adder negative overflow
|
||||
logic main_ops_diff_sgn; // Main adder operands have different signs
|
||||
logic main_ops_non_zero; // Both main adder operands are NOT 0
|
||||
|
||||
// Shifter signals
|
||||
logic ialu_cmd_shft; // IALU command is shift
|
||||
logic signed [`SCR1_XLEN-1:0] shft_op1; // SHIFT operand 1
|
||||
logic [4:0] shft_op2; // SHIFT operand 2
|
||||
logic [1:0] shft_cmd; // SHIFT command: 00 - logical left, 10 - logical right, 11 - arithmetical right
|
||||
logic [`SCR1_XLEN-1:0] shft_res; // SHIFT result
|
||||
|
||||
// MUL/DIV signals
|
||||
`ifdef SCR1_RVM_EXT
|
||||
// MUL/DIV FSM control signals
|
||||
logic mdu_cmd_is_iter; // MDU Command is iterative
|
||||
logic mdu_iter_req; // Request iterative stage
|
||||
logic mdu_iter_rdy; // Iteration is ready
|
||||
logic mdu_corr_req; // DIV/REM(U) correction request
|
||||
logic div_corr_req; // Correction request for DIV operation
|
||||
logic rem_corr_req; // Correction request for REM(U) operations
|
||||
|
||||
// MUL/DIV FSM signals
|
||||
type_scr1_ialu_fsm_state mdu_fsm_ff; // Current FSM state
|
||||
type_scr1_ialu_fsm_state mdu_fsm_next; // Next FSM state
|
||||
logic mdu_fsm_idle; // MDU FSM is in IDLE state
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
logic mdu_fsm_iter; // MDU FSM is in ITER state
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
logic mdu_fsm_corr; // MDU FSM is in CORR state
|
||||
|
||||
// MDU command signals
|
||||
type_scr1_ialu_mdu_cmd mdu_cmd; // MDU command: 00 - NONE, 01 - MUL, 10 - DIV
|
||||
logic mdu_cmd_mul; // MDU command is MUL(HSU)
|
||||
logic mdu_cmd_div; // MDU command is DIV(U)/REM(U)
|
||||
logic [1:0] mul_cmd; // MUL command: 00 - MUL, 01 - MULH, 10 - MULHSU, 11 - MULHU
|
||||
logic mul_cmd_hi; // High part of MUL result is requested
|
||||
logic [1:0] div_cmd; // DIV command: 00 - DIV, 01 - DIVU, 10 - REM, 11 - REMU
|
||||
logic div_cmd_div; // DIV command is DIV
|
||||
logic div_cmd_rem; // DIV command is REM(U)
|
||||
|
||||
// Multiplier signals
|
||||
logic mul_op1_is_sgn; // First MUL operand is signed
|
||||
logic mul_op2_is_sgn; // Second MUL operand is signed
|
||||
logic mul_op1_sgn; // First MUL operand is negative
|
||||
logic mul_op2_sgn; // Second MUL operand is negative
|
||||
logic signed [`SCR1_XLEN:0] mul_op1; // MUL operand 1
|
||||
logic signed [SCR1_MUL_WIDTH:0] mul_op2; // MUL operand 1
|
||||
`ifdef SCR1_FAST_MUL
|
||||
logic signed [SCR1_MUL_RES_WIDTH-1:0] mul_res; // MUL result
|
||||
`else // ~SCR1_FAST_MUL
|
||||
logic signed [SCR1_MDU_SUM_WIDTH:0] mul_part_prod;
|
||||
logic [`SCR1_XLEN-1:0] mul_res_hi;
|
||||
logic [`SCR1_XLEN-1:0] mul_res_lo;
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
|
||||
// Divisor signals
|
||||
logic div_ops_are_sgn;
|
||||
logic div_op1_is_neg;
|
||||
logic div_op2_is_neg;
|
||||
logic div_res_rem_c;
|
||||
logic [`SCR1_XLEN-1:0] div_res_rem;
|
||||
logic [`SCR1_XLEN-1:0] div_res_quo;
|
||||
logic div_quo_bit;
|
||||
logic div_dvdnd_lo_upd;
|
||||
logic [`SCR1_XLEN-1:0] div_dvdnd_lo_ff;
|
||||
logic [`SCR1_XLEN-1:0] div_dvdnd_lo_next;
|
||||
|
||||
// MDU adder signals
|
||||
logic mdu_sum_sub; // MDU adder operation: 0 - add, 1 - sub
|
||||
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op1; // MDU adder operand 1
|
||||
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op2; // MDU adder operand 2
|
||||
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_res; // MDU adder result
|
||||
|
||||
// MDU iteration counter signals
|
||||
logic mdu_iter_cnt_en;
|
||||
logic [`SCR1_XLEN-1:0] mdu_iter_cnt;
|
||||
logic [`SCR1_XLEN-1:0] mdu_iter_cnt_next;
|
||||
|
||||
// Intermediate results registers
|
||||
logic mdu_res_upd;
|
||||
logic mdu_res_c_ff;
|
||||
logic mdu_res_c_next;
|
||||
logic [`SCR1_XLEN-1:0] mdu_res_hi_ff;
|
||||
logic [`SCR1_XLEN-1:0] mdu_res_hi_next;
|
||||
logic [`SCR1_XLEN-1:0] mdu_res_lo_ff;
|
||||
logic [`SCR1_XLEN-1:0] mdu_res_lo_next;
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Main adder
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Main adder is used for the following types of operations:
|
||||
// - Addition/subtraction (ADD/ADDI/SUB)
|
||||
// - Branch comparisons (BEQ/BNE/BLT(U)/BGE(U))
|
||||
// - Arithmetic comparisons (SLT(U)/SLTI(U))
|
||||
//
|
||||
|
||||
// Carry out (MSB of main_sum_res) is evaluated correctly because the result
|
||||
// width equals to the maximum width of both the right-hand and left-hand side variables
|
||||
always_comb begin
|
||||
main_sum_res = (exu2ialu_cmd_i != SCR1_IALU_CMD_ADD)
|
||||
? ({1'b0, exu2ialu_main_op1_i} - {1'b0, exu2ialu_main_op2_i}) // Subtraction and comparison
|
||||
: ({1'b0, exu2ialu_main_op1_i} + {1'b0, exu2ialu_main_op2_i}); // Addition
|
||||
|
||||
main_sum_pos_ovflw = ~exu2ialu_main_op1_i[`SCR1_XLEN-1]
|
||||
& exu2ialu_main_op2_i[`SCR1_XLEN-1]
|
||||
& main_sum_res[`SCR1_XLEN-1];
|
||||
main_sum_neg_ovflw = exu2ialu_main_op1_i[`SCR1_XLEN-1]
|
||||
& ~exu2ialu_main_op2_i[`SCR1_XLEN-1]
|
||||
& ~main_sum_res[`SCR1_XLEN-1];
|
||||
|
||||
// FLAGS1 - flags for comparison (result of subtraction)
|
||||
main_sum_flags.c = main_sum_res[`SCR1_XLEN];
|
||||
main_sum_flags.z = ~|main_sum_res[`SCR1_XLEN-1:0];
|
||||
main_sum_flags.s = main_sum_res[`SCR1_XLEN-1];
|
||||
main_sum_flags.o = main_sum_pos_ovflw | main_sum_neg_ovflw;
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Address adder
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Additional adder is used for the following types of operations:
|
||||
// - PC-based address calculation (AUIPC)
|
||||
// - IMEM branch address calculation (BEQ/BNE/BLT(U)/BGE(U))
|
||||
// - IMEM jump address calculation (JAL/JALR)
|
||||
// - DMEM load address calculation (LB(U)/LH(U)/LW)
|
||||
// - DMEM store address calculation (SB/SH/SW)
|
||||
//
|
||||
|
||||
assign ialu2exu_addr_res_o = exu2ialu_addr_op1_i + exu2ialu_addr_op2_i;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Shift logic
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Shift logic supports the following types of shift operations:
|
||||
// - Logical left shift (SLLI/SLL)
|
||||
// - Logical right shift (SRLI/SRL)
|
||||
// - Arithmetic right shift (SRAI/SRA)
|
||||
//
|
||||
|
||||
assign ialu_cmd_shft = (exu2ialu_cmd_i == SCR1_IALU_CMD_SLL)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_SRL)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA);
|
||||
assign shft_cmd = ialu_cmd_shft
|
||||
? {(exu2ialu_cmd_i != SCR1_IALU_CMD_SLL),
|
||||
(exu2ialu_cmd_i == SCR1_IALU_CMD_SRA)}
|
||||
: 2'b00;
|
||||
|
||||
always_comb begin
|
||||
shft_op1 = exu2ialu_main_op1_i;
|
||||
shft_op2 = exu2ialu_main_op2_i[4:0];
|
||||
case (shft_cmd)
|
||||
2'b10 : shft_res = shft_op1 >> shft_op2;
|
||||
2'b11 : shft_res = shft_op1 >>> shft_op2;
|
||||
default : shft_res = shft_op1 << shft_op2;
|
||||
endcase
|
||||
end
|
||||
|
||||
`ifdef SCR1_RVM_EXT
|
||||
//-------------------------------------------------------------------------------
|
||||
// MUL/DIV logic
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// MUL/DIV instructions use the following functional units:
|
||||
// - MUL/DIV FSM control logic, including iteration number counter
|
||||
// - MUL/DIV FSM
|
||||
// - MUL logic
|
||||
// - DIV logic
|
||||
// - MDU adder to produce an intermediate result
|
||||
// - 2 registers to save the intermediate result (shared between MUL and DIV
|
||||
// operations)
|
||||
//
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// MUL/DIV FSM Control logic
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
assign mdu_cmd_div = (exu2ialu_cmd_i == SCR1_IALU_CMD_DIV)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_REM)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU);
|
||||
assign mdu_cmd_mul = (exu2ialu_cmd_i == SCR1_IALU_CMD_MUL)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU)
|
||||
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU);
|
||||
|
||||
assign mdu_cmd = mdu_cmd_div ? SCR1_IALU_MDU_DIV
|
||||
: mdu_cmd_mul ? SCR1_IALU_MDU_MUL
|
||||
: SCR1_IALU_MDU_NONE;
|
||||
|
||||
assign main_ops_non_zero = |exu2ialu_main_op1_i & |exu2ialu_main_op2_i;
|
||||
assign main_ops_diff_sgn = exu2ialu_main_op1_i[`SCR1_XLEN-1]
|
||||
^ exu2ialu_main_op2_i[`SCR1_XLEN-1];
|
||||
|
||||
`ifdef SCR1_FAST_MUL
|
||||
assign mdu_cmd_is_iter = mdu_cmd_div;
|
||||
`else // ~SCR1_FAST_MUL
|
||||
assign mdu_cmd_is_iter = mdu_cmd_mul | mdu_cmd_div;
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
|
||||
assign mdu_iter_req = mdu_cmd_is_iter ? (main_ops_non_zero & mdu_fsm_idle) : 1'b0;
|
||||
assign mdu_iter_rdy = mdu_iter_cnt[0];
|
||||
|
||||
assign div_cmd_div = (div_cmd == 2'b00);
|
||||
assign div_cmd_rem = div_cmd[1];
|
||||
|
||||
// Correction request signals
|
||||
assign div_corr_req = div_cmd_div & main_ops_diff_sgn;
|
||||
assign rem_corr_req = div_cmd_rem & |div_res_rem & (div_op1_is_neg ^ div_res_rem_c);
|
||||
assign mdu_corr_req = mdu_cmd_div & (div_corr_req | rem_corr_req);
|
||||
|
||||
// MDU iteration counter
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign mdu_iter_cnt_en = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (mdu_iter_cnt_en) begin
|
||||
mdu_iter_cnt <= mdu_iter_cnt_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign mdu_iter_cnt_next = ~mdu_fsm_idle ? mdu_iter_cnt >> 1
|
||||
: mdu_cmd_div ? SCR1_DIV_CNT_INIT
|
||||
`ifndef SCR1_FAST_MUL
|
||||
: mdu_cmd_mul ? SCR1_MUL_CNT_INIT
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
: mdu_iter_cnt;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// MUL/DIV FSM
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
mdu_fsm_ff <= SCR1_IALU_MDU_FSM_IDLE;
|
||||
end else begin
|
||||
mdu_fsm_ff <= mdu_fsm_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
|
||||
|
||||
if (exu2ialu_rvm_cmd_vd_i) begin
|
||||
case (mdu_fsm_ff)
|
||||
SCR1_IALU_MDU_FSM_IDLE : begin
|
||||
mdu_fsm_next = mdu_iter_req ? SCR1_IALU_MDU_FSM_ITER
|
||||
: SCR1_IALU_MDU_FSM_IDLE;
|
||||
end
|
||||
SCR1_IALU_MDU_FSM_ITER : begin
|
||||
mdu_fsm_next = ~mdu_iter_rdy ? SCR1_IALU_MDU_FSM_ITER
|
||||
: mdu_corr_req ? SCR1_IALU_MDU_FSM_CORR
|
||||
: SCR1_IALU_MDU_FSM_IDLE;
|
||||
end
|
||||
SCR1_IALU_MDU_FSM_CORR : begin
|
||||
mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign mdu_fsm_idle = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_IDLE);
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
assign mdu_fsm_iter = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_ITER);
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
assign mdu_fsm_corr = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_CORR);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Multiplier logic
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Multiplication has 2 options: fast (1 cycle) and Radix-2 (32 cycles) multiplication.
|
||||
//
|
||||
// 1. Fast multiplication uses the straightforward approach when 2 operands are
|
||||
// multiplied in one cycle
|
||||
//
|
||||
// 2. Radix-2 multiplication uses 2 registers (high and low part of multiplication)
|
||||
//
|
||||
// Radix-2 algorithm:
|
||||
// 1. Initialize registers
|
||||
// 2. Create a partial product by multiplying multiplicand by the LSB of multiplier
|
||||
// 3. Add the partial product to the previous (intermediate) value of multiplication
|
||||
// result (stored into high and low parts of multiplication result register)
|
||||
// 4. Shift the low part of multiplication result register right
|
||||
// 4. Store the addition result into the high part of multiplication result register
|
||||
// 6. If iteration is not ready, go to step 2. Otherwise multiplication is done
|
||||
//
|
||||
//
|
||||
|
||||
assign mul_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU)),
|
||||
((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH))};
|
||||
|
||||
assign mul_cmd_hi = |mul_cmd;
|
||||
assign mul_op1_is_sgn = ~&mul_cmd;
|
||||
assign mul_op2_is_sgn = ~mul_cmd[1];
|
||||
assign mul_op1_sgn = mul_op1_is_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
|
||||
assign mul_op2_sgn = mul_op2_is_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
|
||||
|
||||
`ifdef SCR1_FAST_MUL
|
||||
assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
|
||||
assign mul_op2 = mdu_cmd_mul ? $signed({mul_op2_sgn, exu2ialu_main_op2_i}) : '0;
|
||||
assign mul_res = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0);
|
||||
`else // ~SCR1_FAST_MUL
|
||||
assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
|
||||
assign mul_op2 = ~mdu_cmd_mul ? '0
|
||||
: mdu_fsm_idle ? $signed({1'b0, exu2ialu_main_op2_i[SCR1_MUL_WIDTH-1:0]})
|
||||
: $signed({(mdu_iter_cnt[0] & mul_op2_is_sgn & mdu_res_lo_ff[SCR1_MUL_WIDTH-1]),
|
||||
mdu_res_lo_ff[SCR1_MUL_WIDTH-1:0]});
|
||||
|
||||
assign mul_part_prod = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0);
|
||||
assign {mul_res_hi, mul_res_lo} = ~mdu_cmd_mul ? '0
|
||||
: mdu_fsm_idle ? ({mdu_sum_res, exu2ialu_main_op2_i[`SCR1_XLEN-1:SCR1_MUL_WIDTH]})
|
||||
: ({mdu_sum_res, mdu_res_lo_ff[`SCR1_XLEN-1:SCR1_MUL_WIDTH]});
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Divider logic
|
||||
//-------------------------------------------------------------------------------
|
||||
//
|
||||
// Division uses a non-restoring algorithm. 3 registers are used:
|
||||
// - Remainder register
|
||||
// - Quotient register
|
||||
// - Dividend low part register (for corner case quotient bit calculation)
|
||||
//
|
||||
// Algorithm:
|
||||
// 1. Initialize registers
|
||||
// 2. Shift remainder and dividend low part registers left
|
||||
// 3. Compare remainder register with the divisor (taking previous quotient bit
|
||||
// and operands signs into account) and calculate quotient bit based on the
|
||||
// comparison results
|
||||
// 4. Shift quotient register left, append quotient bit to the quotient register
|
||||
// 5. If iteration is not ready, go to step 2. Otherwise go to step 6
|
||||
// 6. Do correction if necessary, otherwise division is done
|
||||
//
|
||||
// Quotient bit calculation has a corner case:
|
||||
// When dividend is negative result carry bit check takes into account only
|
||||
// the case of remainder register been greater than divisor. To handle
|
||||
// equality case we should check if both the comparison result and the
|
||||
// lower part of dividend are zero
|
||||
//
|
||||
|
||||
assign div_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_REM) | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU)),
|
||||
((exu2ialu_cmd_i == SCR1_IALU_CMD_REMU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU))};
|
||||
|
||||
assign div_ops_are_sgn = ~div_cmd[0];
|
||||
assign div_op1_is_neg = div_ops_are_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
|
||||
assign div_op2_is_neg = div_ops_are_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
|
||||
|
||||
always_comb begin
|
||||
div_res_rem_c = '0;
|
||||
div_res_rem = '0;
|
||||
div_res_quo = '0;
|
||||
div_quo_bit = 1'b0;
|
||||
if (mdu_cmd_div & ~mdu_fsm_corr) begin
|
||||
div_res_rem_c = mdu_sum_res[SCR1_MDU_SUM_WIDTH-1];
|
||||
div_res_rem = mdu_sum_res[SCR1_MDU_SUM_WIDTH-2:0];
|
||||
div_quo_bit = ~(div_op1_is_neg ^ div_res_rem_c)
|
||||
| (div_op1_is_neg & ({mdu_sum_res, div_dvdnd_lo_next} == '0));
|
||||
div_res_quo = mdu_fsm_idle
|
||||
? {'0, div_quo_bit}
|
||||
: {mdu_res_lo_ff[`SCR1_XLEN-2:0], div_quo_bit};
|
||||
end
|
||||
end
|
||||
|
||||
// Dividend low part register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign div_dvdnd_lo_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (div_dvdnd_lo_upd) begin
|
||||
div_dvdnd_lo_ff <= div_dvdnd_lo_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign div_dvdnd_lo_next = (~mdu_cmd_div | mdu_fsm_corr) ? '0
|
||||
: mdu_fsm_idle ? exu2ialu_main_op1_i << 1
|
||||
: div_dvdnd_lo_ff << 1;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// MDU adder
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
mdu_sum_sub = 1'b0;
|
||||
mdu_sum_op1 = '0;
|
||||
mdu_sum_op2 = '0;
|
||||
case (mdu_cmd)
|
||||
SCR1_IALU_MDU_DIV : begin
|
||||
logic sgn;
|
||||
logic inv;
|
||||
|
||||
sgn = mdu_fsm_corr ? div_op1_is_neg ^ mdu_res_c_ff
|
||||
: mdu_fsm_idle ? 1'b0
|
||||
: ~mdu_res_lo_ff[0];
|
||||
inv = div_ops_are_sgn & main_ops_diff_sgn;
|
||||
mdu_sum_sub = ~inv ^ sgn;
|
||||
mdu_sum_op1 = mdu_fsm_corr ? $signed({1'b0, mdu_res_hi_ff})
|
||||
: mdu_fsm_idle ? $signed({div_op1_is_neg, exu2ialu_main_op1_i[`SCR1_XLEN-1]})
|
||||
: $signed({mdu_res_hi_ff, div_dvdnd_lo_ff[`SCR1_XLEN-1]});
|
||||
mdu_sum_op2 = $signed({div_op2_is_neg, exu2ialu_main_op2_i});
|
||||
end
|
||||
`ifndef SCR1_FAST_MUL
|
||||
SCR1_IALU_MDU_MUL : begin
|
||||
mdu_sum_op1 = mdu_fsm_idle
|
||||
? '0
|
||||
: $signed({(mul_op1_is_sgn & mdu_res_hi_ff[`SCR1_XLEN-1]), mdu_res_hi_ff});
|
||||
mdu_sum_op2 = mul_part_prod;
|
||||
end
|
||||
`endif // SCR1_FAST_MUL
|
||||
default : begin end
|
||||
endcase
|
||||
mdu_sum_res = mdu_sum_sub
|
||||
? (mdu_sum_op1 - mdu_sum_op2)
|
||||
: (mdu_sum_op1 + mdu_sum_op2);
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// MUL/DIV intermediate results registers
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
assign mdu_res_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (mdu_res_upd) begin
|
||||
mdu_res_c_ff <= mdu_res_c_next;
|
||||
mdu_res_hi_ff <= mdu_res_hi_next;
|
||||
mdu_res_lo_ff <= mdu_res_lo_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign mdu_res_c_next = mdu_cmd_div ? div_res_rem_c : mdu_res_c_ff;
|
||||
assign mdu_res_hi_next = mdu_cmd_div ? div_res_rem
|
||||
`ifndef SCR1_FAST_MUL
|
||||
: mdu_cmd_mul ? mul_res_hi
|
||||
`endif // SCR1_FAST_MUL
|
||||
: mdu_res_hi_ff;
|
||||
assign mdu_res_lo_next = mdu_cmd_div ? div_res_quo
|
||||
`ifndef SCR1_FAST_MUL
|
||||
: mdu_cmd_mul ? mul_res_lo
|
||||
`endif // SCR1_FAST_MUL
|
||||
: mdu_res_lo_ff;
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Operation result forming
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
ialu2exu_main_res_o = '0;
|
||||
ialu2exu_cmp_res_o = 1'b0;
|
||||
`ifdef SCR1_RVM_EXT
|
||||
ialu2exu_rvm_res_rdy_o = 1'b1;
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
case (exu2ialu_cmd_i)
|
||||
SCR1_IALU_CMD_AND : begin
|
||||
ialu2exu_main_res_o = exu2ialu_main_op1_i & exu2ialu_main_op2_i;
|
||||
end
|
||||
SCR1_IALU_CMD_OR : begin
|
||||
ialu2exu_main_res_o = exu2ialu_main_op1_i | exu2ialu_main_op2_i;
|
||||
end
|
||||
SCR1_IALU_CMD_XOR : begin
|
||||
ialu2exu_main_res_o = exu2ialu_main_op1_i ^ exu2ialu_main_op2_i;
|
||||
end
|
||||
SCR1_IALU_CMD_ADD : begin
|
||||
ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
|
||||
end
|
||||
SCR1_IALU_CMD_SUB : begin
|
||||
ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_LT : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.s ^ main_sum_flags.o);
|
||||
ialu2exu_cmp_res_o = main_sum_flags.s ^ main_sum_flags.o;
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_LTU : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.c);
|
||||
ialu2exu_cmp_res_o = main_sum_flags.c;
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_EQ : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.z);
|
||||
ialu2exu_cmp_res_o = main_sum_flags.z;
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_NE : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.z);
|
||||
ialu2exu_cmp_res_o = ~main_sum_flags.z;
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_GE : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(~(main_sum_flags.s ^ main_sum_flags.o));
|
||||
ialu2exu_cmp_res_o = ~(main_sum_flags.s ^ main_sum_flags.o);
|
||||
end
|
||||
SCR1_IALU_CMD_SUB_GEU : begin
|
||||
ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.c);
|
||||
ialu2exu_cmp_res_o = ~main_sum_flags.c;
|
||||
end
|
||||
SCR1_IALU_CMD_SLL,
|
||||
SCR1_IALU_CMD_SRL,
|
||||
SCR1_IALU_CMD_SRA: begin
|
||||
ialu2exu_main_res_o = shft_res;
|
||||
end
|
||||
`ifdef SCR1_RVM_EXT
|
||||
SCR1_IALU_CMD_MUL,
|
||||
SCR1_IALU_CMD_MULHU,
|
||||
SCR1_IALU_CMD_MULHSU,
|
||||
SCR1_IALU_CMD_MULH : begin
|
||||
`ifdef SCR1_FAST_MUL
|
||||
ialu2exu_main_res_o = mul_cmd_hi
|
||||
? mul_res[SCR1_MUL_RES_WIDTH-1:`SCR1_XLEN]
|
||||
: mul_res[`SCR1_XLEN-1:0];
|
||||
`else // ~SCR1_FAST_MUL
|
||||
case (mdu_fsm_ff)
|
||||
SCR1_IALU_MDU_FSM_IDLE : begin
|
||||
ialu2exu_main_res_o = '0;
|
||||
ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
|
||||
end
|
||||
SCR1_IALU_MDU_FSM_ITER : begin
|
||||
ialu2exu_main_res_o = mul_cmd_hi ? mul_res_hi : mul_res_lo;
|
||||
ialu2exu_rvm_res_rdy_o = mdu_iter_rdy;
|
||||
end
|
||||
endcase
|
||||
`endif // ~SCR1_FAST_MUL
|
||||
end
|
||||
SCR1_IALU_CMD_DIV,
|
||||
SCR1_IALU_CMD_DIVU,
|
||||
SCR1_IALU_CMD_REM,
|
||||
SCR1_IALU_CMD_REMU : begin
|
||||
case (mdu_fsm_ff)
|
||||
SCR1_IALU_MDU_FSM_IDLE : begin
|
||||
ialu2exu_main_res_o = (|exu2ialu_main_op2_i | div_cmd_rem)
|
||||
? exu2ialu_main_op1_i
|
||||
: '1;
|
||||
ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
|
||||
end
|
||||
SCR1_IALU_MDU_FSM_ITER : begin
|
||||
ialu2exu_main_res_o = div_cmd_rem ? div_res_rem : div_res_quo;
|
||||
ialu2exu_rvm_res_rdy_o = mdu_iter_rdy & ~mdu_corr_req;
|
||||
end
|
||||
SCR1_IALU_MDU_FSM_CORR : begin
|
||||
ialu2exu_main_res_o = div_cmd_rem
|
||||
? mdu_sum_res[`SCR1_XLEN-1:0]
|
||||
: -mdu_res_lo_ff[`SCR1_XLEN-1:0];
|
||||
ialu2exu_rvm_res_rdy_o = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
`endif // SCR1_RVM_EXT
|
||||
default : begin end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
`ifdef SCR1_RVM_EXT
|
||||
|
||||
// X checks
|
||||
|
||||
SCR1_SVA_IALU_XCHECK : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({exu2ialu_rvm_cmd_vd_i, mdu_fsm_ff})
|
||||
) else $error("IALU Error: unknown values");
|
||||
|
||||
SCR1_SVA_IALU_XCHECK_QUEUE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
exu2ialu_rvm_cmd_vd_i |->
|
||||
!$isunknown({exu2ialu_main_op1_i, exu2ialu_main_op2_i, exu2ialu_cmd_i})
|
||||
) else $error("IALU Error: unknown values in queue");
|
||||
|
||||
// Behavior checks
|
||||
|
||||
SCR1_SVA_IALU_ILL_STATE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
$onehot0({~exu2ialu_rvm_cmd_vd_i, mdu_fsm_iter, mdu_fsm_corr})
|
||||
) else $error("IALU Error: illegal state");
|
||||
|
||||
SCR1_SVA_IALU_JUMP_FROM_IDLE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(mdu_fsm_idle & (~exu2ialu_rvm_cmd_vd_i | ~mdu_iter_req)) |=> mdu_fsm_idle
|
||||
) else $error("EXU Error: illegal jump from IDLE state");
|
||||
|
||||
SCR1_SVA_IALU_IDLE_TO_ITER : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(mdu_fsm_idle & exu2ialu_rvm_cmd_vd_i & mdu_iter_req) |=> mdu_fsm_iter
|
||||
) else $error("EXU Error: illegal change state form IDLE to ITER");
|
||||
|
||||
SCR1_SVA_IALU_JUMP_FROM_ITER : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(mdu_fsm_iter & ~mdu_iter_rdy) |=> mdu_fsm_iter
|
||||
) else $error("EXU Error: illegal jump from ITER state");
|
||||
|
||||
SCR1_SVA_IALU_ITER_TO_IDLE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(mdu_fsm_iter & mdu_iter_rdy & ~mdu_corr_req) |=> mdu_fsm_idle
|
||||
) else $error("EXU Error: illegal state change ITER to IDLE");
|
||||
|
||||
SCR1_SVA_IALU_ITER_TO_CORR : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(mdu_fsm_iter & mdu_iter_rdy & mdu_corr_req) |=> mdu_fsm_corr
|
||||
) else $error("EXU Error: illegal state change ITER to CORR");
|
||||
|
||||
SCR1_SVA_IALU_CORR_TO_IDLE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
mdu_fsm_corr |=> mdu_fsm_idle
|
||||
) else $error("EXU Error: illegal state stay in CORR");
|
||||
|
||||
`endif // SCR1_RVM_EXT
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_ialu
|
||||
940
src_ref/core/pipeline/scr1_pipe_idu.sv
Normal file
940
src_ref/core/pipeline/scr1_pipe_idu.sv
Normal file
@@ -0,0 +1,940 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_idu.sv>
|
||||
/// @brief Instruction Decoder Unit (IDU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Decodes the instruction and creates the appropriate control signals for EXU
|
||||
//
|
||||
// Structure:
|
||||
// - Instruction decoder
|
||||
// - IDU <-> IFU i/f
|
||||
// - IDU <-> EXU i/f
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_memif.svh"
|
||||
`include "scr1_arch_types.svh"
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
module scr1_pipe_idu
|
||||
(
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
input logic rst_n, // IDU reset
|
||||
input logic clk, // IDU clock
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
// IFU <-> IDU interface
|
||||
output logic idu2ifu_rdy_o, // IDU ready for new data
|
||||
input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_i, // IFU instruction
|
||||
input logic ifu2idu_imem_err_i, // Instruction access fault exception
|
||||
input logic ifu2idu_err_rvi_hi_i, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
|
||||
input logic ifu2idu_vd_i, // IFU request
|
||||
|
||||
// IDU <-> EXU interface
|
||||
output logic idu2exu_req_o, // IDU request
|
||||
output type_scr1_exu_cmd_s idu2exu_cmd_o, // IDU command
|
||||
output logic idu2exu_use_rs1_o, // Instruction uses rs1
|
||||
output logic idu2exu_use_rs2_o, // Instruction uses rs2
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
output logic idu2exu_use_rd_o, // Instruction uses rd
|
||||
output logic idu2exu_use_imm_o, // Instruction uses immediate
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
input logic exu2idu_rdy_i // EXU ready for new data
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local parameters declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_ZERO_ADDR = 5'd0;
|
||||
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_RA_ADDR = 5'd1;
|
||||
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_SP_ADDR = 5'd2;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
logic [`SCR1_IMEM_DWIDTH-1:0] instr;
|
||||
type_scr1_instr_type_e instr_type;
|
||||
type_scr1_rvi_opcode_e rvi_opcode;
|
||||
logic rvi_illegal;
|
||||
logic [2:0] funct3;
|
||||
logic [6:0] funct7;
|
||||
logic [11:0] funct12;
|
||||
logic [4:0] shamt;
|
||||
`ifdef SCR1_RVC_EXT
|
||||
logic rvc_illegal;
|
||||
`endif // SCR1_RVC_EXT
|
||||
`ifdef SCR1_RVE_EXT
|
||||
logic rve_illegal;
|
||||
`endif // SCR1_RVE_EXT
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Instruction decoding
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
assign idu2ifu_rdy_o = exu2idu_rdy_i;
|
||||
assign idu2exu_req_o = ifu2idu_vd_i;
|
||||
assign instr = ifu2idu_instr_i;
|
||||
|
||||
// RVI / RVC
|
||||
assign instr_type = type_scr1_instr_type_e'(instr[1:0]);
|
||||
|
||||
// RVI / RVC fields
|
||||
assign rvi_opcode = type_scr1_rvi_opcode_e'(instr[6:2]); // RVI
|
||||
assign funct3 = (instr_type == SCR1_INSTR_RVI) ? instr[14:12] : instr[15:13]; // RVI / RVC
|
||||
assign funct7 = instr[31:25]; // RVI
|
||||
assign funct12 = instr[31:20]; // RVI (SYSTEM)
|
||||
assign shamt = instr[24:20]; // RVI
|
||||
|
||||
// RV32I(MC) decode
|
||||
always_comb begin
|
||||
// Defaults
|
||||
idu2exu_cmd_o.instr_rvc = 1'b0;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE;
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE;
|
||||
idu2exu_cmd_o.jump_req = 1'b0;
|
||||
idu2exu_cmd_o.branch_req = 1'b0;
|
||||
idu2exu_cmd_o.mret_req = 1'b0;
|
||||
idu2exu_cmd_o.fencei_req = 1'b0;
|
||||
idu2exu_cmd_o.wfi_req = 1'b0;
|
||||
idu2exu_cmd_o.rs1_addr = '0;
|
||||
idu2exu_cmd_o.rs2_addr = '0;
|
||||
idu2exu_cmd_o.rd_addr = '0;
|
||||
idu2exu_cmd_o.imm = '0;
|
||||
idu2exu_cmd_o.exc_req = 1'b0;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_MISALIGN;
|
||||
|
||||
// Clock gating
|
||||
idu2exu_use_rs1_o = 1'b0;
|
||||
idu2exu_use_rs2_o = 1'b0;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b0;
|
||||
idu2exu_use_imm_o = 1'b0;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
|
||||
rvi_illegal = 1'b0;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
rve_illegal = 1'b0;
|
||||
`endif // SCR1_RVE_EXT
|
||||
`ifdef SCR1_RVC_EXT
|
||||
rvc_illegal = 1'b0;
|
||||
`endif // SCR1_RVC_EXT
|
||||
|
||||
// Check for IMEM access fault
|
||||
if (ifu2idu_imem_err_i) begin
|
||||
idu2exu_cmd_o.exc_req = 1'b1;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_ACCESS_FAULT;
|
||||
idu2exu_cmd_o.instr_rvc = ifu2idu_err_rvi_hi_i;
|
||||
end else begin // no imem fault
|
||||
case (instr_type)
|
||||
SCR1_INSTR_RVI : begin
|
||||
idu2exu_cmd_o.rs1_addr = instr[19:15];
|
||||
idu2exu_cmd_o.rs2_addr = instr[24:20];
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
case (rvi_opcode)
|
||||
SCR1_OPCODE_AUIPC : begin
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_SUM2;
|
||||
idu2exu_cmd_o.imm = {instr[31:12], 12'b0};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_AUIPC
|
||||
|
||||
SCR1_OPCODE_LUI : begin
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
|
||||
idu2exu_cmd_o.imm = {instr[31:12], 12'b0};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_LUI
|
||||
|
||||
SCR1_OPCODE_JAL : begin
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.imm = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_JAL
|
||||
|
||||
SCR1_OPCODE_LOAD : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
|
||||
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LB;
|
||||
3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LH;
|
||||
3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
|
||||
3'b100 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LBU;
|
||||
3'b101 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LHU;
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_LOAD
|
||||
|
||||
SCR1_OPCODE_STORE : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:25], instr[11:7]};
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SB;
|
||||
3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SH;
|
||||
3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[19] | instr[24]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_STORE
|
||||
|
||||
SCR1_OPCODE_OP : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
case (funct7)
|
||||
7'b0000000 : begin
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
|
||||
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT;
|
||||
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU;
|
||||
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR;
|
||||
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
|
||||
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR;
|
||||
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
|
||||
endcase // funct3
|
||||
end // 7'b0000000
|
||||
|
||||
7'b0100000 : begin
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB;
|
||||
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
end // 7'b0100000
|
||||
`ifdef SCR1_RVM_EXT
|
||||
7'b0000001 : begin
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MUL;
|
||||
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULH;
|
||||
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHSU;
|
||||
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHU;
|
||||
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIV;
|
||||
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIVU;
|
||||
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REM;
|
||||
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REMU;
|
||||
endcase // funct3
|
||||
end // 7'b0000001
|
||||
`endif // SCR1_RVM_EXT
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct7
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19] | instr[24]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_OP
|
||||
|
||||
SCR1_OPCODE_OP_IMM : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; // ADDI
|
||||
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT; // SLTI
|
||||
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU; // SLTIU
|
||||
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR; // XORI
|
||||
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR; // ORI
|
||||
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; // ANDI
|
||||
3'b001 : begin
|
||||
case (funct7)
|
||||
7'b0000000 : begin
|
||||
// SLLI
|
||||
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct7
|
||||
end
|
||||
3'b101 : begin
|
||||
case (funct7)
|
||||
7'b0000000 : begin
|
||||
// SRLI
|
||||
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
|
||||
end
|
||||
7'b0100000 : begin
|
||||
// SRAI
|
||||
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct7
|
||||
end
|
||||
endcase // funct3
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_OP_IMM
|
||||
|
||||
SCR1_OPCODE_MISC_MEM : begin
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
if (~|{instr[31:28], instr[19:15], instr[11:7]}) begin
|
||||
// FENCE = NOP
|
||||
end
|
||||
else rvi_illegal = 1'b1;
|
||||
end
|
||||
3'b001 : begin
|
||||
if (~|{instr[31:15], instr[11:7]}) begin
|
||||
// FENCE.I
|
||||
idu2exu_cmd_o.fencei_req = 1'b1;
|
||||
end
|
||||
else rvi_illegal = 1'b1;
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
end // SCR1_OPCODE_MISC_MEM
|
||||
|
||||
SCR1_OPCODE_BRANCH : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
|
||||
idu2exu_cmd_o.branch_req = 1'b1;
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
case (funct3)
|
||||
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ;
|
||||
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE;
|
||||
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT;
|
||||
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GE;
|
||||
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU;
|
||||
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GEU;
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[19] | instr[24]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_BRANCH
|
||||
|
||||
SCR1_OPCODE_JALR : begin
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
// JALR
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end // SCR1_OPCODE_JALR
|
||||
|
||||
SCR1_OPCODE_SYSTEM : begin
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = `SCR1_XLEN'({funct3, instr[31:20]}); // {funct3, CSR address}
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b0;
|
||||
idu2exu_use_imm_o = 1'b0;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
case ({instr[19:15], instr[11:7]})
|
||||
10'd0 : begin
|
||||
case (funct12)
|
||||
12'h000 : begin
|
||||
// ECALL
|
||||
idu2exu_cmd_o.exc_req = 1'b1;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ECALL_M;
|
||||
end
|
||||
12'h001 : begin
|
||||
// EBREAK
|
||||
idu2exu_cmd_o.exc_req = 1'b1;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT;
|
||||
end
|
||||
12'h302 : begin
|
||||
// MRET
|
||||
idu2exu_cmd_o.mret_req = 1'b1;
|
||||
end
|
||||
12'h105 : begin
|
||||
// WFI
|
||||
idu2exu_cmd_o.wfi_req = 1'b1;
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct12
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // {instr[19:15], instr[11:7]}
|
||||
end
|
||||
3'b001 : begin
|
||||
// CSRRW
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b010 : begin
|
||||
// CSRRS
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b011 : begin
|
||||
// CSRRC
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11] | instr[19]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b101 : begin
|
||||
// CSRRWI
|
||||
idu2exu_use_rs1_o = 1'b1; // zimm
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b110 : begin
|
||||
// CSRRSI
|
||||
idu2exu_use_rs1_o = 1'b1; // zimm
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b111 : begin
|
||||
// CSRRCI
|
||||
idu2exu_use_rs1_o = 1'b1; // zimm
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR;
|
||||
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
default : rvi_illegal = 1'b1;
|
||||
endcase // funct3
|
||||
end // SCR1_OPCODE_SYSTEM
|
||||
|
||||
default : begin
|
||||
rvi_illegal = 1'b1;
|
||||
end
|
||||
endcase // rvi_opcode
|
||||
end // SCR1_INSTR_RVI
|
||||
|
||||
`ifdef SCR1_RVC_EXT
|
||||
|
||||
// Quadrant 0
|
||||
SCR1_INSTR_RVC0 : begin
|
||||
idu2exu_cmd_o.instr_rvc = 1'b1;
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
if (~|instr[12:5]) rvc_illegal = 1'b1;
|
||||
// C.ADDI4SPN
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
|
||||
idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]};
|
||||
idu2exu_cmd_o.imm = {22'd0, instr[10:7], instr[12:11], instr[5], instr[6], 2'b00};
|
||||
end
|
||||
3'b010 : begin
|
||||
// C.LW
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
|
||||
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]};
|
||||
idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
|
||||
end
|
||||
3'b110 : begin
|
||||
// C.SW
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
|
||||
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]};
|
||||
idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
|
||||
end
|
||||
default : begin
|
||||
rvc_illegal = 1'b1;
|
||||
end
|
||||
endcase // funct3
|
||||
end // Quadrant 0
|
||||
|
||||
// Quadrant 1
|
||||
SCR1_INSTR_RVC1 : begin
|
||||
idu2exu_cmd_o.instr_rvc = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
// C.ADDI / C.NOP
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.rs1_addr = instr[11:7];
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b001 : begin
|
||||
// C.JAL
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR;
|
||||
idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
|
||||
end
|
||||
3'b010 : begin
|
||||
// C.LI
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b011 : begin
|
||||
if (~|{instr[12], instr[6:2]}) rvc_illegal = 1'b1;
|
||||
if (instr[11:7] == SCR1_MPRF_SP_ADDR) begin
|
||||
// C.ADDI16SP
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
|
||||
idu2exu_cmd_o.rd_addr = SCR1_MPRF_SP_ADDR;
|
||||
idu2exu_cmd_o.imm = {{23{instr[12]}}, instr[4:3], instr[5], instr[2], instr[6], 4'd0};
|
||||
end else begin
|
||||
// C.LUI
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = {{15{instr[12]}}, instr[6:2], 12'd0};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
end
|
||||
3'b100 : begin
|
||||
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rd_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]};
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
case (instr[11:10])
|
||||
2'b00 : begin
|
||||
if (instr[12]) rvc_illegal = 1'b1;
|
||||
// C.SRLI
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
2'b01 : begin
|
||||
if (instr[12]) rvc_illegal = 1'b1;
|
||||
// C.SRAI
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
2'b10 : begin
|
||||
// C.ANDI
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
|
||||
end
|
||||
2'b11 : begin
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
case ({instr[12], instr[6:5]})
|
||||
3'b000 : begin
|
||||
// C.SUB
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
3'b001 : begin
|
||||
// C.XOR
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
3'b010 : begin
|
||||
// C.OR
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
3'b011 : begin
|
||||
// C.AND
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
end
|
||||
default : begin
|
||||
rvc_illegal = 1'b1;
|
||||
end
|
||||
endcase // {instr[12], instr[6:5]}
|
||||
end
|
||||
endcase // instr[11:10]
|
||||
end // funct3 == 3'b100
|
||||
3'b101 : begin
|
||||
// C.J
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
|
||||
end
|
||||
3'b110 : begin
|
||||
// C.BEQZ
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.branch_req = 1'b1;
|
||||
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR;
|
||||
idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
|
||||
end
|
||||
3'b111 : begin
|
||||
// C.BNEZ
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
|
||||
idu2exu_cmd_o.branch_req = 1'b1;
|
||||
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
|
||||
idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR;
|
||||
idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
|
||||
end
|
||||
endcase // funct3
|
||||
end // Quadrant 1
|
||||
|
||||
// Quadrant 2
|
||||
SCR1_INSTR_RVC2 : begin
|
||||
idu2exu_cmd_o.instr_rvc = 1'b1;
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
case (funct3)
|
||||
3'b000 : begin
|
||||
if (instr[12]) rvc_illegal = 1'b1;
|
||||
// C.SLLI
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.rs1_addr = instr[11:7];
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b010 : begin
|
||||
if (~|instr[11:7]) rvc_illegal = 1'b1;
|
||||
// C.LWSP
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
|
||||
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = {24'd0, instr[3:2], instr[12], instr[6:4], 2'b00};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
3'b100 : begin
|
||||
if (~instr[12]) begin
|
||||
if (|instr[6:2]) begin
|
||||
// C.MV
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_ZERO_ADDR;
|
||||
idu2exu_cmd_o.rs2_addr = instr[6:2];
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]|instr[6]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end else begin
|
||||
if (~|instr[11:7]) rvc_illegal = 1'b1;
|
||||
// C.JR
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.rs1_addr = instr[11:7];
|
||||
idu2exu_cmd_o.imm = 0;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
end else begin // instr[12] == 1
|
||||
if (~|instr[11:2]) begin
|
||||
// C.EBREAK
|
||||
idu2exu_cmd_o.exc_req = 1'b1;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT;
|
||||
end else if (~|instr[6:2]) begin
|
||||
// C.JALR
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
|
||||
idu2exu_cmd_o.jump_req = 1'b1;
|
||||
idu2exu_cmd_o.rs1_addr = instr[11:7];
|
||||
idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR;
|
||||
idu2exu_cmd_o.imm = 0;
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end else begin
|
||||
// C.ADD
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
|
||||
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
|
||||
idu2exu_cmd_o.rs1_addr = instr[11:7];
|
||||
idu2exu_cmd_o.rs2_addr = instr[6:2];
|
||||
idu2exu_cmd_o.rd_addr = instr[11:7];
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[11]|instr[6]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
end // instr[12] == 1
|
||||
end
|
||||
3'b110 : begin
|
||||
// C.SWSP
|
||||
idu2exu_use_rs1_o = 1'b1;
|
||||
idu2exu_use_rs2_o = 1'b1;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
|
||||
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
|
||||
idu2exu_cmd_o.rs2_addr = instr[6:2];
|
||||
idu2exu_cmd_o.imm = {24'd0, instr[8:7], instr[12:9], 2'b00};
|
||||
`ifdef SCR1_RVE_EXT
|
||||
if (instr[6]) rve_illegal = 1'b1;
|
||||
`endif // SCR1_RVE_EXT
|
||||
end
|
||||
default : begin
|
||||
rvc_illegal = 1'b1;
|
||||
end
|
||||
endcase // funct3
|
||||
end // Quadrant 2
|
||||
|
||||
default : begin
|
||||
`ifdef SCR1_XPROP_EN
|
||||
rvi_illegal = 1'b1;
|
||||
`endif // SCR1_XPROP_EN
|
||||
end
|
||||
`else // SCR1_RVC_EXT
|
||||
default : begin
|
||||
idu2exu_cmd_o.instr_rvc = 1'b1;
|
||||
rvi_illegal = 1'b1;
|
||||
end
|
||||
`endif // SCR1_RVC_EXT
|
||||
endcase // instr_type
|
||||
end // no imem fault
|
||||
|
||||
// At this point the instruction is fully decoded
|
||||
// given that no imem fault has happened
|
||||
|
||||
// Check illegal instruction
|
||||
if (
|
||||
rvi_illegal
|
||||
`ifdef SCR1_RVC_EXT
|
||||
| rvc_illegal
|
||||
`endif
|
||||
`ifdef SCR1_RVE_EXT
|
||||
| rve_illegal
|
||||
`endif
|
||||
) begin
|
||||
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE;
|
||||
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE;
|
||||
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE;
|
||||
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE;
|
||||
idu2exu_cmd_o.jump_req = 1'b0;
|
||||
idu2exu_cmd_o.branch_req = 1'b0;
|
||||
idu2exu_cmd_o.mret_req = 1'b0;
|
||||
idu2exu_cmd_o.fencei_req = 1'b0;
|
||||
idu2exu_cmd_o.wfi_req = 1'b0;
|
||||
|
||||
idu2exu_use_rs1_o = 1'b0;
|
||||
idu2exu_use_rs2_o = 1'b0;
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_rd_o = 1'b0;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
|
||||
`ifndef SCR1_MTVAL_ILLEGAL_INSTR_EN
|
||||
idu2exu_use_imm_o = 1'b0;
|
||||
`else // SCR1_MTVAL_ILLEGAL_INSTR_EN
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
idu2exu_use_imm_o = 1'b1;
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
idu2exu_cmd_o.imm = instr;
|
||||
`endif // SCR1_MTVAL_ILLEGAL_INSTR_EN
|
||||
|
||||
idu2exu_cmd_o.exc_req = 1'b1;
|
||||
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ILLEGAL_INSTR;
|
||||
end
|
||||
|
||||
end // RV32I(MC) decode
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// X checks
|
||||
|
||||
SCR1_SVA_IDU_XCHECK : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({ifu2idu_vd_i, exu2idu_rdy_i})
|
||||
) else $error("IDU Error: unknown values");
|
||||
|
||||
// Behavior checks
|
||||
|
||||
SCR1_SVA_IDU_IALU_CMD_RANGE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(ifu2idu_vd_i & ~ifu2idu_imem_err_i) |->
|
||||
((idu2exu_cmd_o.ialu_cmd >= SCR1_IALU_CMD_NONE) &
|
||||
(idu2exu_cmd_o.ialu_cmd <=
|
||||
`ifdef SCR1_RVM_EXT
|
||||
SCR1_IALU_CMD_REMU
|
||||
`else
|
||||
SCR1_IALU_CMD_SRA
|
||||
`endif // SCR1_RVM_EXT
|
||||
))
|
||||
) else $error("IDU Error: IALU_CMD out of range");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_idu
|
||||
826
src_ref/core/pipeline/scr1_pipe_ifu.sv
Normal file
826
src_ref/core/pipeline/scr1_pipe_ifu.sv
Normal file
@@ -0,0 +1,826 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_ifu.sv>
|
||||
/// @brief Instruction Fetch Unit (IFU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Controls instruction fetching process:
|
||||
// - Fetches instructions either from IMEM or from Program Buffer, supporting
|
||||
// pending IMEM instructions handling
|
||||
// - Handles new PC misalignment and constructs the correct instruction (supports
|
||||
// RVI and RVC instructions)
|
||||
// - Either stores instructions in the instruction queue or bypasses to the
|
||||
// IDU if the corresponding option is used
|
||||
// - Flushes instruction queue if requested
|
||||
//
|
||||
// Structure:
|
||||
// - Instruction queue
|
||||
// - IFU FSM
|
||||
// - IFU <-> IMEM i/f
|
||||
// - IFU <-> IDU i/f
|
||||
// - IFU <-> HDU i/f
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_memif.svh"
|
||||
`include "scr1_arch_description.svh"
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_hdu.svh"
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
module scr1_pipe_ifu
|
||||
(
|
||||
// Control signals
|
||||
input logic rst_n, // IFU reset
|
||||
input logic clk, // IFU clock
|
||||
input logic pipe2ifu_stop_fetch_i, // Stop instruction fetch
|
||||
|
||||
// IFU <-> IMEM interface
|
||||
input logic imem2ifu_req_ack_i, // Instruction memory request acknowledgement
|
||||
output logic ifu2imem_req_o, // Instruction memory request
|
||||
output type_scr1_mem_cmd_e ifu2imem_cmd_o, // Instruction memory command (READ/WRITE)
|
||||
output logic [`SCR1_IMEM_AWIDTH-1:0] ifu2imem_addr_o, // Instruction memory address
|
||||
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2ifu_rdata_i, // Instruction memory read data
|
||||
input type_scr1_mem_resp_e imem2ifu_resp_i, // Instruction memory response
|
||||
|
||||
// IFU <-> EXU New PC interface
|
||||
input logic exu2ifu_pc_new_req_i, // New PC request (jumps, branches, traps etc)
|
||||
input logic [`SCR1_XLEN-1:0] exu2ifu_pc_new_i, // New PC
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// IFU <-> HDU Program Buffer interface
|
||||
input logic hdu2ifu_pbuf_fetch_i, // Fetch instructions provided by Program Buffer
|
||||
output logic ifu2hdu_pbuf_rdy_o, // Program Buffer Instruction i/f ready
|
||||
input logic hdu2ifu_pbuf_vd_i, // Program Buffer Instruction valid
|
||||
input logic hdu2ifu_pbuf_err_i, // Program Buffer Instruction i/f error
|
||||
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_i, // Program Buffer Instruction itself
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
output logic ifu2pipe_imem_txns_pnd_o, // There are pending imem transactions
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// IFU <-> IDU interface
|
||||
input logic idu2ifu_rdy_i, // IDU ready for new data
|
||||
output logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_o, // IFU instruction
|
||||
output logic ifu2idu_imem_err_o, // Instruction access fault exception
|
||||
output logic ifu2idu_err_rvi_hi_o, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
|
||||
output logic ifu2idu_vd_o // IFU request
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local parameters declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
localparam SCR1_IFU_Q_SIZE_WORD = 2;
|
||||
localparam SCR1_IFU_Q_SIZE_HALF = SCR1_IFU_Q_SIZE_WORD * 2;
|
||||
localparam SCR1_TXN_CNT_W = 3;
|
||||
|
||||
localparam SCR1_IFU_QUEUE_ADR_W = $clog2(SCR1_IFU_Q_SIZE_HALF);
|
||||
localparam SCR1_IFU_QUEUE_PTR_W = SCR1_IFU_QUEUE_ADR_W + 1;
|
||||
|
||||
localparam SCR1_IFU_Q_FREE_H_W = $clog2(SCR1_IFU_Q_SIZE_HALF + 1);
|
||||
localparam SCR1_IFU_Q_FREE_W_W = $clog2(SCR1_IFU_Q_SIZE_WORD + 1);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef enum logic {
|
||||
SCR1_IFU_FSM_IDLE,
|
||||
SCR1_IFU_FSM_FETCH
|
||||
} type_scr1_ifu_fsm_e;
|
||||
|
||||
typedef enum logic[1:0] {
|
||||
SCR1_IFU_QUEUE_WR_NONE, // No write to queue
|
||||
SCR1_IFU_QUEUE_WR_FULL, // Write 32 rdata bits to queue
|
||||
SCR1_IFU_QUEUE_WR_HI // Write 16 upper rdata bits to queue
|
||||
} type_scr1_ifu_queue_wr_e;
|
||||
|
||||
typedef enum logic[1:0] {
|
||||
SCR1_IFU_QUEUE_RD_NONE, // No queue read
|
||||
SCR1_IFU_QUEUE_RD_HWORD, // Read halfword
|
||||
SCR1_IFU_QUEUE_RD_WORD // Read word
|
||||
} type_scr1_ifu_queue_rd_e;
|
||||
|
||||
`ifdef SCR1_NO_DEC_STAGE
|
||||
typedef enum logic[1:0] {
|
||||
SCR1_BYPASS_NONE, // No bypass
|
||||
SCR1_BYPASS_RVC, // Bypass RVC
|
||||
SCR1_BYPASS_RVI_RDATA_QUEUE, // Bypass RVI, rdata+queue
|
||||
SCR1_BYPASS_RVI_RDATA // Bypass RVI, rdata only
|
||||
} type_scr1_bypass_e;
|
||||
`endif // SCR1_NO_DEC_STAGE
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
// SCR1_IFU_INSTR_<UPPER_16_BITS>_<LOWER_16_BITS>
|
||||
SCR1_IFU_INSTR_NONE, // No valid instruction
|
||||
SCR1_IFU_INSTR_RVI_HI_RVI_LO, // Full RV32I instruction
|
||||
SCR1_IFU_INSTR_RVC_RVC,
|
||||
SCR1_IFU_INSTR_RVI_LO_RVC,
|
||||
SCR1_IFU_INSTR_RVC_RVI_HI,
|
||||
SCR1_IFU_INSTR_RVI_LO_RVI_HI,
|
||||
SCR1_IFU_INSTR_RVC_NV, // Instruction after unaligned new_pc
|
||||
SCR1_IFU_INSTR_RVI_LO_NV // Instruction after unaligned new_pc
|
||||
} type_scr1_ifu_instr_e;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Instruction queue signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// New PC unaligned flag register
|
||||
logic new_pc_unaligned_ff;
|
||||
logic new_pc_unaligned_next;
|
||||
logic new_pc_unaligned_upd;
|
||||
|
||||
// IMEM instruction type decoder
|
||||
logic instr_hi_is_rvi;
|
||||
logic instr_lo_is_rvi;
|
||||
type_scr1_ifu_instr_e instr_type;
|
||||
|
||||
// Register to store if the previous IMEM instruction had low part of RVI instruction
|
||||
// in its high part
|
||||
logic instr_hi_rvi_lo_ff;
|
||||
logic instr_hi_rvi_lo_next;
|
||||
|
||||
// Queue read/write size decoders
|
||||
type_scr1_ifu_queue_rd_e q_rd_size;
|
||||
logic q_rd_vd;
|
||||
logic q_rd_none;
|
||||
logic q_rd_hword;
|
||||
type_scr1_ifu_queue_wr_e q_wr_size;
|
||||
logic q_wr_none;
|
||||
logic q_wr_full;
|
||||
|
||||
// Write/read pointer registers
|
||||
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr;
|
||||
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr_next;
|
||||
logic q_rptr_upd;
|
||||
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr;
|
||||
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr_next;
|
||||
logic q_wptr_upd;
|
||||
|
||||
// Instruction queue control signals
|
||||
logic q_wr_en;
|
||||
logic q_flush_req;
|
||||
|
||||
// Queue data registers
|
||||
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data [SCR1_IFU_Q_SIZE_HALF];
|
||||
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_head;
|
||||
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_next;
|
||||
|
||||
// Queue error flags registers
|
||||
logic q_err [SCR1_IFU_Q_SIZE_HALF];
|
||||
logic q_err_head;
|
||||
logic q_err_next;
|
||||
|
||||
// Instruction queue status signals
|
||||
logic q_is_empty;
|
||||
logic q_has_free_slots;
|
||||
logic q_has_1_ocpd_hw;
|
||||
logic q_head_is_rvc;
|
||||
logic q_head_is_rvi;
|
||||
logic [SCR1_IFU_Q_FREE_H_W-1:0] q_ocpd_h;
|
||||
logic [SCR1_IFU_Q_FREE_H_W-1:0] q_free_h_next;
|
||||
logic [SCR1_IFU_Q_FREE_W_W-1:0] q_free_w_next;
|
||||
|
||||
// IFU FSM signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// IFU FSM control signals
|
||||
logic ifu_fetch_req;
|
||||
logic ifu_stop_req;
|
||||
|
||||
type_scr1_ifu_fsm_e ifu_fsm_curr;
|
||||
type_scr1_ifu_fsm_e ifu_fsm_next;
|
||||
logic ifu_fsm_fetch;
|
||||
|
||||
// IMEM signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// IMEM response signals
|
||||
logic imem_resp_ok;
|
||||
logic imem_resp_er;
|
||||
logic imem_resp_er_discard_pnd;
|
||||
logic imem_resp_discard_req;
|
||||
logic imem_resp_received;
|
||||
logic imem_resp_vd;
|
||||
logic imem_handshake_done;
|
||||
|
||||
logic [15:0] imem_rdata_lo;
|
||||
logic [31:16] imem_rdata_hi;
|
||||
|
||||
// IMEM address signals
|
||||
logic imem_addr_upd;
|
||||
logic [`SCR1_XLEN-1:2] imem_addr_ff;
|
||||
logic [`SCR1_XLEN-1:2] imem_addr_next;
|
||||
|
||||
// IMEM pending transactions counter
|
||||
logic imem_pnd_txns_cnt_upd;
|
||||
logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt;
|
||||
logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt_next;
|
||||
logic [SCR1_TXN_CNT_W-1:0] imem_vd_pnd_txns_cnt;
|
||||
logic imem_pnd_txns_q_full;
|
||||
|
||||
// IMEM responses discard counter
|
||||
logic imem_resp_discard_cnt_upd;
|
||||
logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt;
|
||||
logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt_next;
|
||||
|
||||
`ifdef SCR1_NEW_PC_REG
|
||||
logic new_pc_req_ff;
|
||||
`endif // SCR1_NEW_PC_REG
|
||||
|
||||
// Instruction bypass signals
|
||||
`ifdef SCR1_NO_DEC_STAGE
|
||||
type_scr1_bypass_e instr_bypass_type;
|
||||
logic instr_bypass_vd;
|
||||
`endif // SCR1_NO_DEC_STAGE
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Instruction queue
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Instruction queue consists of the following functional units:
|
||||
// - New PC unaligned flag register
|
||||
// - Instruction type decoder, including register to store if the previous
|
||||
// IMEM instruction had low part of RVI instruction in its high part
|
||||
// - Read/write size decoders
|
||||
// - Read/write pointer registers
|
||||
// - Data and error flag registers
|
||||
// - Status logic
|
||||
//
|
||||
|
||||
// New PC unaligned flag register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign new_pc_unaligned_upd = exu2ifu_pc_new_req_i | imem_resp_vd;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
new_pc_unaligned_ff <= 1'b0;
|
||||
end else if (new_pc_unaligned_upd) begin
|
||||
new_pc_unaligned_ff <= new_pc_unaligned_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign new_pc_unaligned_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[1]
|
||||
: ~imem_resp_vd ? new_pc_unaligned_ff
|
||||
: 1'b0;
|
||||
|
||||
// Instruction type decoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign instr_hi_is_rvi = &imem2ifu_rdata_i[17:16];
|
||||
assign instr_lo_is_rvi = &imem2ifu_rdata_i[1:0];
|
||||
|
||||
always_comb begin
|
||||
instr_type = SCR1_IFU_INSTR_NONE;
|
||||
|
||||
if (imem_resp_ok & ~imem_resp_discard_req) begin
|
||||
if (new_pc_unaligned_ff) begin
|
||||
instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_NV
|
||||
: SCR1_IFU_INSTR_RVC_NV;
|
||||
end else begin // ~new_pc_unaligned_ff
|
||||
if (instr_hi_rvi_lo_ff) begin
|
||||
instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_RVI_HI
|
||||
: SCR1_IFU_INSTR_RVC_RVI_HI;
|
||||
end else begin // SCR1_OTHER
|
||||
case ({instr_hi_is_rvi, instr_lo_is_rvi})
|
||||
2'b00 : instr_type = SCR1_IFU_INSTR_RVC_RVC;
|
||||
2'b10 : instr_type = SCR1_IFU_INSTR_RVI_LO_RVC;
|
||||
default : instr_type = SCR1_IFU_INSTR_RVI_HI_RVI_LO;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Register to store if the previous IMEM instruction had low part of RVI
|
||||
// instruction in its high part
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
instr_hi_rvi_lo_ff <= 1'b0;
|
||||
end else begin
|
||||
if (exu2ifu_pc_new_req_i) begin
|
||||
instr_hi_rvi_lo_ff <= 1'b0;
|
||||
end else if (imem_resp_vd) begin
|
||||
instr_hi_rvi_lo_ff <= instr_hi_rvi_lo_next;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign instr_hi_rvi_lo_next = (instr_type == SCR1_IFU_INSTR_RVI_LO_NV)
|
||||
| (instr_type == SCR1_IFU_INSTR_RVI_LO_RVI_HI)
|
||||
| (instr_type == SCR1_IFU_INSTR_RVI_LO_RVC);
|
||||
|
||||
// Queue write/read size decoders
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Queue read size decoder
|
||||
assign q_rd_vd = ~q_is_empty & ifu2idu_vd_o & idu2ifu_rdy_i;
|
||||
assign q_rd_hword = q_head_is_rvc | q_err_head
|
||||
`ifdef SCR1_NO_DEC_STAGE
|
||||
| (q_head_is_rvi & instr_bypass_vd)
|
||||
`endif // SCR1_NO_DEC_STAGE
|
||||
;
|
||||
assign q_rd_size = ~q_rd_vd ? SCR1_IFU_QUEUE_RD_NONE
|
||||
: q_rd_hword ? SCR1_IFU_QUEUE_RD_HWORD
|
||||
: SCR1_IFU_QUEUE_RD_WORD;
|
||||
assign q_rd_none = (q_rd_size == SCR1_IFU_QUEUE_RD_NONE);
|
||||
|
||||
// Queue write size decoder
|
||||
always_comb begin
|
||||
q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
|
||||
if (~imem_resp_discard_req) begin
|
||||
if (imem_resp_ok) begin
|
||||
`ifdef SCR1_NO_DEC_STAGE
|
||||
case (instr_type)
|
||||
SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
|
||||
SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI;
|
||||
SCR1_IFU_INSTR_RVC_NV : q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
|
||||
? SCR1_IFU_QUEUE_WR_NONE
|
||||
: SCR1_IFU_QUEUE_WR_HI;
|
||||
SCR1_IFU_INSTR_RVI_HI_RVI_LO: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
|
||||
? SCR1_IFU_QUEUE_WR_NONE
|
||||
: SCR1_IFU_QUEUE_WR_FULL;
|
||||
SCR1_IFU_INSTR_RVC_RVC,
|
||||
SCR1_IFU_INSTR_RVI_LO_RVC,
|
||||
SCR1_IFU_INSTR_RVC_RVI_HI,
|
||||
SCR1_IFU_INSTR_RVI_LO_RVI_HI: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
|
||||
? SCR1_IFU_QUEUE_WR_HI
|
||||
: SCR1_IFU_QUEUE_WR_FULL;
|
||||
endcase // instr_type
|
||||
`else // SCR1_NO_DEC_STAGE
|
||||
case (instr_type)
|
||||
SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
|
||||
SCR1_IFU_INSTR_RVC_NV,
|
||||
SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI;
|
||||
default : q_wr_size = SCR1_IFU_QUEUE_WR_FULL;
|
||||
endcase // instr_type
|
||||
`endif // SCR1_NO_DEC_STAGE
|
||||
end else if (imem_resp_er) begin
|
||||
q_wr_size = SCR1_IFU_QUEUE_WR_FULL;
|
||||
end // imem_resp_er
|
||||
end // ~imem_resp_discard_req
|
||||
end
|
||||
|
||||
assign q_wr_none = (q_wr_size == SCR1_IFU_QUEUE_WR_NONE);
|
||||
assign q_wr_full = (q_wr_size == SCR1_IFU_QUEUE_WR_FULL);
|
||||
|
||||
// Write/read pointer registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign q_flush_req = exu2ifu_pc_new_req_i | pipe2ifu_stop_fetch_i;
|
||||
|
||||
// Queue write pointer register
|
||||
assign q_wptr_upd = q_flush_req | ~q_wr_none;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
q_wptr <= '0;
|
||||
end else if (q_wptr_upd) begin
|
||||
q_wptr <= q_wptr_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign q_wptr_next = q_flush_req ? '0
|
||||
: ~q_wr_none ? q_wptr + (q_wr_full ? SCR1_IFU_QUEUE_PTR_W'('b010) : SCR1_IFU_QUEUE_PTR_W'('b001))
|
||||
: q_wptr;
|
||||
|
||||
// Queue read pointer register
|
||||
assign q_rptr_upd = q_flush_req | ~q_rd_none;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
q_rptr <= '0;
|
||||
end else if (q_rptr_upd) begin
|
||||
q_rptr <= q_rptr_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign q_rptr_next = q_flush_req ? '0
|
||||
: ~q_rd_none ? q_rptr + (q_rd_hword ? SCR1_IFU_QUEUE_PTR_W'('b001) : SCR1_IFU_QUEUE_PTR_W'('b010))
|
||||
: q_rptr;
|
||||
|
||||
// Queue data and error flag registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign imem_rdata_hi = imem2ifu_rdata_i[31:16];
|
||||
assign imem_rdata_lo = imem2ifu_rdata_i[15:0];
|
||||
|
||||
assign q_wr_en = imem_resp_vd & ~q_flush_req;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
q_data <= '{SCR1_IFU_Q_SIZE_HALF{'0}};
|
||||
q_err <= '{SCR1_IFU_Q_SIZE_HALF{1'b0}};
|
||||
end else if (q_wr_en) begin
|
||||
case (q_wr_size)
|
||||
SCR1_IFU_QUEUE_WR_HI : begin
|
||||
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_hi;
|
||||
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er;
|
||||
end
|
||||
SCR1_IFU_QUEUE_WR_FULL : begin
|
||||
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_lo;
|
||||
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er;
|
||||
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_rdata_hi;
|
||||
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_resp_er;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign q_data_head = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr)];
|
||||
assign q_data_next = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)];
|
||||
assign q_err_head = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr)];
|
||||
assign q_err_next = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)];
|
||||
|
||||
// Queue status logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign q_ocpd_h = SCR1_IFU_Q_FREE_H_W'(q_wptr - q_rptr);
|
||||
assign q_free_h_next = SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF - (q_wptr - q_rptr_next));
|
||||
assign q_free_w_next = SCR1_IFU_Q_FREE_W_W'(q_free_h_next >> 1'b1);
|
||||
|
||||
assign q_is_empty = (q_rptr == q_wptr);
|
||||
assign q_has_free_slots = (SCR1_TXN_CNT_W'(q_free_w_next) > imem_vd_pnd_txns_cnt);
|
||||
assign q_has_1_ocpd_hw = (q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(1));
|
||||
|
||||
assign q_head_is_rvi = &(q_data_head[1:0]);
|
||||
assign q_head_is_rvc = ~q_head_is_rvi;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IFU FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// IFU FSM control signals
|
||||
assign ifu_fetch_req = exu2ifu_pc_new_req_i & ~pipe2ifu_stop_fetch_i;
|
||||
assign ifu_stop_req = pipe2ifu_stop_fetch_i
|
||||
| (imem_resp_er_discard_pnd & ~exu2ifu_pc_new_req_i);
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
ifu_fsm_curr <= SCR1_IFU_FSM_IDLE;
|
||||
end else begin
|
||||
ifu_fsm_curr <= ifu_fsm_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
case (ifu_fsm_curr)
|
||||
SCR1_IFU_FSM_IDLE : begin
|
||||
ifu_fsm_next = ifu_fetch_req ? SCR1_IFU_FSM_FETCH
|
||||
: SCR1_IFU_FSM_IDLE;
|
||||
end
|
||||
SCR1_IFU_FSM_FETCH : begin
|
||||
ifu_fsm_next = ifu_stop_req ? SCR1_IFU_FSM_IDLE
|
||||
: SCR1_IFU_FSM_FETCH;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign ifu_fsm_fetch = (ifu_fsm_curr == SCR1_IFU_FSM_FETCH);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IFU <-> IMEM interface
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// IFU <-> IMEM interface consists of the following functional units:
|
||||
// - IMEM response logic
|
||||
// - IMEM address register
|
||||
// - Pending IMEM transactions counter
|
||||
// - IMEM discard responses counter
|
||||
// - IFU <-> IMEM interface output signals
|
||||
//
|
||||
|
||||
// IMEM response logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign imem_resp_er = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_ER);
|
||||
assign imem_resp_ok = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_OK);
|
||||
assign imem_resp_received = imem_resp_ok | imem_resp_er;
|
||||
assign imem_resp_vd = imem_resp_received & ~imem_resp_discard_req;
|
||||
assign imem_resp_er_discard_pnd = imem_resp_er & ~imem_resp_discard_req;
|
||||
|
||||
assign imem_handshake_done = ifu2imem_req_o & imem2ifu_req_ack_i;
|
||||
|
||||
// IMEM address register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign imem_addr_upd = imem_handshake_done | exu2ifu_pc_new_req_i;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
imem_addr_ff <= '0;
|
||||
end else if (imem_addr_upd) begin
|
||||
imem_addr_ff <= imem_addr_next;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SCR1_NEW_PC_REG
|
||||
assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2] + imem_handshake_done
|
||||
: &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done
|
||||
: {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done};
|
||||
`else // SCR1_NEW_PC_REG
|
||||
assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2]
|
||||
: &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done
|
||||
: {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done};
|
||||
`endif // SCR1_NEW_PC_REG
|
||||
|
||||
// Pending IMEM transactions counter
|
||||
//------------------------------------------------------------------------------
|
||||
// Pending IMEM transactions occur if IFU request has been acknowledged, but
|
||||
// response comes in the next cycle or later
|
||||
|
||||
assign imem_pnd_txns_cnt_upd = imem_handshake_done ^ imem_resp_received;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
imem_pnd_txns_cnt <= '0;
|
||||
end else if (imem_pnd_txns_cnt_upd) begin
|
||||
imem_pnd_txns_cnt <= imem_pnd_txns_cnt_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign imem_pnd_txns_cnt_next = imem_pnd_txns_cnt + (imem_handshake_done - imem_resp_received);
|
||||
assign imem_pnd_txns_q_full = &imem_pnd_txns_cnt;
|
||||
|
||||
// IMEM discard responses counter
|
||||
//------------------------------------------------------------------------------
|
||||
// IMEM instructions should be discarded in the following 2 cases:
|
||||
// 1. New PC is requested by jump, branch, mret or other instruction
|
||||
// 2. IMEM response was erroneous and not discarded
|
||||
//
|
||||
// In both cases the number of instructions to be discarded equals to the number
|
||||
// of pending instructions.
|
||||
// In the 1st case we don't need all the instructions that haven't been fetched
|
||||
// yet, since the PC has changed.
|
||||
// In the 2nd case, since the IMEM responce was erroneous there is no guarantee
|
||||
// that subsequent IMEM instructions would be valid.
|
||||
|
||||
assign imem_resp_discard_cnt_upd = exu2ifu_pc_new_req_i | imem_resp_er
|
||||
| (imem_resp_ok & imem_resp_discard_req);
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
imem_resp_discard_cnt <= '0;
|
||||
end else if (imem_resp_discard_cnt_upd) begin
|
||||
imem_resp_discard_cnt <= imem_resp_discard_cnt_next;
|
||||
end
|
||||
end
|
||||
|
||||
`ifndef SCR1_NEW_PC_REG
|
||||
assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i ? imem_pnd_txns_cnt_next - imem_handshake_done
|
||||
: imem_resp_er_discard_pnd ? imem_pnd_txns_cnt_next
|
||||
: imem_resp_discard_cnt - 1'b1;
|
||||
`else // SCR1_NEW_PC_REG
|
||||
assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i | imem_resp_er_discard_pnd
|
||||
? imem_pnd_txns_cnt_next
|
||||
: imem_resp_discard_cnt - 1'b1;
|
||||
`endif // SCR1_NEW_PC_REG
|
||||
|
||||
assign imem_vd_pnd_txns_cnt = imem_pnd_txns_cnt - imem_resp_discard_cnt;
|
||||
assign imem_resp_discard_req = |imem_resp_discard_cnt;
|
||||
|
||||
// IFU <-> IMEM interface output signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`ifndef SCR1_NEW_PC_REG
|
||||
assign ifu2imem_req_o = (exu2ifu_pc_new_req_i & ~imem_pnd_txns_q_full & ~pipe2ifu_stop_fetch_i)
|
||||
| (ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots);
|
||||
assign ifu2imem_addr_o = exu2ifu_pc_new_req_i
|
||||
? {exu2ifu_pc_new_i[`SCR1_XLEN-1:2], 2'b00}
|
||||
: {imem_addr_ff, 2'b00};
|
||||
`else // SCR1_NEW_PC_REG
|
||||
assign ifu2imem_req_o = ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots;
|
||||
assign ifu2imem_addr_o = {imem_addr_ff, 2'b00};
|
||||
`endif // SCR1_NEW_PC_REG
|
||||
|
||||
assign ifu2imem_cmd_o = SCR1_MEM_CMD_RD;
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
assign ifu2pipe_imem_txns_pnd_o = |imem_pnd_txns_cnt;
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IFU <-> IDU interface
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// IFU <-> IDU interface consists of the following functional units:
|
||||
// - Instruction bypass type decoder
|
||||
// - IFU <-> IDU status signals
|
||||
// - Output instruction multiplexer
|
||||
//
|
||||
|
||||
`ifdef SCR1_NO_DEC_STAGE
|
||||
|
||||
// Instruction bypass type decoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign instr_bypass_vd = (instr_bypass_type != SCR1_BYPASS_NONE);
|
||||
|
||||
always_comb begin
|
||||
instr_bypass_type = SCR1_BYPASS_NONE;
|
||||
|
||||
if (imem_resp_vd) begin
|
||||
if (q_is_empty) begin
|
||||
case (instr_type)
|
||||
SCR1_IFU_INSTR_RVC_NV,
|
||||
SCR1_IFU_INSTR_RVC_RVC,
|
||||
SCR1_IFU_INSTR_RVI_LO_RVC : begin
|
||||
instr_bypass_type = SCR1_BYPASS_RVC;
|
||||
end
|
||||
SCR1_IFU_INSTR_RVI_HI_RVI_LO : begin
|
||||
instr_bypass_type = SCR1_BYPASS_RVI_RDATA;
|
||||
end
|
||||
default : begin end
|
||||
endcase // instr_type
|
||||
end else if (q_has_1_ocpd_hw & q_head_is_rvi) begin
|
||||
if (instr_hi_rvi_lo_ff) begin
|
||||
instr_bypass_type = SCR1_BYPASS_RVI_RDATA_QUEUE;
|
||||
end
|
||||
end
|
||||
end // imem_resp_vd
|
||||
end
|
||||
|
||||
// IFU <-> IDU interface status signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
ifu2idu_vd_o = 1'b0;
|
||||
ifu2idu_imem_err_o = 1'b0;
|
||||
ifu2idu_err_rvi_hi_o = 1'b0;
|
||||
|
||||
if (ifu_fsm_fetch | ~q_is_empty) begin
|
||||
if (instr_bypass_vd) begin
|
||||
ifu2idu_vd_o = 1'b1;
|
||||
ifu2idu_imem_err_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE)
|
||||
? (imem_resp_er | q_err_head)
|
||||
: imem_resp_er;
|
||||
ifu2idu_err_rvi_hi_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE) & imem_resp_er;
|
||||
end else if (~q_is_empty) begin
|
||||
if (q_has_1_ocpd_hw) begin
|
||||
ifu2idu_vd_o = q_head_is_rvc | q_err_head;
|
||||
ifu2idu_imem_err_o = q_err_head;
|
||||
ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next;
|
||||
end else begin
|
||||
ifu2idu_vd_o = 1'b1;
|
||||
ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next);
|
||||
end
|
||||
end // ~q_is_empty
|
||||
end
|
||||
`ifdef SCR1_DBG_EN
|
||||
if (hdu2ifu_pbuf_fetch_i) begin
|
||||
ifu2idu_vd_o = hdu2ifu_pbuf_vd_i;
|
||||
ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i;
|
||||
end
|
||||
`endif // SCR1_DBG_EN
|
||||
end
|
||||
|
||||
// Output instruction multiplexer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
case (instr_bypass_type)
|
||||
SCR1_BYPASS_RVC : begin
|
||||
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(new_pc_unaligned_ff ? imem_rdata_hi
|
||||
: imem_rdata_lo);
|
||||
end
|
||||
SCR1_BYPASS_RVI_RDATA : begin
|
||||
ifu2idu_instr_o = imem2ifu_rdata_i;
|
||||
end
|
||||
SCR1_BYPASS_RVI_RDATA_QUEUE: begin
|
||||
ifu2idu_instr_o = {imem_rdata_lo, q_data_head};
|
||||
end
|
||||
default : begin
|
||||
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(q_head_is_rvc ? q_data_head
|
||||
: {q_data_next, q_data_head});
|
||||
end
|
||||
endcase // instr_bypass_type
|
||||
`ifdef SCR1_DBG_EN
|
||||
if (hdu2ifu_pbuf_fetch_i) begin
|
||||
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i});
|
||||
end
|
||||
`endif // SCR1_DBG_EN
|
||||
end
|
||||
|
||||
`else // SCR1_NO_DEC_STAGE
|
||||
|
||||
// IFU <-> IDU interface status signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
ifu2idu_vd_o = 1'b0;
|
||||
ifu2idu_imem_err_o = 1'b0;
|
||||
ifu2idu_err_rvi_hi_o = 1'b0;
|
||||
if (~q_is_empty) begin
|
||||
if (q_has_1_ocpd_hw) begin
|
||||
ifu2idu_vd_o = q_head_is_rvc | q_err_head;
|
||||
ifu2idu_imem_err_o = q_err_head;
|
||||
end else begin
|
||||
ifu2idu_vd_o = 1'b1;
|
||||
ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next);
|
||||
ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next;
|
||||
end
|
||||
end // ~q_is_empty
|
||||
`ifdef SCR1_DBG_EN
|
||||
if (hdu2ifu_pbuf_fetch_i) begin
|
||||
ifu2idu_vd_o = hdu2ifu_pbuf_vd_i;
|
||||
ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i;
|
||||
end
|
||||
`endif // SCR1_DBG_EN
|
||||
end
|
||||
|
||||
// Output instruction multiplexer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
ifu2idu_instr_o = q_head_is_rvc ? `SCR1_IMEM_DWIDTH'(q_data_head)
|
||||
: {q_data_next, q_data_head};
|
||||
`ifdef SCR1_DBG_EN
|
||||
if (hdu2ifu_pbuf_fetch_i) begin
|
||||
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i});
|
||||
end
|
||||
`endif // SCR1_DBG_EN
|
||||
end
|
||||
|
||||
`endif // SCR1_NO_DEC_STAGE
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
assign ifu2hdu_pbuf_rdy_o = idu2ifu_rdy_i;
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Assertions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// X checks
|
||||
|
||||
SCR1_SVA_IFU_XCHECK : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({imem2ifu_req_ack_i, idu2ifu_rdy_i, exu2ifu_pc_new_req_i})
|
||||
) else $error("IFU Error: unknown values");
|
||||
|
||||
SCR1_SVA_IFU_XCHECK_REQ : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
ifu2imem_req_o |-> !$isunknown({ifu2imem_addr_o, ifu2imem_cmd_o})
|
||||
) else $error("IFU Error: unknown {ifu2imem_addr_o, ifu2imem_cmd_o}");
|
||||
|
||||
// Behavior checks
|
||||
|
||||
SCR1_SVA_IFU_DRC_UNDERFLOW : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
~imem_resp_discard_req |=> ~(imem_resp_discard_cnt == SCR1_TXN_CNT_W'('1))
|
||||
) else $error("IFU Error: imem_resp_discard_cnt underflow");
|
||||
|
||||
SCR1_SVA_IFU_DRC_RANGE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(imem_resp_discard_cnt >= 0) & (imem_resp_discard_cnt <= imem_pnd_txns_cnt)
|
||||
) else $error("IFU Error: imem_resp_discard_cnt out of range");
|
||||
|
||||
SCR1_SVA_IFU_QUEUE_OVF : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(q_ocpd_h >= SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) |->
|
||||
((q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) ? (q_wr_size != SCR1_IFU_QUEUE_WR_FULL)
|
||||
: (q_wr_size == SCR1_IFU_QUEUE_WR_NONE))
|
||||
) else $error("IFU Error: queue overflow");
|
||||
|
||||
SCR1_SVA_IFU_IMEM_ERR_BEH : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(imem_resp_er & ~imem_resp_discard_req & ~exu2ifu_pc_new_req_i) |=>
|
||||
(ifu_fsm_curr == SCR1_IFU_FSM_IDLE) & (imem_resp_discard_cnt == imem_pnd_txns_cnt)
|
||||
) else $error("IFU Error: incorrect behavior after memory error");
|
||||
|
||||
SCR1_SVA_IFU_NEW_PC_REQ_BEH : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
exu2ifu_pc_new_req_i |=> q_is_empty
|
||||
) else $error("IFU Error: incorrect behavior after exu2ifu_pc_new_req_i");
|
||||
|
||||
SCR1_SVA_IFU_IMEM_ADDR_ALIGNED : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
ifu2imem_req_o |-> ~|ifu2imem_addr_o[1:0]
|
||||
) else $error("IFU Error: unaligned IMEM access");
|
||||
|
||||
SCR1_SVA_IFU_STOP_FETCH : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
pipe2ifu_stop_fetch_i |=> (ifu_fsm_curr == SCR1_IFU_FSM_IDLE)
|
||||
) else $error("IFU Error: fetch not stopped");
|
||||
|
||||
SCR1_SVA_IFU_IMEM_FAULT_RVI_HI : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
ifu2idu_err_rvi_hi_o |-> ifu2idu_imem_err_o
|
||||
) else $error("IFU Error: ifu2idu_imem_err_o == 0");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_ifu
|
||||
351
src_ref/core/pipeline/scr1_pipe_lsu.sv
Normal file
351
src_ref/core/pipeline/scr1_pipe_lsu.sv
Normal file
@@ -0,0 +1,351 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_lsu.sv>
|
||||
/// @brief Load/Store Unit (LSU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Performs load and store operations in Data Memory
|
||||
// - Generates DMEM address misalign and access fault exceptions
|
||||
// - Passes DMEM operations information to TDU and generates LSU breakpoint exception
|
||||
//
|
||||
// Structure:
|
||||
// - FSM
|
||||
// - Exceptions logic
|
||||
// - LSU <-> EXU interface
|
||||
// - LSU <-> DMEM interface
|
||||
// - LSU <-> TDU interface
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_arch_types.svh"
|
||||
`include "scr1_memif.svh"
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`ifdef SCR1_TDU_EN
|
||||
`include "scr1_tdu.svh"
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
module scr1_pipe_lsu (
|
||||
// Common
|
||||
input logic rst_n, // LSU reset
|
||||
input logic clk, // LSU clock
|
||||
|
||||
// LSU <-> EXU interface
|
||||
input logic exu2lsu_req_i, // Request to LSU
|
||||
input type_scr1_lsu_cmd_sel_e exu2lsu_cmd_i, // LSU command
|
||||
input logic [`SCR1_XLEN-1:0] exu2lsu_addr_i, // Address of DMEM
|
||||
input logic [`SCR1_XLEN-1:0] exu2lsu_sdata_i, // Data for store
|
||||
output logic lsu2exu_rdy_o, // LSU received DMEM response
|
||||
output logic [`SCR1_XLEN-1:0] lsu2exu_ldata_o, // Load data
|
||||
output logic lsu2exu_exc_o, // Exception from LSU
|
||||
output type_scr1_exc_code_e lsu2exu_exc_code_o, // Exception code
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
// LSU <-> TDU interface
|
||||
output type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_o, // Data address stream monitoring
|
||||
input logic tdu2lsu_ibrkpt_exc_req_i, // Instruction BP exception request
|
||||
input logic tdu2lsu_dbrkpt_exc_req_i, // Data BP exception request
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
// LSU <-> DMEM interface
|
||||
output logic lsu2dmem_req_o, // Data memory request
|
||||
output type_scr1_mem_cmd_e lsu2dmem_cmd_o, // Data memory command (READ/WRITE)
|
||||
output type_scr1_mem_width_e lsu2dmem_width_o, // Data memory data width
|
||||
output logic [`SCR1_DMEM_AWIDTH-1:0] lsu2dmem_addr_o, // Data memory address
|
||||
output logic [`SCR1_DMEM_DWIDTH-1:0] lsu2dmem_wdata_o, // Data memory write data
|
||||
input logic dmem2lsu_req_ack_i, // Data memory request acknowledge
|
||||
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2lsu_rdata_i, // Data memory read data
|
||||
input type_scr1_mem_resp_e dmem2lsu_resp_i // Data memory response
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef enum logic {
|
||||
SCR1_LSU_FSM_IDLE,
|
||||
SCR1_LSU_FSM_BUSY
|
||||
} type_scr1_lsu_fsm_e;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// LSU FSM signals
|
||||
type_scr1_lsu_fsm_e lsu_fsm_curr; // LSU FSM current state
|
||||
type_scr1_lsu_fsm_e lsu_fsm_next; // LSU FSM next state
|
||||
logic lsu_fsm_idle; // LSU FSM is in IDLE state
|
||||
|
||||
// LSU Command register signals
|
||||
logic lsu_cmd_upd; // LSU Command register update
|
||||
type_scr1_lsu_cmd_sel_e lsu_cmd_ff; // LSU Command register value
|
||||
logic lsu_cmd_ff_load; // Registered LSU Command is load
|
||||
logic lsu_cmd_ff_store; // Registered LSU Command is store
|
||||
|
||||
// DMEM command and width flags
|
||||
logic dmem_cmd_load; // DMEM command is load
|
||||
logic dmem_cmd_store; // DMEM Command is store
|
||||
logic dmem_wdth_word; // DMEM data width is WORD
|
||||
logic dmem_wdth_hword; // DMEM data width is HALFWORD
|
||||
logic dmem_wdth_byte; // DMEM data width is BYTE
|
||||
|
||||
// DMEM response and request control signals
|
||||
logic dmem_resp_ok; // DMEM response is OK
|
||||
logic dmem_resp_er; // DMEM response is erroneous
|
||||
logic dmem_resp_received; // DMEM response is received
|
||||
logic dmem_req_vd; // DMEM request is valid (req_ack received)
|
||||
|
||||
// Exceptions signals
|
||||
logic lsu_exc_req; // LSU exception request
|
||||
logic dmem_addr_mslgn; // DMEM address is misaligned
|
||||
logic dmem_addr_mslgn_l; // DMEM load address is misaligned
|
||||
logic dmem_addr_mslgn_s; // DMEM store address is misaligned
|
||||
`ifdef SCR1_TDU_EN
|
||||
logic lsu_exc_hwbrk; // LSU hardware breakpoint exception
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Control logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// DMEM response and request control signals
|
||||
assign dmem_resp_ok = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_OK);
|
||||
assign dmem_resp_er = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_ER);
|
||||
assign dmem_resp_received = dmem_resp_ok | dmem_resp_er;
|
||||
assign dmem_req_vd = exu2lsu_req_i & dmem2lsu_req_ack_i & ~lsu_exc_req;
|
||||
|
||||
// LSU load and store command flags
|
||||
assign dmem_cmd_load = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU)
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LH )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU)
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LW );
|
||||
assign dmem_cmd_store = (exu2lsu_cmd_i == SCR1_LSU_CMD_SB )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SH )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SW );
|
||||
|
||||
// LSU data width flags
|
||||
assign dmem_wdth_word = (exu2lsu_cmd_i == SCR1_LSU_CMD_LW )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SW );
|
||||
assign dmem_wdth_hword = (exu2lsu_cmd_i == SCR1_LSU_CMD_LH )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU)
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SH );
|
||||
assign dmem_wdth_byte = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB )
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU)
|
||||
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SB );
|
||||
|
||||
// LSU command register
|
||||
assign lsu_cmd_upd = lsu_fsm_idle & dmem_req_vd;
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
lsu_cmd_ff <= SCR1_LSU_CMD_NONE;
|
||||
end else if (lsu_cmd_upd) begin
|
||||
lsu_cmd_ff <= exu2lsu_cmd_i;
|
||||
end
|
||||
end
|
||||
|
||||
// LSU registered load and store command flags
|
||||
assign lsu_cmd_ff_load = (lsu_cmd_ff == SCR1_LSU_CMD_LB )
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_LBU)
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_LH )
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_LHU)
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_LW );
|
||||
assign lsu_cmd_ff_store = (lsu_cmd_ff == SCR1_LSU_CMD_SB )
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_SH )
|
||||
| (lsu_cmd_ff == SCR1_LSU_CMD_SW );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// LSU FSM
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// LSU FSM is used to control the LSU <-> DMEM interface
|
||||
//
|
||||
//
|
||||
|
||||
// Updating LSU FSM state
|
||||
always_ff @(posedge clk, negedge rst_n) begin
|
||||
if (~rst_n) begin
|
||||
lsu_fsm_curr <= SCR1_LSU_FSM_IDLE;
|
||||
end else begin
|
||||
lsu_fsm_curr <= lsu_fsm_next;
|
||||
end
|
||||
end
|
||||
|
||||
// LSU FSM next state logic
|
||||
always_comb begin
|
||||
case (lsu_fsm_curr)
|
||||
SCR1_LSU_FSM_IDLE: begin
|
||||
lsu_fsm_next = dmem_req_vd ? SCR1_LSU_FSM_BUSY
|
||||
: SCR1_LSU_FSM_IDLE;
|
||||
end
|
||||
SCR1_LSU_FSM_BUSY: begin
|
||||
lsu_fsm_next = dmem_resp_received ? SCR1_LSU_FSM_IDLE
|
||||
: SCR1_LSU_FSM_BUSY;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
assign lsu_fsm_idle = (lsu_fsm_curr == SCR1_LSU_FSM_IDLE);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exceptions logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// The following types of exceptions are supported:
|
||||
// - Load address misalign
|
||||
// - Load access fault
|
||||
// - Store address misalign
|
||||
// - Store access fault
|
||||
// - LSU breakpoint exception
|
||||
//
|
||||
|
||||
// DMEM addr misalign logic
|
||||
assign dmem_addr_mslgn = exu2lsu_req_i & ( (dmem_wdth_hword & exu2lsu_addr_i[0])
|
||||
| (dmem_wdth_word & |exu2lsu_addr_i[1:0]));
|
||||
assign dmem_addr_mslgn_l = dmem_addr_mslgn & dmem_cmd_load;
|
||||
assign dmem_addr_mslgn_s = dmem_addr_mslgn & dmem_cmd_store;
|
||||
|
||||
// Exception code logic
|
||||
always_comb begin
|
||||
case (1'b1)
|
||||
dmem_resp_er : lsu2exu_exc_code_o = lsu_cmd_ff_load ? SCR1_EXC_CODE_LD_ACCESS_FAULT
|
||||
: lsu_cmd_ff_store ? SCR1_EXC_CODE_ST_ACCESS_FAULT
|
||||
: SCR1_EXC_CODE_INSTR_MISALIGN;
|
||||
`ifdef SCR1_TDU_EN
|
||||
lsu_exc_hwbrk : lsu2exu_exc_code_o = SCR1_EXC_CODE_BREAKPOINT;
|
||||
`endif // SCR1_TDU_EN
|
||||
dmem_addr_mslgn_l: lsu2exu_exc_code_o = SCR1_EXC_CODE_LD_ADDR_MISALIGN;
|
||||
dmem_addr_mslgn_s: lsu2exu_exc_code_o = SCR1_EXC_CODE_ST_ADDR_MISALIGN;
|
||||
default : lsu2exu_exc_code_o = SCR1_EXC_CODE_INSTR_MISALIGN;
|
||||
endcase // 1'b1
|
||||
end
|
||||
|
||||
assign lsu_exc_req = dmem_addr_mslgn_l | dmem_addr_mslgn_s
|
||||
`ifdef SCR1_TDU_EN
|
||||
| lsu_exc_hwbrk
|
||||
`endif // SCR1_TDU_EN
|
||||
;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// LSU <-> EXU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign lsu2exu_rdy_o = dmem_resp_received;
|
||||
assign lsu2exu_exc_o = dmem_resp_er | lsu_exc_req;
|
||||
|
||||
// Sign- or zero-extending data received from DMEM
|
||||
always_comb begin
|
||||
case (lsu_cmd_ff)
|
||||
SCR1_LSU_CMD_LH : lsu2exu_ldata_o = {{16{dmem2lsu_rdata_i[15]}}, dmem2lsu_rdata_i[15:0]};
|
||||
SCR1_LSU_CMD_LHU: lsu2exu_ldata_o = { 16'b0, dmem2lsu_rdata_i[15:0]};
|
||||
SCR1_LSU_CMD_LB : lsu2exu_ldata_o = {{24{dmem2lsu_rdata_i[7]}}, dmem2lsu_rdata_i[7:0]};
|
||||
SCR1_LSU_CMD_LBU: lsu2exu_ldata_o = { 24'b0, dmem2lsu_rdata_i[7:0]};
|
||||
default : lsu2exu_ldata_o = dmem2lsu_rdata_i;
|
||||
endcase // lsu_cmd_ff
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// LSU <-> DMEM interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign lsu2dmem_req_o = exu2lsu_req_i & ~lsu_exc_req & lsu_fsm_idle;
|
||||
assign lsu2dmem_addr_o = exu2lsu_addr_i;
|
||||
assign lsu2dmem_wdata_o = exu2lsu_sdata_i;
|
||||
assign lsu2dmem_cmd_o = dmem_cmd_store ? SCR1_MEM_CMD_WR : SCR1_MEM_CMD_RD;
|
||||
assign lsu2dmem_width_o = dmem_wdth_byte ? SCR1_MEM_WIDTH_BYTE
|
||||
: dmem_wdth_hword ? SCR1_MEM_WIDTH_HWORD
|
||||
: SCR1_MEM_WIDTH_WORD;
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
//------------------------------------------------------------------------------
|
||||
// LSU <-> TDU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign lsu2tdu_dmon_o.vd = exu2lsu_req_i & lsu_fsm_idle & ~tdu2lsu_ibrkpt_exc_req_i;
|
||||
assign lsu2tdu_dmon_o.addr = exu2lsu_addr_i;
|
||||
assign lsu2tdu_dmon_o.load = dmem_cmd_load;
|
||||
assign lsu2tdu_dmon_o.store = dmem_cmd_store;
|
||||
|
||||
assign lsu_exc_hwbrk = (exu2lsu_req_i & tdu2lsu_ibrkpt_exc_req_i)
|
||||
| tdu2lsu_dbrkpt_exc_req_i;
|
||||
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//------------------------------------------------------------------------------
|
||||
// Assertions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// X checks
|
||||
|
||||
SCR1_SVA_LSU_XCHECK_CTRL : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({exu2lsu_req_i, lsu_fsm_curr
|
||||
`ifdef SCR1_TDU_EN
|
||||
, tdu2lsu_ibrkpt_exc_req_i, tdu2lsu_dbrkpt_exc_req_i
|
||||
`endif // SCR1_TDU_EN
|
||||
})
|
||||
) else $error("LSU Error: unknown control value");
|
||||
|
||||
SCR1_SVA_LSU_XCHECK_CMD : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
exu2lsu_req_i |-> !$isunknown({exu2lsu_cmd_i, exu2lsu_addr_i})
|
||||
) else $error("LSU Error: undefined CMD or address");
|
||||
|
||||
SCR1_SVA_LSU_XCHECK_SDATA : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(exu2lsu_req_i & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR)) |-> !$isunknown({exu2lsu_sdata_i})
|
||||
) else $error("LSU Error: undefined store data");
|
||||
|
||||
SCR1_SVA_LSU_XCHECK_EXC : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2exu_exc_o |-> !$isunknown(lsu2exu_exc_code_o)
|
||||
) else $error("LSU Error: exception code undefined");
|
||||
|
||||
SCR1_SVA_LSU_IMEM_CTRL : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2dmem_req_o |-> !$isunknown({lsu2dmem_cmd_o, lsu2dmem_width_o, lsu2dmem_addr_o})
|
||||
) else $error("LSU Error: undefined dmem control");
|
||||
|
||||
SCR1_SVA_LSU_IMEM_ACK : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2dmem_req_o |-> !$isunknown(dmem2lsu_req_ack_i)
|
||||
) else $error("LSU Error: undefined dmem ack");
|
||||
|
||||
SCR1_SVA_LSU_IMEM_WDATA : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2dmem_req_o & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR)
|
||||
|-> !$isunknown(lsu2dmem_wdata_o[8:0])
|
||||
) else $error("LSU Error: undefined dmem wdata");
|
||||
|
||||
// Behavior checks
|
||||
|
||||
SCR1_SVA_LSU_EXC_ONEHOT : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
$onehot0({dmem_resp_er, dmem_addr_mslgn_l, dmem_addr_mslgn_s})
|
||||
) else $error("LSU Error: more than one exception at a time");
|
||||
|
||||
SCR1_SVA_LSU_UNEXPECTED_DMEM_RESP : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu_fsm_idle |-> ~dmem_resp_received
|
||||
) else $error("LSU Error: not expecting memory response");
|
||||
|
||||
SCR1_SVA_LSU_REQ_EXC : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2exu_exc_o |-> exu2lsu_req_i
|
||||
) else $error("LSU Error: impossible exception");
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
|
||||
SCR1_COV_LSU_MISALIGN_BRKPT : cover property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(dmem_addr_mslgn_l | dmem_addr_mslgn_s) & lsu_exc_hwbrk
|
||||
);
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_lsu
|
||||
167
src_ref/core/pipeline/scr1_pipe_mprf.sv
Normal file
167
src_ref/core/pipeline/scr1_pipe_mprf.sv
Normal file
@@ -0,0 +1,167 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_mprf.sv>
|
||||
/// @brief Multi Port Register File (MPRF)
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_arch_types.svh"
|
||||
|
||||
module scr1_pipe_mprf (
|
||||
// Common
|
||||
`ifdef SCR1_MPRF_RST_EN
|
||||
input logic rst_n, // MPRF reset
|
||||
`endif // SCR1_MPRF_RST_EN
|
||||
input logic clk, // MPRF clock
|
||||
|
||||
// EXU <-> MPRF interface
|
||||
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr_i, // MPRF rs1 read address
|
||||
output logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data_o, // MPRF rs1 read data
|
||||
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr_i, // MPRF rs2 read address
|
||||
output logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data_o, // MPRF rs2 read data
|
||||
input logic exu2mprf_w_req_i, // MPRF write request
|
||||
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr_i, // MPRF rd write address
|
||||
input logic [`SCR1_XLEN-1:0] exu2mprf_rd_data_i // MPRF rd write data
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
logic wr_req_vd;
|
||||
|
||||
logic rs1_addr_vd;
|
||||
logic rs2_addr_vd;
|
||||
|
||||
`ifdef SCR1_MPRF_RAM
|
||||
logic rs1_addr_vd_ff;
|
||||
logic rs2_addr_vd_ff;
|
||||
|
||||
logic rs1_new_data_req;
|
||||
logic rs2_new_data_req;
|
||||
logic rs1_new_data_req_ff;
|
||||
logic rs2_new_data_req_ff;
|
||||
logic read_new_data_req;
|
||||
|
||||
logic [`SCR1_XLEN-1:0] rd_data_ff;
|
||||
|
||||
logic [`SCR1_XLEN-1:0] rs1_data_ff;
|
||||
logic [`SCR1_XLEN-1:0] rs2_data_ff;
|
||||
|
||||
// when using RAM, 2 memories are needed because 3 simultaneous independent
|
||||
// write/read operations can occur
|
||||
`ifdef SCR1_TRGT_FPGA_INTEL_MAX10
|
||||
(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
|
||||
(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
|
||||
`elsif SCR1_TRGT_FPGA_INTEL_ARRIAV
|
||||
(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
|
||||
(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
|
||||
`else
|
||||
logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
|
||||
logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
|
||||
`endif
|
||||
`else // distributed logic implementation
|
||||
type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf_int;
|
||||
`endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MPRF control logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// control signals common for distributed logic and RAM implementations
|
||||
assign rs1_addr_vd = |exu2mprf_rs1_addr_i;
|
||||
assign rs2_addr_vd = |exu2mprf_rs2_addr_i;
|
||||
|
||||
assign wr_req_vd = exu2mprf_w_req_i & |exu2mprf_rd_addr_i;
|
||||
|
||||
// RAM implementation specific control signals
|
||||
`ifdef SCR1_MPRF_RAM
|
||||
assign rs1_new_data_req = wr_req_vd & ( exu2mprf_rs1_addr_i == exu2mprf_rd_addr_i );
|
||||
assign rs2_new_data_req = wr_req_vd & ( exu2mprf_rs2_addr_i == exu2mprf_rd_addr_i );
|
||||
assign read_new_data_req = rs1_new_data_req | rs2_new_data_req;
|
||||
|
||||
always_ff @( posedge clk ) begin
|
||||
rs1_addr_vd_ff <= rs1_addr_vd;
|
||||
rs2_addr_vd_ff <= rs2_addr_vd;
|
||||
rs1_new_data_req_ff <= rs1_new_data_req;
|
||||
rs2_new_data_req_ff <= rs2_new_data_req;
|
||||
end
|
||||
`endif // SCR1_MPRF_RAM
|
||||
|
||||
`ifdef SCR1_MPRF_RAM
|
||||
//-------------------------------------------------------------------------------
|
||||
// RAM implementation
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// RAM is implemented with 2 simple dual-port memories with sync read operation;
|
||||
// logic for "write-first" RDW behavior is implemented externally to the embedded
|
||||
// memory blocks
|
||||
|
||||
// bypass new wr_data to the read output if write/read collision occurs
|
||||
assign mprf2exu_rs1_data_o = ( rs1_new_data_req_ff ) ? rd_data_ff
|
||||
: (( rs1_addr_vd_ff ) ? rs1_data_ff
|
||||
: '0 );
|
||||
|
||||
assign mprf2exu_rs2_data_o = ( rs2_new_data_req_ff ) ? rd_data_ff
|
||||
: (( rs2_addr_vd_ff ) ? rs2_data_ff
|
||||
: '0 );
|
||||
|
||||
always_ff @( posedge clk ) begin
|
||||
if ( read_new_data_req ) begin
|
||||
rd_data_ff <= exu2mprf_rd_data_i;
|
||||
end
|
||||
end
|
||||
|
||||
// synchronous read operation
|
||||
always_ff @( posedge clk ) begin
|
||||
rs1_data_ff <= mprf_int[exu2mprf_rs1_addr_i];
|
||||
rs2_data_ff <= mprf_int2[exu2mprf_rs2_addr_i];
|
||||
end
|
||||
|
||||
// write operation
|
||||
always_ff @( posedge clk ) begin
|
||||
if ( wr_req_vd ) begin
|
||||
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
|
||||
mprf_int2[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
|
||||
end
|
||||
end
|
||||
`else // distributed logic implementation
|
||||
//------------------------------------------------------------------------------
|
||||
// distributed logic implementation
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// asynchronous read operation
|
||||
assign mprf2exu_rs1_data_o = ( rs1_addr_vd ) ? mprf_int[exu2mprf_rs1_addr_i] : '0;
|
||||
assign mprf2exu_rs2_data_o = ( rs2_addr_vd ) ? mprf_int[exu2mprf_rs2_addr_i] : '0;
|
||||
|
||||
// write operation
|
||||
`ifdef SCR1_MPRF_RST_EN
|
||||
always_ff @( posedge clk, negedge rst_n ) begin
|
||||
if ( ~rst_n ) begin
|
||||
mprf_int <= '{default: '0};
|
||||
end else if ( wr_req_vd ) begin
|
||||
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
|
||||
end
|
||||
end
|
||||
`else // ~SCR1_MPRF_RST_EN
|
||||
always_ff @( posedge clk ) begin
|
||||
if ( wr_req_vd ) begin
|
||||
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
|
||||
end
|
||||
end
|
||||
`endif // ~SCR1_MPRF_RST_EN
|
||||
`endif
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_MPRF_RST_EN
|
||||
SCR1_SVA_MPRF_WRITEX : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
exu2mprf_w_req_i |-> !$isunknown({exu2mprf_rd_addr_i, (|exu2mprf_rd_addr_i ? exu2mprf_rd_data_i : `SCR1_XLEN'd0)})
|
||||
) else $error("MPRF error: unknown values");
|
||||
`endif // SCR1_MPRF_RST_EN
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_mprf
|
||||
610
src_ref/core/pipeline/scr1_pipe_tdu.sv
Normal file
610
src_ref/core/pipeline/scr1_pipe_tdu.sv
Normal file
@@ -0,0 +1,610 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_tdu.sv>
|
||||
/// @brief Trigger Debug Unit (TDU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Provides read/write interface for TDU CSRs
|
||||
// - Provides triggers functionality:
|
||||
// - Supports triggers either in both Debug and M modes or in Debug mode only
|
||||
// - Supports virtual address matching (load, store, exec) triggers
|
||||
// - Supports instruction count triggers
|
||||
// - Supports the following actions on trigger firing:
|
||||
// - Breakpoint exception raising
|
||||
// - Debug Mode entering
|
||||
// - Supports triggers chaining
|
||||
//
|
||||
// Structure:
|
||||
// - CSR read/write i/f
|
||||
// - TDU CSRs:
|
||||
// - TSELECT
|
||||
// - TDATA1/MCONTROL/ICOUNT
|
||||
// - TDATA2
|
||||
// - TINFO
|
||||
// - TDU <-> EXU i/f
|
||||
// - TDU <-> LSU i/f
|
||||
// - TDU <-> HDU i/f
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`include "scr1_tdu.svh"
|
||||
|
||||
module scr1_pipe_tdu (
|
||||
// Common signals
|
||||
input logic rst_n, // TDU reset
|
||||
input logic clk, // TDU clock
|
||||
input logic clk_en, // TDU clock enable
|
||||
input logic tdu_dsbl_i, // TDU Disable
|
||||
|
||||
// TDU <-> CSR interface
|
||||
input logic csr2tdu_req_i, // CSR-TDU i/f request
|
||||
input type_scr1_csr_cmd_sel_e csr2tdu_cmd_i, // CSR-TDU i/f command
|
||||
input logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr_i, // CSR-TDU i/f address
|
||||
input logic [SCR1_TDU_DATA_W-1:0] csr2tdu_wdata_i, // CSR-TDU i/f write data
|
||||
output logic [SCR1_TDU_DATA_W-1:0] tdu2csr_rdata_o, // CSR-TDU i/f read data
|
||||
output type_scr1_csr_resp_e tdu2csr_resp_o, // CSR-TDU i/f response
|
||||
|
||||
// TDU <-> EXU interface
|
||||
input type_scr1_brkm_instr_mon_s exu2tdu_imon_i, // Instruction stream monitoring
|
||||
output logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] tdu2exu_ibrkpt_match_o, // Instruction BP match
|
||||
output logic tdu2exu_ibrkpt_exc_req_o, // Instruction BP exception request
|
||||
input logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] exu2tdu_bp_retire_i, // Map of BPs being retired
|
||||
|
||||
// TDU <-> LSU interface
|
||||
`ifndef SCR1_TDU_EN
|
||||
output logic tdu2lsu_brk_en_o, // TDU-LSU Breakpoint enable
|
||||
`endif // SCR1_TDU_EN
|
||||
output logic tdu2lsu_ibrkpt_exc_req_o, // TDU-LSU Instruction BP exception request
|
||||
input type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_i, // TDU-LSU Data address stream monitoring
|
||||
output logic [SCR1_TDU_MTRIG_NUM-1 : 0] tdu2lsu_dbrkpt_match_o, // TDU-LSU Data BP match
|
||||
output logic tdu2lsu_dbrkpt_exc_req_o, // TDU-LSU Data BP exception request
|
||||
|
||||
// TDU <-> HDU interface
|
||||
output logic tdu2hdu_dmode_req_o // Debug Mode redirection request
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local parameters declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
localparam int unsigned MTRIG_NUM = SCR1_TDU_MTRIG_NUM;
|
||||
localparam int unsigned ALLTRIG_NUM = SCR1_TDU_ALLTRIG_NUM;
|
||||
localparam int unsigned ALLTRIG_W = $clog2(ALLTRIG_NUM+1);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TDU CSRs read/write i/f signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Write signals
|
||||
logic csr_wr_req;
|
||||
logic [SCR1_TDU_DATA_W-1:0] csr_wr_data;
|
||||
|
||||
// Register select
|
||||
logic csr_addr_tselect;
|
||||
logic [MTRIG_NUM-1:0] csr_addr_mcontrol;
|
||||
logic [MTRIG_NUM-1:0] csr_addr_tdata2;
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
logic csr_addr_icount;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
// TDU CSRs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TSELECT register
|
||||
logic csr_tselect_upd;
|
||||
logic [ALLTRIG_W-1:0] csr_tselect_ff;
|
||||
|
||||
// MCONTROL register
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_wr_req;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_clk_en;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_upd;
|
||||
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_m_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_m_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_load_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_load_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_store_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_store_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_action_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_action_next;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_ff;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_next;
|
||||
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_hit;
|
||||
logic [MTRIG_NUM-1:0] csr_mcontrol_ldst_hit;
|
||||
|
||||
// ICOUNT register
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
logic csr_icount_wr_req;
|
||||
logic csr_icount_clk_en;
|
||||
logic csr_icount_upd;
|
||||
|
||||
logic csr_icount_dmode_ff;
|
||||
logic csr_icount_dmode_next;
|
||||
logic csr_icount_m_ff;
|
||||
logic csr_icount_m_next;
|
||||
logic csr_icount_action_ff;
|
||||
logic csr_icount_action_next;
|
||||
logic csr_icount_hit_ff;
|
||||
logic csr_icount_hit_next;
|
||||
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
|
||||
csr_icount_count_ff;
|
||||
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
|
||||
csr_icount_count_next;
|
||||
logic csr_icount_skip_ff;
|
||||
logic csr_icount_skip_next;
|
||||
|
||||
logic csr_icount_decr_en;
|
||||
logic csr_icount_count_decr;
|
||||
logic csr_icount_skip_dsbl;
|
||||
logic csr_icount_hit;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
// TDATA2 register
|
||||
logic [MTRIG_NUM-1:0] csr_tdata2_upd;
|
||||
logic [MTRIG_NUM-1:0] [SCR1_TDU_DATA_W-1:0] csr_tdata2_ff;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CSR read/write interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Read logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign tdu2csr_resp_o = csr2tdu_req_i ? SCR1_CSR_RESP_OK : SCR1_CSR_RESP_ER;
|
||||
|
||||
always_comb begin
|
||||
tdu2csr_rdata_o = '0;
|
||||
if (csr2tdu_req_i) begin
|
||||
case (csr2tdu_addr_i)
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
|
||||
tdu2csr_rdata_o = {'0, csr_tselect_ff};
|
||||
end
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
|
||||
tdu2csr_rdata_o = csr_tdata2_ff[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
|
||||
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
|
||||
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_MCONTROL_TYPE_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_mcontrol_dmode_ff[i];
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MASKMAX_HI:
|
||||
SCR1_TDU_MCONTROL_MASKMAX_LO] = SCR1_TDU_MCONTROL_MASKMAX_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_HIT] = csr_mcontrol_hit_ff[i];
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_SELECT] = SCR1_TDU_MCONTROL_SELECT_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TIMING] = SCR1_TDU_MCONTROL_TIMING_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_ACTION_HI:
|
||||
SCR1_TDU_MCONTROL_ACTION_LO] = {5'b0, csr_mcontrol_action_ff[i]};
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_CHAIN] = 1'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MATCH_HI:
|
||||
SCR1_TDU_MCONTROL_MATCH_LO] = 4'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_M] = csr_mcontrol_m_ff[i];
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_RESERVEDA] = SCR1_TDU_MCONTROL_RESERVEDA_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_S] = 1'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_U] = 1'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_EXECUTE] = csr_mcontrol_exec_ff [i];
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_STORE] = csr_mcontrol_store_ff[i];
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_LOAD] = csr_mcontrol_load_ff [i];
|
||||
end
|
||||
end
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
|
||||
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
|
||||
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_ICOUNT_TYPE_VAL;
|
||||
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_icount_dmode_ff;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_HIT] = csr_icount_hit_ff;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_COUNT_HI:
|
||||
SCR1_TDU_ICOUNT_COUNT_LO] = csr_icount_count_ff;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_U] = 1'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_S] = 1'b0;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_M] = csr_icount_m_ff;
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_ACTION_HI:
|
||||
SCR1_TDU_ICOUNT_ACTION_LO] = {5'b0, csr_icount_action_ff};
|
||||
end
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
end
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TINFO : begin
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
|
||||
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TYPE_VAL] = 1'b1;
|
||||
end
|
||||
end
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
|
||||
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_TYPE_VAL] = 1'b1;
|
||||
end
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
end
|
||||
default : begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// Write logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
csr_wr_req = 1'b0;
|
||||
csr_wr_data = '0;
|
||||
|
||||
case (csr2tdu_cmd_i)
|
||||
SCR1_CSR_CMD_WRITE: begin
|
||||
csr_wr_req = 1'b1;
|
||||
csr_wr_data = csr2tdu_wdata_i;
|
||||
end
|
||||
SCR1_CSR_CMD_SET : begin
|
||||
csr_wr_req = |csr2tdu_wdata_i;
|
||||
csr_wr_data = tdu2csr_rdata_o | csr2tdu_wdata_i;
|
||||
end
|
||||
SCR1_CSR_CMD_CLEAR: begin
|
||||
csr_wr_req = |csr2tdu_wdata_i;
|
||||
csr_wr_data = tdu2csr_rdata_o & ~csr2tdu_wdata_i;
|
||||
end
|
||||
default : begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// Register selection
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
csr_addr_tselect = 1'b0;
|
||||
csr_addr_tdata2 = '0;
|
||||
csr_addr_mcontrol = '0;
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
csr_addr_icount = '0;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
if (csr2tdu_req_i) begin
|
||||
case (csr2tdu_addr_i)
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
|
||||
csr_addr_tselect = 1'b1;
|
||||
end
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
|
||||
csr_addr_mcontrol[i] = 1'b1;
|
||||
end
|
||||
end
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
|
||||
csr_addr_icount = 1'b1;
|
||||
end
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
end
|
||||
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
if(csr_tselect_ff == ALLTRIG_W'(i) ) begin
|
||||
csr_addr_tdata2[i] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
default : begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TDU CSRs
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// TDU CSRs consist of the following registers:
|
||||
// - TSELECT
|
||||
// - TDATA1/MCONTROL/ICOUNT (depending on the type field value)
|
||||
// - TDATA2
|
||||
//
|
||||
|
||||
// TSELECT register
|
||||
//------------------------------------------------------------------------------
|
||||
// Determines which trigger is accessible through the other trigger registers
|
||||
|
||||
assign csr_tselect_upd = clk_en & csr_addr_tselect & csr_wr_req
|
||||
& (csr_wr_data[ALLTRIG_W-1:0] < ALLTRIG_W'(ALLTRIG_NUM));
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if(~rst_n) begin
|
||||
csr_tselect_ff <= '0;
|
||||
end else if(csr_tselect_upd) begin
|
||||
csr_tselect_ff <= csr_wr_data[ALLTRIG_W-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
// ICOUNT register
|
||||
//------------------------------------------------------------------------------
|
||||
// Provides a trigger that fires when the certain number of instructions has retired
|
||||
// Is intended to be used as a single step trigger (in this case count must be 1)
|
||||
|
||||
assign csr_icount_wr_req = csr_addr_icount & csr_wr_req;
|
||||
assign csr_icount_clk_en = clk_en & (csr_icount_wr_req | csr_icount_m_ff);
|
||||
assign csr_icount_upd = ~csr_icount_dmode_ff
|
||||
? csr_icount_wr_req
|
||||
: tdu_dsbl_i & csr_icount_wr_req;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if(~rst_n) begin
|
||||
csr_icount_dmode_ff <= 1'b0;
|
||||
csr_icount_m_ff <= 1'b0;
|
||||
csr_icount_action_ff <= 1'b0;
|
||||
csr_icount_hit_ff <= 1'b0;
|
||||
csr_icount_count_ff <= '0;
|
||||
csr_icount_skip_ff <= 1'b0;
|
||||
end else if (csr_icount_clk_en) begin
|
||||
csr_icount_dmode_ff <= csr_icount_dmode_next;
|
||||
csr_icount_m_ff <= csr_icount_m_next;
|
||||
csr_icount_action_ff <= csr_icount_action_next;
|
||||
csr_icount_hit_ff <= csr_icount_hit_next;
|
||||
csr_icount_count_ff <= csr_icount_count_next;
|
||||
csr_icount_skip_ff <= csr_icount_skip_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign csr_icount_decr_en = (~tdu_dsbl_i & csr_icount_m_ff)
|
||||
? exu2tdu_imon_i.vd & (csr_icount_count_ff != 14'b0)
|
||||
: 1'b0;
|
||||
assign csr_icount_count_decr = exu2tdu_imon_i.req & csr_icount_decr_en & ~csr_icount_skip_ff;
|
||||
assign csr_icount_skip_dsbl = exu2tdu_imon_i.req & csr_icount_decr_en & csr_icount_skip_ff;
|
||||
|
||||
always_comb begin
|
||||
if (csr_icount_upd) begin
|
||||
csr_icount_dmode_next = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
|
||||
csr_icount_m_next = csr_wr_data[SCR1_TDU_ICOUNT_M];
|
||||
csr_icount_action_next = (csr_wr_data[SCR1_TDU_ICOUNT_ACTION_HI
|
||||
:SCR1_TDU_ICOUNT_ACTION_LO] == 'b1);
|
||||
csr_icount_hit_next = csr_wr_data[SCR1_TDU_ICOUNT_HIT];
|
||||
csr_icount_count_next = csr_wr_data[SCR1_TDU_ICOUNT_COUNT_HI:SCR1_TDU_ICOUNT_COUNT_LO];
|
||||
end else begin
|
||||
csr_icount_dmode_next = csr_icount_dmode_ff;
|
||||
csr_icount_m_next = csr_icount_m_ff;
|
||||
csr_icount_action_next = csr_icount_action_ff;
|
||||
csr_icount_hit_next = exu2tdu_bp_retire_i[ALLTRIG_NUM - 1'b1]
|
||||
? 1'b1
|
||||
: csr_icount_hit_ff;
|
||||
csr_icount_count_next = csr_icount_count_decr
|
||||
? csr_icount_count_ff - 1'b1
|
||||
: csr_icount_count_ff;
|
||||
end
|
||||
end
|
||||
|
||||
assign csr_icount_skip_next = csr_icount_wr_req ? csr_wr_data[SCR1_TDU_ICOUNT_M]
|
||||
: csr_icount_skip_dsbl ? 1'b0
|
||||
: csr_icount_skip_ff;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
// MCONTROL registers
|
||||
//------------------------------------------------------------------------------
|
||||
// Provides a trigger that fires on the virtual address (stored in TDATA2) match
|
||||
// (load, store, exec options supported). Triggers chaining supported
|
||||
|
||||
genvar trig;
|
||||
generate
|
||||
for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_mtrig
|
||||
|
||||
assign csr_mcontrol_wr_req[trig] = csr_addr_mcontrol[trig] & csr_wr_req;
|
||||
assign csr_mcontrol_clk_en[trig] = clk_en
|
||||
& (csr_mcontrol_wr_req[trig] | csr_mcontrol_m_ff[trig]);
|
||||
assign csr_mcontrol_upd [trig] = ~csr_mcontrol_dmode_ff[trig]
|
||||
? csr_mcontrol_wr_req[trig]
|
||||
: tdu_dsbl_i & csr_mcontrol_wr_req[trig];
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if(~rst_n) begin
|
||||
csr_mcontrol_dmode_ff [trig] <= 1'b0;
|
||||
csr_mcontrol_m_ff [trig] <= 1'b0;
|
||||
csr_mcontrol_exec_ff [trig] <= 1'b0;
|
||||
csr_mcontrol_load_ff [trig] <= 1'b0;
|
||||
csr_mcontrol_store_ff [trig] <= 1'b0;
|
||||
csr_mcontrol_action_ff[trig] <= 1'b0;
|
||||
csr_mcontrol_hit_ff [trig] <= 1'b0;
|
||||
end else if(csr_mcontrol_clk_en[trig]) begin
|
||||
csr_mcontrol_dmode_ff [trig] <= csr_mcontrol_dmode_next[trig];
|
||||
csr_mcontrol_m_ff [trig] <= csr_mcontrol_m_next[trig];
|
||||
csr_mcontrol_exec_ff [trig] <= csr_mcontrol_exec_next[trig];
|
||||
csr_mcontrol_load_ff [trig] <= csr_mcontrol_load_next[trig];
|
||||
csr_mcontrol_store_ff [trig] <= csr_mcontrol_store_next[trig];
|
||||
csr_mcontrol_action_ff[trig] <= csr_mcontrol_action_next[trig];
|
||||
csr_mcontrol_hit_ff [trig] <= csr_mcontrol_hit_next[trig];
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if (csr_mcontrol_upd[trig]) begin
|
||||
csr_mcontrol_dmode_next [trig] = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
|
||||
csr_mcontrol_m_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_M];
|
||||
csr_mcontrol_exec_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_EXECUTE];
|
||||
csr_mcontrol_load_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_LOAD];
|
||||
csr_mcontrol_store_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_STORE];
|
||||
csr_mcontrol_action_next[trig] = (csr_wr_data[SCR1_TDU_MCONTROL_ACTION_HI
|
||||
:SCR1_TDU_MCONTROL_ACTION_LO] == 'b1);
|
||||
csr_mcontrol_hit_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_HIT];
|
||||
end else begin
|
||||
csr_mcontrol_dmode_next [trig] = csr_mcontrol_dmode_ff [trig];
|
||||
csr_mcontrol_m_next [trig] = csr_mcontrol_m_ff [trig];
|
||||
csr_mcontrol_exec_next [trig] = csr_mcontrol_exec_ff [trig];
|
||||
csr_mcontrol_load_next [trig] = csr_mcontrol_load_ff [trig];
|
||||
csr_mcontrol_store_next [trig] = csr_mcontrol_store_ff [trig];
|
||||
csr_mcontrol_action_next[trig] = csr_mcontrol_action_ff[trig];
|
||||
csr_mcontrol_hit_next [trig] = exu2tdu_bp_retire_i[trig]
|
||||
? 1'b1
|
||||
: csr_mcontrol_hit_ff[trig];
|
||||
end
|
||||
end
|
||||
|
||||
// TDATA2 register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_tdata2_upd[trig] = ~csr_mcontrol_dmode_ff[trig]
|
||||
? clk_en & csr_addr_tdata2[trig] & csr_wr_req
|
||||
: clk_en & csr_addr_tdata2[trig] & csr_wr_req & tdu_dsbl_i;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (csr_tdata2_upd[trig]) begin
|
||||
csr_tdata2_ff[trig] <= csr_wr_data;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate // gblock_mtrig
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TDU <-> EXU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign csr_icount_hit = ~tdu_dsbl_i & csr_icount_m_ff
|
||||
? exu2tdu_imon_i.vd & (csr_icount_count_ff == 14'b1) & ~csr_icount_skip_ff
|
||||
: 1'b0;
|
||||
|
||||
`ifndef SCR1_TDU_ICOUNT_EN
|
||||
assign tdu2exu_ibrkpt_match_o = csr_mcontrol_exec_hit;
|
||||
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
|
||||
`else
|
||||
assign tdu2exu_ibrkpt_match_o = {csr_icount_hit, csr_mcontrol_exec_hit};
|
||||
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TDU <-> LSU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Breakpoint logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
generate
|
||||
for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_break_trig
|
||||
assign csr_mcontrol_exec_hit[trig] = ~tdu_dsbl_i
|
||||
& csr_mcontrol_m_ff[trig]
|
||||
& csr_mcontrol_exec_ff[trig]
|
||||
& exu2tdu_imon_i.vd
|
||||
& exu2tdu_imon_i.addr == csr_tdata2_ff[trig];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
`ifndef SCR1_TDU_ICOUNT_EN
|
||||
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
|
||||
`else
|
||||
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
|
||||
// Watchpoint logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
generate
|
||||
for( trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig ) begin : gblock_watch_trig
|
||||
assign csr_mcontrol_ldst_hit[trig] = ~tdu_dsbl_i
|
||||
& csr_mcontrol_m_ff[trig]
|
||||
& lsu2tdu_dmon_i.vd
|
||||
& ( (csr_mcontrol_load_ff [trig] & lsu2tdu_dmon_i.load)
|
||||
| (csr_mcontrol_store_ff[trig] & lsu2tdu_dmon_i.store))
|
||||
& lsu2tdu_dmon_i.addr == csr_tdata2_ff[trig];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign tdu2lsu_dbrkpt_match_o = csr_mcontrol_ldst_hit;
|
||||
assign tdu2lsu_dbrkpt_exc_req_o = |csr_mcontrol_ldst_hit;
|
||||
|
||||
`ifndef SCR1_TDU_EN
|
||||
assign tdu2lsu_brk_en_o = |csr_mcontrol_m_ff | csr_icount_m_ff;
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TDU <-> HDU interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
tdu2hdu_dmode_req_o = 1'b0;
|
||||
|
||||
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
|
||||
tdu2hdu_dmode_req_o |= (csr_mcontrol_action_ff[i] & exu2tdu_bp_retire_i[i]);
|
||||
end
|
||||
`ifdef SCR1_TDU_ICOUNT_EN
|
||||
tdu2hdu_dmode_req_o |= (csr_icount_action_ff & exu2tdu_bp_retire_i[ALLTRIG_NUM-1]);
|
||||
`endif // SCR1_TDU_ICOUNT_EN
|
||||
end
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
SVA_TDU_X_CONTROL : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({clk_en, tdu_dsbl_i, csr2tdu_req_i,
|
||||
exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i})
|
||||
) else $error("TDU Error: control signals is X - %0b", {clk_en,
|
||||
tdu_dsbl_i, csr2tdu_req_i, exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i});
|
||||
|
||||
SVA_DM_X_CLK_EN : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(clk_en)
|
||||
) else $error("TDU Error: clk_en control signals is X");
|
||||
|
||||
SVA_DM_X_DSBL : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(tdu_dsbl_i)
|
||||
) else $error("TDU Error: tdu_dsbl_i control signals is X");
|
||||
|
||||
SVA_DM_X_CSR2TDU_REQ : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(csr2tdu_req_i)
|
||||
) else $error("TDU Error: csr2tdu_req_i control signals is X");
|
||||
|
||||
SVA_DM_X_I_MON_VD : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(exu2tdu_imon_i.vd)
|
||||
) else $error("TDU Error: exu2tdu_imon_i.vd control signals is X");
|
||||
|
||||
SVA_DM_X_D_MON_VD : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(lsu2tdu_dmon_i.vd)
|
||||
) else $error("TDU Error: lsu2tdu_dmon_i.vd control signals is X");
|
||||
|
||||
SVA_DM_X_BP_RETIRE : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown(exu2tdu_bp_retire_i)
|
||||
) else $error("TDU Error: exu2tdu_bp_retire_i control signals is X");
|
||||
|
||||
SVA_TDU_X_CSR : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
csr2tdu_req_i |-> !$isunknown({csr2tdu_cmd_i,csr2tdu_addr_i})
|
||||
) else $error("TDU Error: csr is X");
|
||||
|
||||
SVA_TDU_XW_CSR : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
(csr2tdu_req_i & csr_wr_req) |-> !$isunknown(csr2tdu_wdata_i)
|
||||
) else $error("TDU Error: csr wdata is X ");
|
||||
|
||||
SVA_TDU_X_IMON : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
exu2tdu_imon_i.vd |-> !$isunknown({exu2tdu_imon_i.req,exu2tdu_imon_i.addr})
|
||||
) else $error("TDU Error: imonitor is X");
|
||||
|
||||
SVA_TDU_X_DMON : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
lsu2tdu_dmon_i.vd |-> !$isunknown({lsu2tdu_dmon_i})
|
||||
) else $error("TDU Error: dmonitor is X");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_tdu
|
||||
|
||||
`endif // SCR1_TDU_EN
|
||||
825
src_ref/core/pipeline/scr1_pipe_top.sv
Normal file
825
src_ref/core/pipeline/scr1_pipe_top.sv
Normal file
@@ -0,0 +1,825 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_pipe_top.sv>
|
||||
/// @brief SCR1 pipeline top
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_memif.svh"
|
||||
`include "scr1_riscv_isa_decoding.svh"
|
||||
`include "scr1_csr.svh"
|
||||
|
||||
`ifdef SCR1_IPIC_EN
|
||||
`include "scr1_ipic.svh"
|
||||
`endif // SCR1_IPIC_EN
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_hdu.svh"
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
`include "scr1_tdu.svh"
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
module scr1_pipe_top (
|
||||
// Common
|
||||
input logic pipe_rst_n, // Pipe reset
|
||||
`ifdef SCR1_DBG_EN
|
||||
input logic pipe2hdu_rdc_qlfy_i, // Pipe RDC qualifier
|
||||
input logic dbg_rst_n, // Debug reset
|
||||
`endif // SCR1_DBG_EN
|
||||
input logic clk, // Pipe clock
|
||||
|
||||
// Instruction Memory Interface
|
||||
output logic pipe2imem_req_o, // IMEM request
|
||||
output type_scr1_mem_cmd_e pipe2imem_cmd_o, // IMEM command
|
||||
output logic [`SCR1_IMEM_AWIDTH-1:0] pipe2imem_addr_o, // IMEM address
|
||||
input logic imem2pipe_req_ack_i, // IMEM request acknowledge
|
||||
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2pipe_rdata_i, // IMEM read data
|
||||
input type_scr1_mem_resp_e imem2pipe_resp_i, // IMEM response
|
||||
|
||||
// Data Memory Interface
|
||||
output logic pipe2dmem_req_o, // DMEM request
|
||||
output type_scr1_mem_cmd_e pipe2dmem_cmd_o, // DMEM command
|
||||
output type_scr1_mem_width_e pipe2dmem_width_o, // DMEM data width
|
||||
output logic [`SCR1_DMEM_AWIDTH-1:0] pipe2dmem_addr_o, // DMEM address
|
||||
output logic [`SCR1_DMEM_DWIDTH-1:0] pipe2dmem_wdata_o, // DMEM write data
|
||||
input logic dmem2pipe_req_ack_i, // DMEM request acknowledge
|
||||
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2pipe_rdata_i, // DMEM read data
|
||||
input type_scr1_mem_resp_e dmem2pipe_resp_i, // DMEM response
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Debug interface:
|
||||
input logic dbg_en, // 1 - debug operations enabled
|
||||
// DM <-> Pipeline: HART Run Control i/f
|
||||
input logic dm2pipe_active_i, // Debug Module active flag
|
||||
|
||||
input logic dm2pipe_cmd_req_i, // Request from Debug Module
|
||||
input type_scr1_hdu_dbgstates_e dm2pipe_cmd_i, // Command from Debug Module
|
||||
output logic pipe2dm_cmd_resp_o, // Response to Debug Module
|
||||
output logic pipe2dm_cmd_rcode_o, // Debug Module return code: 0 - Ok; 1 - Error
|
||||
output logic pipe2dm_hart_event_o, // HART event flag
|
||||
output type_scr1_hdu_hartstatus_s pipe2dm_hart_status_o, // HART status
|
||||
|
||||
// DM <-> Pipeline: Program Buffer - HART instruction execution i/f
|
||||
output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pipe2dm_pbuf_addr_o, // Program Buffer address
|
||||
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2pipe_pbuf_instr_i, // Program Buffer instruction
|
||||
|
||||
// DM <-> Pipeline: HART Abstract Data regs i/f
|
||||
output logic pipe2dm_dreg_req_o, // Abstract Data Register request
|
||||
output logic pipe2dm_dreg_wr_o, // Abstract Data Register write
|
||||
output logic [`SCR1_XLEN-1:0] pipe2dm_dreg_wdata_o, // Abstract Data Register write data
|
||||
input logic dm2pipe_dreg_resp_i, // Abstract Data Register response
|
||||
input logic dm2pipe_dreg_fail_i, // Abstract Data Register fail - possibly not needed?
|
||||
input logic [`SCR1_XLEN-1:0] dm2pipe_dreg_rdata_i, // Abstract Data Register read data
|
||||
|
||||
// DM <-> Pipeling: PC i/f
|
||||
output logic [`SCR1_XLEN-1:0] pipe2dm_pc_sample_o, // Current PC for sampling
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// IRQ
|
||||
`ifdef SCR1_IPIC_EN
|
||||
input logic [SCR1_IRQ_LINES_NUM-1:0] soc2pipe_irq_lines_i, // External interrupt request lines
|
||||
`else // SCR1_IPIC_EN
|
||||
input logic soc2pipe_irq_ext_i, // External interrupt request
|
||||
`endif // SCR1_IPIC_EN
|
||||
input logic soc2pipe_irq_soft_i, // Software generated interrupt request
|
||||
input logic soc2pipe_irq_mtimer_i, // Machine timer interrupt request
|
||||
|
||||
// Memory-mapped external timer
|
||||
input logic [63:0] soc2pipe_mtimer_val_i, // Machine timer value
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
// CLK_CTRL interface
|
||||
output logic pipe2clkctl_sleep_req_o, // CLK disable request to CLK gating circuit
|
||||
output logic pipe2clkctl_wake_req_o, // CLK enable request to CLK gating circuit
|
||||
input logic clkctl2pipe_clk_alw_on_i, // Not gated CLK
|
||||
input logic clkctl2pipe_clk_dbgc_i, // CLK for HDU (not gated for now)
|
||||
input logic clkctl2pipe_clk_en_i, // CLK enabled flag
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// Fuse
|
||||
input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i // Fuse MHARTID value
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// Pipeline control
|
||||
logic [`SCR1_XLEN-1:0] curr_pc; // Current PC
|
||||
logic [`SCR1_XLEN-1:0] next_pc; // Is written to MEPC on interrupt trap
|
||||
logic new_pc_req; // New PC request (jumps, branches, traps etc)
|
||||
logic [`SCR1_XLEN-1:0] new_pc; // New PC
|
||||
|
||||
logic stop_fetch; // Stop IFU
|
||||
logic exu_exc_req; // Exception request
|
||||
logic brkpt; // Breakpoint (sw) on current instruction
|
||||
logic exu_init_pc; // Reset exit
|
||||
logic wfi_run2halt; // Transition to WFI halted state
|
||||
logic instret; // Instruction retirement (with or without exception)
|
||||
`ifndef SCR1_CSR_REDUCED_CNT
|
||||
logic instret_nexc; // Instruction retirement (without exception)
|
||||
`endif // SCR1_CSR_REDUCED_CNT
|
||||
`ifdef SCR1_IPIC_EN
|
||||
logic ipic2csr_irq; // IRQ request from IPIC
|
||||
`endif // SCR1_IPIC_EN
|
||||
`ifdef SCR1_TDU_EN
|
||||
`ifdef SCR1_DBG_EN
|
||||
logic brkpt_hw; // Hardware breakpoint on current instruction
|
||||
`endif // SCR1_DBG_EN
|
||||
`endif // SCR1_TDU_EN
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
logic imem_txns_pending; // There are pending imem transactions
|
||||
logic wfi_halted; // WFI halted state
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// IFU <-> IDU
|
||||
logic ifu2idu_vd; // IFU request
|
||||
logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr; // IFU instruction
|
||||
logic ifu2idu_imem_err; // IFU instruction access fault
|
||||
logic ifu2idu_err_rvi_hi; // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
|
||||
logic idu2ifu_rdy; // IDU ready for new data
|
||||
|
||||
// IDU <-> EXU
|
||||
logic idu2exu_req; // IDU request
|
||||
type_scr1_exu_cmd_s idu2exu_cmd; // IDU command (see scr1_riscv_isa_decoding.svh)
|
||||
logic idu2exu_use_rs1; // Instruction uses rs1
|
||||
logic idu2exu_use_rs2; // Instruction uses rs2
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
logic idu2exu_use_rd; // Instruction uses rd
|
||||
logic idu2exu_use_imm; // Instruction uses immediate
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
logic exu2idu_rdy; // EXU ready for new data
|
||||
|
||||
// EXU <-> MPRF
|
||||
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr; // MPRF rs1 read address
|
||||
logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data; // MPRF rs1 read data
|
||||
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr; // MPRF rs2 read address
|
||||
logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data; // MPRF rs2 read data
|
||||
logic exu2mprf_w_req; // MPRF write request
|
||||
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr; // MPRF rd write address
|
||||
logic [`SCR1_XLEN-1:0] exu2mprf_rd_data; // MPRF rd write data
|
||||
|
||||
// EXU <-> CSR
|
||||
logic [SCR1_CSR_ADDR_WIDTH-1:0] exu2csr_rw_addr; // CSR read/write address
|
||||
logic exu2csr_r_req; // CSR read request
|
||||
logic [`SCR1_XLEN-1:0] csr2exu_r_data; // CSR read data
|
||||
logic exu2csr_w_req; // CSR write request
|
||||
type_scr1_csr_cmd_sel_e exu2csr_w_cmd; // CSR write command
|
||||
logic [`SCR1_XLEN-1:0] exu2csr_w_data; // CSR write data
|
||||
logic csr2exu_rw_exc; // CSR read/write access exception
|
||||
|
||||
// EXU <-> CSR event interface
|
||||
logic exu2csr_take_irq; // Take IRQ trap
|
||||
logic exu2csr_take_exc; // Take exception trap
|
||||
logic exu2csr_mret_update; // MRET update CSR
|
||||
logic exu2csr_mret_instr; // MRET instruction
|
||||
type_scr1_exc_code_e exu2csr_exc_code; // Exception code (see scr1_arch_types.svh)
|
||||
logic [`SCR1_XLEN-1:0] exu2csr_trap_val; // Trap value
|
||||
logic [`SCR1_XLEN-1:0] csr2exu_new_pc; // Exception/IRQ/MRET new PC
|
||||
logic csr2exu_irq; // IRQ request
|
||||
logic csr2exu_ip_ie; // Some IRQ pending and locally enabled
|
||||
logic csr2exu_mstatus_mie_up; // MSTATUS or MIE update in the current cycle
|
||||
|
||||
`ifdef SCR1_IPIC_EN
|
||||
// CSR <-> IPIC
|
||||
logic csr2ipic_r_req; // IPIC read request
|
||||
logic csr2ipic_w_req; // IPIC write request
|
||||
logic [2:0] csr2ipic_addr; // IPIC address
|
||||
logic [`SCR1_XLEN-1:0] csr2ipic_wdata; // IPIC write data
|
||||
logic [`SCR1_XLEN-1:0] ipic2csr_rdata; // IPIC read data
|
||||
`endif // SCR1_IPIC_EN
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
// CSR <-> TDU
|
||||
logic csr2tdu_req; // Request to TDU
|
||||
type_scr1_csr_cmd_sel_e csr2tdu_cmd; // TDU command
|
||||
logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr; // TDU address
|
||||
logic [`SCR1_XLEN-1:0] csr2tdu_wdata; // TDU write data
|
||||
logic [`SCR1_XLEN-1:0] tdu2csr_rdata; // TDU read data
|
||||
type_scr1_csr_resp_e tdu2csr_resp; // TDU response
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Qualified TDU input signals from pipe_rst_n
|
||||
// reset domain:
|
||||
logic csr2tdu_req_qlfy; // Request to TDU
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// EXU/LSU <-> TDU
|
||||
type_scr1_brkm_instr_mon_s exu2tdu_i_mon; // Instruction monitor
|
||||
type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon; // Data monitor
|
||||
logic [SCR1_TDU_ALLTRIG_NUM-1:0] tdu2exu_i_match; // Instruction breakpoint(s) match
|
||||
logic [SCR1_TDU_MTRIG_NUM-1:0] tdu2lsu_d_match; // Data breakpoint(s) match
|
||||
logic tdu2exu_i_x_req; // Instruction breakpoint exception
|
||||
logic tdu2lsu_i_x_req; // Instruction breakpoint exception
|
||||
logic tdu2lsu_d_x_req; // Data breakpoint exception
|
||||
logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire; // Instruction with breakpoint flag retire
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Qualified TDU input signals from pipe_rst_n
|
||||
// reset domain:
|
||||
type_scr1_brkm_instr_mon_s exu2tdu_i_mon_qlfy; // Instruction monitor
|
||||
type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon_qlfy; // Data monitor
|
||||
logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire_qlfy; // Instruction with breakpoint flag retire
|
||||
`endif // SCR1_DBG_EN
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Debug signals:
|
||||
logic fetch_pbuf; // Fetch instructions provided by Program Buffer (via HDU)
|
||||
logic csr2hdu_req; // Request to HDU
|
||||
type_scr1_csr_cmd_sel_e csr2hdu_cmd; // HDU command
|
||||
logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr; // HDU address
|
||||
logic [`SCR1_XLEN-1:0] csr2hdu_wdata; // HDU write data
|
||||
logic [`SCR1_XLEN-1:0] hdu2csr_rdata; // HDU read data
|
||||
type_scr1_csr_resp_e hdu2csr_resp; // HDU response
|
||||
// Qualified HDU input signals from pipe_rst_n
|
||||
// reset domain:
|
||||
logic csr2hdu_req_qlfy; // Request to HDU
|
||||
|
||||
logic hwbrk_dsbl; // Disables TDU
|
||||
logic hdu_hwbrk_dsbl; // Disables TDU
|
||||
logic tdu2hdu_dmode_req; // TDU requests transition to debug mode
|
||||
|
||||
logic exu_no_commit; // Forbid instruction commitment
|
||||
logic exu_irq_dsbl; // Disable IRQ
|
||||
logic exu_pc_advmt_dsbl; // Forbid PC advancement
|
||||
logic exu_dmode_sstep_en; // Enable single-step
|
||||
|
||||
logic dbg_halted; // Debug halted state
|
||||
logic dbg_run2halt; // Transition to debug halted state
|
||||
logic dbg_halt2run; // Transition to run state
|
||||
logic dbg_run_start; // First cycle of run state
|
||||
logic [`SCR1_XLEN-1:0] dbg_new_pc; // New PC as starting point for HART Resume
|
||||
|
||||
logic ifu2hdu_pbuf_rdy;
|
||||
logic hdu2ifu_pbuf_vd;
|
||||
logic hdu2ifu_pbuf_err;
|
||||
logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr;
|
||||
|
||||
// Qualified HDU input signals from pipe_rst_n reset domain:
|
||||
logic ifu2hdu_pbuf_rdy_qlfy;
|
||||
logic exu_busy_qlfy;
|
||||
logic instret_qlfy;
|
||||
logic exu_init_pc_qlfy;
|
||||
logic exu_exc_req_qlfy;
|
||||
logic brkpt_qlfy;
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
logic exu_busy;
|
||||
|
||||
|
||||
`ifndef SCR1_CLKCTRL_EN
|
||||
logic pipe2clkctl_wake_req_o;
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Pipeline logic
|
||||
//-------------------------------------------------------------------------------
|
||||
assign stop_fetch = wfi_run2halt
|
||||
`ifdef SCR1_DBG_EN
|
||||
| fetch_pbuf
|
||||
`endif // SCR1_DBG_EN
|
||||
;
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
assign pipe2clkctl_sleep_req_o = wfi_halted & ~imem_txns_pending;
|
||||
assign pipe2clkctl_wake_req_o = csr2exu_ip_ie
|
||||
`ifdef SCR1_DBG_EN
|
||||
| dm2pipe_active_i
|
||||
`endif // SCR1_DBG_EN
|
||||
;
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
assign pipe2dm_pc_sample_o = curr_pc;
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Instruction fetch unit
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_ifu i_pipe_ifu (
|
||||
.rst_n (pipe_rst_n ),
|
||||
.clk (clk ),
|
||||
|
||||
// Instruction memory interface
|
||||
.imem2ifu_req_ack_i (imem2pipe_req_ack_i),
|
||||
.ifu2imem_req_o (pipe2imem_req_o ),
|
||||
.ifu2imem_cmd_o (pipe2imem_cmd_o ),
|
||||
.ifu2imem_addr_o (pipe2imem_addr_o ),
|
||||
.imem2ifu_rdata_i (imem2pipe_rdata_i ),
|
||||
.imem2ifu_resp_i (imem2pipe_resp_i ),
|
||||
|
||||
// New PC interface
|
||||
.exu2ifu_pc_new_req_i (new_pc_req ),
|
||||
.exu2ifu_pc_new_i (new_pc ),
|
||||
.pipe2ifu_stop_fetch_i (stop_fetch ),
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// IFU <-> HDU Program Buffer interface
|
||||
.hdu2ifu_pbuf_fetch_i (fetch_pbuf ),
|
||||
.ifu2hdu_pbuf_rdy_o (ifu2hdu_pbuf_rdy ),
|
||||
.hdu2ifu_pbuf_vd_i (hdu2ifu_pbuf_vd ),
|
||||
.hdu2ifu_pbuf_err_i (hdu2ifu_pbuf_err ),
|
||||
.hdu2ifu_pbuf_instr_i (hdu2ifu_pbuf_instr ),
|
||||
`endif // SCR1_DBG_EN
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.ifu2pipe_imem_txns_pnd_o (imem_txns_pending ),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// IFU <-> IDU interface
|
||||
.idu2ifu_rdy_i (idu2ifu_rdy ),
|
||||
.ifu2idu_instr_o (ifu2idu_instr ),
|
||||
.ifu2idu_imem_err_o (ifu2idu_imem_err ),
|
||||
.ifu2idu_err_rvi_hi_o (ifu2idu_err_rvi_hi ),
|
||||
.ifu2idu_vd_o (ifu2idu_vd )
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Instruction decode unit
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_idu i_pipe_idu (
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
.rst_n (pipe_rst_n ),
|
||||
.clk (clk ),
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
.idu2ifu_rdy_o (idu2ifu_rdy ),
|
||||
.ifu2idu_instr_i (ifu2idu_instr ),
|
||||
.ifu2idu_imem_err_i (ifu2idu_imem_err ),
|
||||
.ifu2idu_err_rvi_hi_i (ifu2idu_err_rvi_hi),
|
||||
.ifu2idu_vd_i (ifu2idu_vd ),
|
||||
|
||||
.idu2exu_req_o (idu2exu_req ),
|
||||
.idu2exu_cmd_o (idu2exu_cmd ),
|
||||
.idu2exu_use_rs1_o (idu2exu_use_rs1 ),
|
||||
.idu2exu_use_rs2_o (idu2exu_use_rs2 ),
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
.idu2exu_use_rd_o (idu2exu_use_rd ),
|
||||
.idu2exu_use_imm_o (idu2exu_use_imm ),
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
.exu2idu_rdy_i (exu2idu_rdy )
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Execution unit
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_exu i_pipe_exu (
|
||||
.rst_n (pipe_rst_n ),
|
||||
.clk (clk ),
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.clk_alw_on (clkctl2pipe_clk_alw_on_i),
|
||||
.clk_pipe_en (clkctl2pipe_clk_en_i),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// IDU <-> EXU interface
|
||||
.idu2exu_req_i (idu2exu_req ),
|
||||
.exu2idu_rdy_o (exu2idu_rdy ),
|
||||
.idu2exu_cmd_i (idu2exu_cmd ),
|
||||
.idu2exu_use_rs1_i (idu2exu_use_rs1 ),
|
||||
.idu2exu_use_rs2_i (idu2exu_use_rs2 ),
|
||||
`ifndef SCR1_NO_EXE_STAGE
|
||||
.idu2exu_use_rd_i (idu2exu_use_rd ),
|
||||
.idu2exu_use_imm_i (idu2exu_use_imm ),
|
||||
`endif // SCR1_NO_EXE_STAGE
|
||||
|
||||
// EXU <-> MPRF interface
|
||||
.exu2mprf_rs1_addr_o (exu2mprf_rs1_addr ),
|
||||
.mprf2exu_rs1_data_i (mprf2exu_rs1_data ),
|
||||
.exu2mprf_rs2_addr_o (exu2mprf_rs2_addr ),
|
||||
.mprf2exu_rs2_data_i (mprf2exu_rs2_data ),
|
||||
.exu2mprf_w_req_o (exu2mprf_w_req ),
|
||||
.exu2mprf_rd_addr_o (exu2mprf_rd_addr ),
|
||||
.exu2mprf_rd_data_o (exu2mprf_rd_data ),
|
||||
|
||||
// EXU <-> CSR read/write interface
|
||||
.exu2csr_rw_addr_o (exu2csr_rw_addr ),
|
||||
.exu2csr_r_req_o (exu2csr_r_req ),
|
||||
.csr2exu_r_data_i (csr2exu_r_data ),
|
||||
.exu2csr_w_req_o (exu2csr_w_req ),
|
||||
.exu2csr_w_cmd_o (exu2csr_w_cmd ),
|
||||
.exu2csr_w_data_o (exu2csr_w_data ),
|
||||
.csr2exu_rw_exc_i (csr2exu_rw_exc ),
|
||||
|
||||
// EXU <-> CSR event interface
|
||||
.exu2csr_take_irq_o (exu2csr_take_irq ),
|
||||
.exu2csr_take_exc_o (exu2csr_take_exc ),
|
||||
.exu2csr_mret_update_o (exu2csr_mret_update ),
|
||||
.exu2csr_mret_instr_o (exu2csr_mret_instr ),
|
||||
.exu2csr_exc_code_o (exu2csr_exc_code ),
|
||||
.exu2csr_trap_val_o (exu2csr_trap_val ),
|
||||
.csr2exu_new_pc_i (csr2exu_new_pc ),
|
||||
.csr2exu_irq_i (csr2exu_irq ),
|
||||
.csr2exu_ip_ie_i (csr2exu_ip_ie ),
|
||||
.csr2exu_mstatus_mie_up_i (csr2exu_mstatus_mie_up ),
|
||||
|
||||
// EXU <-> DMEM interface
|
||||
.exu2dmem_req_o (pipe2dmem_req_o ),
|
||||
.exu2dmem_cmd_o (pipe2dmem_cmd_o ),
|
||||
.exu2dmem_width_o (pipe2dmem_width_o ),
|
||||
.exu2dmem_addr_o (pipe2dmem_addr_o ),
|
||||
.exu2dmem_wdata_o (pipe2dmem_wdata_o ),
|
||||
.dmem2exu_req_ack_i (dmem2pipe_req_ack_i ),
|
||||
.dmem2exu_rdata_i (dmem2pipe_rdata_i ),
|
||||
.dmem2exu_resp_i (dmem2pipe_resp_i ),
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// EXU <-> HDU interface
|
||||
.hdu2exu_no_commit_i (exu_no_commit ),
|
||||
.hdu2exu_irq_dsbl_i (exu_irq_dsbl ),
|
||||
.hdu2exu_pc_advmt_dsbl_i (exu_pc_advmt_dsbl ),
|
||||
.hdu2exu_dmode_sstep_en_i (exu_dmode_sstep_en ),
|
||||
.hdu2exu_pbuf_fetch_i (fetch_pbuf ),
|
||||
.hdu2exu_dbg_halted_i (dbg_halted ),
|
||||
.hdu2exu_dbg_run2halt_i (dbg_run2halt ),
|
||||
.hdu2exu_dbg_halt2run_i (dbg_halt2run ),
|
||||
.hdu2exu_dbg_run_start_i (dbg_run_start ),
|
||||
.hdu2exu_dbg_new_pc_i (dbg_new_pc ),
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
// EXU <-> TDU interface
|
||||
.exu2tdu_imon_o (exu2tdu_i_mon ),
|
||||
.tdu2exu_ibrkpt_match_i (tdu2exu_i_match ),
|
||||
.tdu2exu_ibrkpt_exc_req_i (tdu2exu_i_x_req ),
|
||||
.lsu2tdu_dmon_o (lsu2tdu_d_mon ),
|
||||
.tdu2lsu_ibrkpt_exc_req_i (tdu2lsu_i_x_req ),
|
||||
.tdu2lsu_dbrkpt_match_i (tdu2lsu_d_match ),
|
||||
.tdu2lsu_dbrkpt_exc_req_i (tdu2lsu_d_x_req ),
|
||||
.exu2tdu_ibrkpt_ret_o (exu2tdu_bp_retire ),
|
||||
`ifdef SCR1_DBG_EN
|
||||
.exu2hdu_ibrkpt_hw_o (brkpt_hw ),
|
||||
`endif // SCR1_DBG_EN
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
// EXU control
|
||||
.exu2pipe_exc_req_o (exu_exc_req ),
|
||||
.exu2pipe_brkpt_o (brkpt ),
|
||||
.exu2pipe_init_pc_o (exu_init_pc ),
|
||||
.exu2pipe_wfi_run2halt_o (wfi_run2halt ),
|
||||
.exu2pipe_instret_o (instret ),
|
||||
`ifndef SCR1_CSR_REDUCED_CNT
|
||||
.exu2csr_instret_no_exc_o (instret_nexc ),
|
||||
`endif // SCR1_CSR_REDUCED_CNT
|
||||
.exu2pipe_exu_busy_o (exu_busy ),
|
||||
|
||||
// PC interface
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.exu2pipe_wfi_halted_o (wfi_halted ),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
.exu2pipe_pc_curr_o (curr_pc ),
|
||||
.exu2csr_pc_next_o (next_pc ),
|
||||
.exu2ifu_pc_new_req_o (new_pc_req ),
|
||||
.exu2ifu_pc_new_o (new_pc )
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Multi-port register file
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_mprf i_pipe_mprf (
|
||||
`ifdef SCR1_MPRF_RST_EN
|
||||
.rst_n (pipe_rst_n ),
|
||||
`endif // SCR1_MPRF_RST_EN
|
||||
.clk (clk ),
|
||||
|
||||
// EXU <-> MPRF interface
|
||||
.exu2mprf_rs1_addr_i (exu2mprf_rs1_addr),
|
||||
.mprf2exu_rs1_data_o (mprf2exu_rs1_data),
|
||||
.exu2mprf_rs2_addr_i (exu2mprf_rs2_addr),
|
||||
.mprf2exu_rs2_data_o (mprf2exu_rs2_data),
|
||||
.exu2mprf_w_req_i (exu2mprf_w_req ),
|
||||
.exu2mprf_rd_addr_i (exu2mprf_rd_addr ),
|
||||
.exu2mprf_rd_data_i (exu2mprf_rd_data )
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Control and status registers
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_csr i_pipe_csr (
|
||||
.rst_n (pipe_rst_n ),
|
||||
.clk (clk ),
|
||||
`ifndef SCR1_CSR_REDUCED_CNT
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.clk_alw_on (clkctl2pipe_clk_alw_on_i),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
`endif // SCR1_CSR_REDUCED_CNT
|
||||
|
||||
// EXU <-> CSR read/write interface
|
||||
.exu2csr_r_req_i (exu2csr_r_req ),
|
||||
.exu2csr_rw_addr_i (exu2csr_rw_addr ),
|
||||
.csr2exu_r_data_o (csr2exu_r_data ),
|
||||
.exu2csr_w_req_i (exu2csr_w_req ),
|
||||
.exu2csr_w_cmd_i (exu2csr_w_cmd ),
|
||||
.exu2csr_w_data_i (exu2csr_w_data ),
|
||||
.csr2exu_rw_exc_o (csr2exu_rw_exc ),
|
||||
|
||||
// EXU <-> CSR event interface
|
||||
.exu2csr_take_irq_i (exu2csr_take_irq ),
|
||||
.exu2csr_take_exc_i (exu2csr_take_exc ),
|
||||
.exu2csr_mret_update_i (exu2csr_mret_update ),
|
||||
.exu2csr_mret_instr_i (exu2csr_mret_instr ),
|
||||
.exu2csr_exc_code_i (exu2csr_exc_code ),
|
||||
.exu2csr_trap_val_i (exu2csr_trap_val ),
|
||||
.csr2exu_new_pc_o (csr2exu_new_pc ),
|
||||
.csr2exu_irq_o (csr2exu_irq ),
|
||||
.csr2exu_ip_ie_o (csr2exu_ip_ie ),
|
||||
.csr2exu_mstatus_mie_up_o (csr2exu_mstatus_mie_up ),
|
||||
|
||||
`ifdef SCR1_IPIC_EN
|
||||
// CSR <-> IPIC interface
|
||||
.csr2ipic_r_req_o (csr2ipic_r_req ),
|
||||
.csr2ipic_w_req_o (csr2ipic_w_req ),
|
||||
.csr2ipic_addr_o (csr2ipic_addr ),
|
||||
.csr2ipic_wdata_o (csr2ipic_wdata ),
|
||||
.ipic2csr_rdata_i (ipic2csr_rdata ),
|
||||
`endif // SCR1_IPIC_EN
|
||||
|
||||
// CSR <-> PC interface
|
||||
.exu2csr_pc_curr_i (curr_pc ),
|
||||
.exu2csr_pc_next_i (next_pc ),
|
||||
`ifndef SCR1_CSR_REDUCED_CNT
|
||||
.exu2csr_instret_no_exc_i (instret_nexc ),
|
||||
`endif // SCR1_CSR_REDUCED_CNT
|
||||
|
||||
// IRQ
|
||||
`ifdef SCR1_IPIC_EN
|
||||
.soc2csr_irq_ext_i (ipic2csr_irq ),
|
||||
`else // SCR1_IPIC_EN
|
||||
.soc2csr_irq_ext_i (soc2pipe_irq_ext_i ),
|
||||
`endif // SCR1_IPIC_EN
|
||||
.soc2csr_irq_soft_i (soc2pipe_irq_soft_i ),
|
||||
.soc2csr_irq_mtimer_i (soc2pipe_irq_mtimer_i ),
|
||||
|
||||
// Memory-mapped external timer
|
||||
.soc2csr_mtimer_val_i (soc2pipe_mtimer_val_i ),
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// CSR <-> HDU interface
|
||||
.csr2hdu_req_o (csr2hdu_req ),
|
||||
.csr2hdu_cmd_o (csr2hdu_cmd ),
|
||||
.csr2hdu_addr_o (csr2hdu_addr ),
|
||||
.csr2hdu_wdata_o (csr2hdu_wdata ),
|
||||
.hdu2csr_rdata_i (hdu2csr_rdata ),
|
||||
.hdu2csr_resp_i (hdu2csr_resp ),
|
||||
.hdu2csr_no_commit_i (exu_no_commit ),
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_TDU_EN
|
||||
// CSR <-> TDU interface
|
||||
.csr2tdu_req_o (csr2tdu_req ),
|
||||
.csr2tdu_cmd_o (csr2tdu_cmd ),
|
||||
.csr2tdu_addr_o (csr2tdu_addr ),
|
||||
.csr2tdu_wdata_o (csr2tdu_wdata ),
|
||||
.tdu2csr_rdata_i (tdu2csr_rdata ),
|
||||
.tdu2csr_resp_i (tdu2csr_resp ),
|
||||
`endif // SCR1_TDU_EN
|
||||
.soc2csr_fuse_mhartid_i (soc2pipe_fuse_mhartid_i )
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Integrated programmable interrupt controller
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_IPIC_EN
|
||||
scr1_ipic i_pipe_ipic (
|
||||
.rst_n (pipe_rst_n ),
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.clk (clkctl2pipe_clk_alw_on_i),
|
||||
`else // SCR1_CLKCTRL_EN
|
||||
.clk (clk ),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
.soc2ipic_irq_lines_i (soc2pipe_irq_lines_i ),
|
||||
.csr2ipic_r_req_i (csr2ipic_r_req ),
|
||||
.csr2ipic_w_req_i (csr2ipic_w_req ),
|
||||
.csr2ipic_addr_i (csr2ipic_addr ),
|
||||
.csr2ipic_wdata_i (csr2ipic_wdata ),
|
||||
.ipic2csr_rdata_o (ipic2csr_rdata ),
|
||||
.ipic2csr_irq_m_req_o (ipic2csr_irq )
|
||||
);
|
||||
`endif // SCR1_IPIC_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Breakpoint module
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_TDU_EN
|
||||
scr1_pipe_tdu i_pipe_tdu (
|
||||
// Common signals
|
||||
`ifdef SCR1_DBG_EN
|
||||
.rst_n (dbg_rst_n ),
|
||||
`else
|
||||
.rst_n (pipe_rst_n ),
|
||||
`endif // SCR1_DBG_EN
|
||||
.clk (clk ),
|
||||
.clk_en (1'b1 ),
|
||||
`ifdef SCR1_DBG_EN
|
||||
.tdu_dsbl_i (hwbrk_dsbl ),
|
||||
`else // SCR1_DBG_EN
|
||||
.tdu_dsbl_i (1'b0 ),
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// TDU <-> CSR interface
|
||||
`ifdef SCR1_DBG_EN
|
||||
.csr2tdu_req_i (csr2tdu_req_qlfy ),
|
||||
.csr2tdu_cmd_i (csr2tdu_cmd ),
|
||||
.csr2tdu_addr_i (csr2tdu_addr ),
|
||||
.csr2tdu_wdata_i (csr2tdu_wdata ),
|
||||
`else // SCR1_DBG_EN
|
||||
.csr2tdu_req_i (csr2tdu_req ),
|
||||
.csr2tdu_cmd_i (csr2tdu_cmd ),
|
||||
.csr2tdu_addr_i (csr2tdu_addr ),
|
||||
.csr2tdu_wdata_i (csr2tdu_wdata ),
|
||||
`endif // SCR1_DBG_EN
|
||||
.tdu2csr_rdata_o (tdu2csr_rdata ),
|
||||
.tdu2csr_resp_o (tdu2csr_resp ),
|
||||
|
||||
// TDU <-> EXU interface
|
||||
`ifdef SCR1_DBG_EN
|
||||
.exu2tdu_imon_i (exu2tdu_i_mon_qlfy ),
|
||||
`else // SCR1_DBG_EN
|
||||
.exu2tdu_imon_i (exu2tdu_i_mon ),
|
||||
`endif // SCR1_DBG_EN
|
||||
.tdu2exu_ibrkpt_match_o (tdu2exu_i_match ),
|
||||
.tdu2exu_ibrkpt_exc_req_o (tdu2exu_i_x_req ),
|
||||
`ifdef SCR1_DBG_EN
|
||||
.exu2tdu_bp_retire_i (exu2tdu_bp_retire_qlfy),
|
||||
`else // SCR1_DBG_EN
|
||||
.exu2tdu_bp_retire_i (exu2tdu_bp_retire ),
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// TDU <-> LSU interface
|
||||
.tdu2lsu_ibrkpt_exc_req_o (tdu2lsu_i_x_req ),
|
||||
`ifdef SCR1_DBG_EN
|
||||
.lsu2tdu_dmon_i (lsu2tdu_d_mon_qlfy ),
|
||||
`else // SCR1_DBG_EN
|
||||
.lsu2tdu_dmon_i (lsu2tdu_d_mon ),
|
||||
`endif // SCR1_DBG_EN
|
||||
.tdu2lsu_dbrkpt_match_o (tdu2lsu_d_match ),
|
||||
.tdu2lsu_dbrkpt_exc_req_o (tdu2lsu_d_x_req ),
|
||||
// EPU I/F
|
||||
`ifdef SCR1_DBG_EN
|
||||
.tdu2hdu_dmode_req_o (tdu2hdu_dmode_req )
|
||||
`else // SCR1_DBG_EN
|
||||
.tdu2hdu_dmode_req_o ( )
|
||||
`endif // SCR1_DBG_EN
|
||||
);
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
assign hwbrk_dsbl = (~dbg_en) | hdu_hwbrk_dsbl;
|
||||
//
|
||||
assign csr2tdu_req_qlfy = dbg_en & csr2tdu_req & pipe2hdu_rdc_qlfy_i;
|
||||
//
|
||||
assign exu2tdu_i_mon_qlfy.vd = exu2tdu_i_mon.vd & pipe2hdu_rdc_qlfy_i;
|
||||
assign exu2tdu_i_mon_qlfy.req = exu2tdu_i_mon.req;
|
||||
assign exu2tdu_i_mon_qlfy.addr = exu2tdu_i_mon.addr;
|
||||
assign lsu2tdu_d_mon_qlfy.vd = lsu2tdu_d_mon.vd & pipe2hdu_rdc_qlfy_i;
|
||||
assign lsu2tdu_d_mon_qlfy.load = lsu2tdu_d_mon.load;
|
||||
assign lsu2tdu_d_mon_qlfy.store = lsu2tdu_d_mon.store;
|
||||
assign lsu2tdu_d_mon_qlfy.addr = lsu2tdu_d_mon.addr;
|
||||
assign exu2tdu_bp_retire_qlfy = exu2tdu_bp_retire & {$bits(exu2tdu_bp_retire){pipe2hdu_rdc_qlfy_i}};
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// HART Debug Unit (HDU)
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_DBG_EN
|
||||
scr1_pipe_hdu i_pipe_hdu (
|
||||
// Common signals
|
||||
.rst_n (dbg_rst_n ),
|
||||
.clk_en (dm2pipe_active_i ),
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
.clk_pipe_en (clkctl2pipe_clk_en_i ),
|
||||
.clk (clkctl2pipe_clk_dbgc_i),
|
||||
`else
|
||||
.clk (clk ),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// Control/status registers i/f
|
||||
.csr2hdu_req_i (csr2hdu_req_qlfy ),
|
||||
.csr2hdu_cmd_i (csr2hdu_cmd ),
|
||||
.csr2hdu_addr_i (csr2hdu_addr ),
|
||||
.csr2hdu_wdata_i (csr2hdu_wdata ),
|
||||
.hdu2csr_resp_o (hdu2csr_resp ),
|
||||
.hdu2csr_rdata_o (hdu2csr_rdata ),
|
||||
|
||||
// HART Run Control i/f
|
||||
.pipe2hdu_rdc_qlfy_i (pipe2hdu_rdc_qlfy_i ),
|
||||
.dm2hdu_cmd_req_i (dm2pipe_cmd_req_i ),
|
||||
.dm2hdu_cmd_i (dm2pipe_cmd_i ),
|
||||
.hdu2dm_cmd_resp_o (pipe2dm_cmd_resp_o ),
|
||||
.hdu2dm_cmd_rcode_o (pipe2dm_cmd_rcode_o ),
|
||||
.hdu2dm_hart_event_o (pipe2dm_hart_event_o ),
|
||||
.hdu2dm_hart_status_o (pipe2dm_hart_status_o ),
|
||||
|
||||
// Program Buffer - HART instruction execution i/f
|
||||
.hdu2dm_pbuf_addr_o (pipe2dm_pbuf_addr_o ),
|
||||
.dm2hdu_pbuf_instr_i (dm2pipe_pbuf_instr_i ),
|
||||
|
||||
// HART Abstract Data regs i/f
|
||||
.hdu2dm_dreg_req_o (pipe2dm_dreg_req_o ),
|
||||
.hdu2dm_dreg_wr_o (pipe2dm_dreg_wr_o ),
|
||||
.hdu2dm_dreg_wdata_o (pipe2dm_dreg_wdata_o ),
|
||||
.dm2hdu_dreg_resp_i (dm2pipe_dreg_resp_i ),
|
||||
.dm2hdu_dreg_fail_i (dm2pipe_dreg_fail_i ),
|
||||
.dm2hdu_dreg_rdata_i (dm2pipe_dreg_rdata_i ),
|
||||
//
|
||||
`ifdef SCR1_TDU_EN
|
||||
// HDU <-> TDU interface
|
||||
.hdu2tdu_hwbrk_dsbl_o (hdu_hwbrk_dsbl ),
|
||||
.tdu2hdu_dmode_req_i (tdu2hdu_dmode_req ),
|
||||
.exu2hdu_ibrkpt_hw_i (brkpt_hw ),
|
||||
`endif // SCR1_TDU_EN
|
||||
|
||||
// HART Run Status
|
||||
.pipe2hdu_exu_busy_i (exu_busy_qlfy ),
|
||||
.pipe2hdu_instret_i (instret_qlfy ),
|
||||
.pipe2hdu_init_pc_i (exu_init_pc_qlfy ),
|
||||
|
||||
// HART Halt Status
|
||||
.pipe2hdu_exu_exc_req_i (exu_exc_req_qlfy ),
|
||||
.pipe2hdu_brkpt_i (brkpt_qlfy ),
|
||||
|
||||
// HART Run Control
|
||||
.hdu2exu_pbuf_fetch_o (fetch_pbuf ),
|
||||
.hdu2exu_no_commit_o (exu_no_commit ),
|
||||
.hdu2exu_irq_dsbl_o (exu_irq_dsbl ),
|
||||
.hdu2exu_pc_advmt_dsbl_o (exu_pc_advmt_dsbl ),
|
||||
.hdu2exu_dmode_sstep_en_o (exu_dmode_sstep_en ),
|
||||
|
||||
// HART state
|
||||
.hdu2exu_dbg_halted_o (dbg_halted ),
|
||||
.hdu2exu_dbg_run2halt_o (dbg_run2halt ),
|
||||
.hdu2exu_dbg_halt2run_o (dbg_halt2run ),
|
||||
.hdu2exu_dbg_run_start_o (dbg_run_start ),
|
||||
|
||||
// PC interface
|
||||
.pipe2hdu_pc_curr_i (curr_pc ),
|
||||
.hdu2exu_dbg_new_pc_o (dbg_new_pc ),
|
||||
|
||||
// Prgram Buffer Instruction interface
|
||||
.ifu2hdu_pbuf_instr_rdy_i (ifu2hdu_pbuf_rdy_qlfy ),
|
||||
.hdu2ifu_pbuf_instr_vd_o (hdu2ifu_pbuf_vd ),
|
||||
.hdu2ifu_pbuf_instr_err_o (hdu2ifu_pbuf_err ),
|
||||
.hdu2ifu_pbuf_instr_o (hdu2ifu_pbuf_instr )
|
||||
);
|
||||
|
||||
assign csr2hdu_req_qlfy = csr2hdu_req & dbg_en & pipe2hdu_rdc_qlfy_i;
|
||||
//
|
||||
assign exu_busy_qlfy = exu_busy & {$bits(exu_busy){pipe2hdu_rdc_qlfy_i}};
|
||||
assign instret_qlfy = instret & {$bits(instret){pipe2hdu_rdc_qlfy_i}};
|
||||
assign exu_init_pc_qlfy = exu_init_pc & {$bits(exu_init_pc){pipe2hdu_rdc_qlfy_i}};
|
||||
assign exu_exc_req_qlfy = exu_exc_req & {$bits(exu_exc_req){pipe2hdu_rdc_qlfy_i}};
|
||||
assign brkpt_qlfy = brkpt & {$bits(brkpt){pipe2hdu_rdc_qlfy_i}};
|
||||
assign ifu2hdu_pbuf_rdy_qlfy = ifu2hdu_pbuf_rdy & {$bits(ifu2hdu_pbuf_rdy){pipe2hdu_rdc_qlfy_i}};
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Tracelog
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
scr1_tracelog i_tracelog (
|
||||
.rst_n (pipe_rst_n ),
|
||||
.clk (clk )
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
,
|
||||
.soc2pipe_fuse_mhartid_i (soc2pipe_fuse_mhartid_i ),
|
||||
|
||||
// MPRF
|
||||
.mprf2trace_int_i (i_pipe_mprf.mprf_int ),
|
||||
.mprf2trace_wr_en_i (i_pipe_mprf.exu2mprf_w_req_i ),
|
||||
.mprf2trace_wr_addr_i (i_pipe_mprf.exu2mprf_rd_addr_i ),
|
||||
.mprf2trace_wr_data_i (i_pipe_mprf.exu2mprf_rd_data_i ),
|
||||
|
||||
// EXU
|
||||
.exu2trace_update_pc_en_i (i_pipe_exu.update_pc_en ),
|
||||
.exu2trace_update_pc_i (i_pipe_exu.update_pc ),
|
||||
|
||||
// IFU
|
||||
.ifu2trace_instr_i (i_pipe_ifu.ifu2idu_instr_o ),
|
||||
|
||||
// CSR
|
||||
.csr2trace_mstatus_mie_i (i_pipe_csr.csr_mstatus_mie_ff ),
|
||||
.csr2trace_mstatus_mpie_i (i_pipe_csr.csr_mstatus_mpie_ff ),
|
||||
.csr2trace_mtvec_base_i (i_pipe_csr.csr_mtvec_base ),
|
||||
.csr2trace_mtvec_mode_i (i_pipe_csr.csr_mtvec_mode ),
|
||||
.csr2trace_mie_meie_i (i_pipe_csr.csr_mie_meie_ff ),
|
||||
.csr2trace_mie_mtie_i (i_pipe_csr.csr_mie_mtie_ff ),
|
||||
.csr2trace_mie_msie_i (i_pipe_csr.csr_mie_msie_ff ),
|
||||
.csr2trace_mip_meip_i (i_pipe_csr.csr_mip_meip ),
|
||||
.csr2trace_mip_mtip_i (i_pipe_csr.csr_mip_mtip ),
|
||||
.csr2trace_mip_msip_i (i_pipe_csr.csr_mip_msip ),
|
||||
.csr2trace_mepc_i (i_pipe_csr.csr_mepc_ff ),
|
||||
.csr2trace_mcause_irq_i (i_pipe_csr.csr_mcause_i_ff ),
|
||||
.csr2trace_mcause_ec_i (i_pipe_csr.csr_mcause_ec_ff ),
|
||||
.csr2trace_mtval_i (i_pipe_csr.csr_mtval_ff ),
|
||||
|
||||
// Events
|
||||
.csr2trace_e_exc_i (i_pipe_csr.e_exc ),
|
||||
.csr2trace_e_irq_i (i_pipe_csr.e_irq ),
|
||||
.pipe2trace_e_wake_i (pipe2clkctl_wake_req_o )
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
);
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_pipe_top
|
||||
453
src_ref/core/pipeline/scr1_tracelog.sv
Normal file
453
src_ref/core/pipeline/scr1_tracelog.sv
Normal file
@@ -0,0 +1,453 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_tracelog.sv>
|
||||
/// @brief Core tracelog module
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_arch_types.svh"
|
||||
`include "scr1_csr.svh"
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
|
||||
module scr1_tracelog (
|
||||
input logic rst_n, // Tracelog reset
|
||||
input logic clk // Tracelog clock
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
,
|
||||
input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i, // Fuse MHARTID
|
||||
|
||||
// MPRF
|
||||
`ifdef SCR1_MPRF_RAM
|
||||
input logic [`SCR1_XLEN-1:0] mprf2trace_int_i [1:`SCR1_MPRF_SIZE-1], // MPRF registers content
|
||||
`else // SCR1_MPRF_RAM
|
||||
input type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf2trace_int_i, // MPRF registers content
|
||||
`endif // SCR1_MPRF_RAM
|
||||
input logic mprf2trace_wr_en_i, // MPRF write enable
|
||||
input logic [`SCR1_MPRF_AWIDTH-1:0] mprf2trace_wr_addr_i, // MPRF write address
|
||||
input logic [`SCR1_XLEN-1:0] mprf2trace_wr_data_i, // MPRF write data
|
||||
|
||||
// EXU
|
||||
input logic exu2trace_update_pc_en_i, // PC updated flag
|
||||
input logic [`SCR1_XLEN-1:0] exu2trace_update_pc_i, // Next PC value
|
||||
|
||||
// IFU
|
||||
input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2trace_instr_i, // Current instruction from IFU stage
|
||||
|
||||
// CSR
|
||||
input logic csr2trace_mstatus_mie_i, // CSR MSTATUS.mie bit
|
||||
input logic csr2trace_mstatus_mpie_i, // CSR MSTATUS.mpie bit
|
||||
input logic [`SCR1_XLEN-1:6] csr2trace_mtvec_base_i, // CSR MTVEC.
|
||||
input logic csr2trace_mtvec_mode_i, // CSR MTVEC.
|
||||
input logic csr2trace_mie_meie_i, // CSR MIE.meie bit
|
||||
input logic csr2trace_mie_mtie_i, // CSR MIE.mtie bit
|
||||
input logic csr2trace_mie_msie_i, // CSR MIE.msie bit
|
||||
input logic csr2trace_mip_meip_i, // CSR MIP.meip bit
|
||||
input logic csr2trace_mip_mtip_i, // CSR MIP.mtip bit
|
||||
input logic csr2trace_mip_msip_i, // CSR MIP.msip bit
|
||||
`ifdef SCR1_RVC_EXT
|
||||
input logic [`SCR1_XLEN-1:1] csr2trace_mepc_i, // CSR MEPC register
|
||||
`else // SCR1_RVC_EXT
|
||||
input logic [`SCR1_XLEN-1:2] csr2trace_mepc_i, // CSR MEPC register
|
||||
`endif // SCR1_RVC_EXT
|
||||
input logic csr2trace_mcause_irq_i, // CSR MCAUSE.interrupt bit
|
||||
input type_scr1_exc_code_e csr2trace_mcause_ec_i, // CSR MCAUSE.exception_code bit
|
||||
input logic [`SCR1_XLEN-1:0] csr2trace_mtval_i, // CSR MTVAL register
|
||||
|
||||
// Events
|
||||
input logic csr2trace_e_exc_i, // exception event
|
||||
input logic csr2trace_e_irq_i, // interrupt event
|
||||
input logic pipe2trace_e_wake_i // pipe wakeup event
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local types declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
typedef struct {
|
||||
logic [`SCR1_XLEN-1:0] INT_00_ZERO ;
|
||||
logic [`SCR1_XLEN-1:0] INT_01_RA ;
|
||||
logic [`SCR1_XLEN-1:0] INT_02_SP ;
|
||||
logic [`SCR1_XLEN-1:0] INT_03_GP ;
|
||||
logic [`SCR1_XLEN-1:0] INT_04_TP ;
|
||||
logic [`SCR1_XLEN-1:0] INT_05_T0 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_06_T1 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_07_T2 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_08_S0 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_09_S1 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_10_A0 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_11_A1 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_12_A2 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_13_A3 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_14_A4 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_15_A5 ;
|
||||
`ifndef SCR1_RVE_EXT
|
||||
logic [`SCR1_XLEN-1:0] INT_16_A6 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_17_A7 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_18_S2 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_19_S3 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_20_S4 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_21_S5 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_22_S6 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_23_S7 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_24_S8 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_25_S9 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_26_S10 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_27_S11 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_28_T3 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_29_T4 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_30_T5 ;
|
||||
logic [`SCR1_XLEN-1:0] INT_31_T6 ;
|
||||
`endif // SCR1_RVE_EXT
|
||||
} type_scr1_ireg_name_s;
|
||||
|
||||
typedef struct packed {
|
||||
logic [`SCR1_XLEN-1:0] mstatus;
|
||||
logic [`SCR1_XLEN-1:0] mtvec;
|
||||
logic [`SCR1_XLEN-1:0] mie;
|
||||
logic [`SCR1_XLEN-1:0] mip;
|
||||
logic [`SCR1_XLEN-1:0] mepc;
|
||||
logic [`SCR1_XLEN-1:0] mcause;
|
||||
logic [`SCR1_XLEN-1:0] mtval;
|
||||
} type_scr1_csr_trace_s;
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local Signal Declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
|
||||
type_scr1_ireg_name_s mprf_int_alias;
|
||||
|
||||
|
||||
time current_time;
|
||||
|
||||
// Tracelog control signals
|
||||
logic trace_flag;
|
||||
logic trace_update;
|
||||
logic trace_update_r;
|
||||
byte event_type;
|
||||
|
||||
logic [`SCR1_XLEN-1:0] trace_pc;
|
||||
logic [`SCR1_XLEN-1:0] trace_npc;
|
||||
logic [`SCR1_IMEM_DWIDTH-1:0] trace_instr;
|
||||
|
||||
type_scr1_csr_trace_s csr_trace1;
|
||||
|
||||
// File handlers
|
||||
int unsigned trace_fhandler_core;
|
||||
|
||||
// MPRF signals
|
||||
logic mprf_up;
|
||||
logic [`SCR1_MPRF_AWIDTH-1:0] mprf_addr;
|
||||
logic [`SCR1_XLEN-1:0] mprf_wdata;
|
||||
|
||||
string hart;
|
||||
string test_name;
|
||||
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local tasks
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
|
||||
task trace_write_common;
|
||||
$fwrite(trace_fhandler_core, "%16d ", current_time);
|
||||
// $fwrite(trace_fhandler_core, " 0 ");
|
||||
$fwrite(trace_fhandler_core, " %s ", event_type);
|
||||
$fwrite(trace_fhandler_core, " %8x ", trace_pc);
|
||||
$fwrite(trace_fhandler_core, " %8x ", trace_instr);
|
||||
$fwrite(trace_fhandler_core, " %8x ", trace_npc);
|
||||
endtask // trace_write_common
|
||||
|
||||
task trace_write_int_walias;
|
||||
case (mprf_addr)
|
||||
0 : $fwrite(trace_fhandler_core, " x00_zero ");
|
||||
1 : $fwrite(trace_fhandler_core, " x01_ra ");
|
||||
2 : $fwrite(trace_fhandler_core, " x02_sp ");
|
||||
3 : $fwrite(trace_fhandler_core, " x03_gp ");
|
||||
4 : $fwrite(trace_fhandler_core, " x04_tp ");
|
||||
5 : $fwrite(trace_fhandler_core, " x05_t0 ");
|
||||
6 : $fwrite(trace_fhandler_core, " x06_t1 ");
|
||||
7 : $fwrite(trace_fhandler_core, " x07_t2 ");
|
||||
8 : $fwrite(trace_fhandler_core, " x08_s0 ");
|
||||
9 : $fwrite(trace_fhandler_core, " x09_s1 ");
|
||||
10 : $fwrite(trace_fhandler_core, " x10_a0 ");
|
||||
11 : $fwrite(trace_fhandler_core, " x11_a1 ");
|
||||
12 : $fwrite(trace_fhandler_core, " x12_a2 ");
|
||||
13 : $fwrite(trace_fhandler_core, " x13_a3 ");
|
||||
14 : $fwrite(trace_fhandler_core, " x14_a4 ");
|
||||
15 : $fwrite(trace_fhandler_core, " x15_a5 ");
|
||||
`ifndef SCR1_RVE_EXT
|
||||
16 : $fwrite(trace_fhandler_core, " x16_a6 ");
|
||||
17 : $fwrite(trace_fhandler_core, " x17_a7 ");
|
||||
18 : $fwrite(trace_fhandler_core, " x18_s2 ");
|
||||
19 : $fwrite(trace_fhandler_core, " x19_s3 ");
|
||||
20 : $fwrite(trace_fhandler_core, " x20_s4 ");
|
||||
21 : $fwrite(trace_fhandler_core, " x21_s5 ");
|
||||
22 : $fwrite(trace_fhandler_core, " x22_s6 ");
|
||||
23 : $fwrite(trace_fhandler_core, " x23_s7 ");
|
||||
24 : $fwrite(trace_fhandler_core, " x24_s8 ");
|
||||
25 : $fwrite(trace_fhandler_core, " x25_s9 ");
|
||||
26 : $fwrite(trace_fhandler_core, " x26_s10 ");
|
||||
27 : $fwrite(trace_fhandler_core, " x27_s11 ");
|
||||
28 : $fwrite(trace_fhandler_core, " x28_t3 ");
|
||||
29 : $fwrite(trace_fhandler_core, " x29_t4 ");
|
||||
30 : $fwrite(trace_fhandler_core, " x30_t5 ");
|
||||
31 : $fwrite(trace_fhandler_core, " x31_t6 ");
|
||||
`endif // SCR1_RVE_EXT
|
||||
default: begin
|
||||
$fwrite(trace_fhandler_core, " xxx ");
|
||||
end
|
||||
endcase
|
||||
endtask
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// MPRF Registers assignment
|
||||
//-------------------------------------------------------------------------------
|
||||
assign mprf_int_alias.INT_00_ZERO = '0;
|
||||
assign mprf_int_alias.INT_01_RA = mprf2trace_int_i[1];
|
||||
assign mprf_int_alias.INT_02_SP = mprf2trace_int_i[2];
|
||||
assign mprf_int_alias.INT_03_GP = mprf2trace_int_i[3];
|
||||
assign mprf_int_alias.INT_04_TP = mprf2trace_int_i[4];
|
||||
assign mprf_int_alias.INT_05_T0 = mprf2trace_int_i[5];
|
||||
assign mprf_int_alias.INT_06_T1 = mprf2trace_int_i[6];
|
||||
assign mprf_int_alias.INT_07_T2 = mprf2trace_int_i[7];
|
||||
assign mprf_int_alias.INT_08_S0 = mprf2trace_int_i[8];
|
||||
assign mprf_int_alias.INT_09_S1 = mprf2trace_int_i[9];
|
||||
assign mprf_int_alias.INT_10_A0 = mprf2trace_int_i[10];
|
||||
assign mprf_int_alias.INT_11_A1 = mprf2trace_int_i[11];
|
||||
assign mprf_int_alias.INT_12_A2 = mprf2trace_int_i[12];
|
||||
assign mprf_int_alias.INT_13_A3 = mprf2trace_int_i[13];
|
||||
assign mprf_int_alias.INT_14_A4 = mprf2trace_int_i[14];
|
||||
assign mprf_int_alias.INT_15_A5 = mprf2trace_int_i[15];
|
||||
`ifndef SCR1_RVE_EXT
|
||||
assign mprf_int_alias.INT_16_A6 = mprf2trace_int_i[16];
|
||||
assign mprf_int_alias.INT_17_A7 = mprf2trace_int_i[17];
|
||||
assign mprf_int_alias.INT_18_S2 = mprf2trace_int_i[18];
|
||||
assign mprf_int_alias.INT_19_S3 = mprf2trace_int_i[19];
|
||||
assign mprf_int_alias.INT_20_S4 = mprf2trace_int_i[20];
|
||||
assign mprf_int_alias.INT_21_S5 = mprf2trace_int_i[21];
|
||||
assign mprf_int_alias.INT_22_S6 = mprf2trace_int_i[22];
|
||||
assign mprf_int_alias.INT_23_S7 = mprf2trace_int_i[23];
|
||||
assign mprf_int_alias.INT_24_S8 = mprf2trace_int_i[24];
|
||||
assign mprf_int_alias.INT_25_S9 = mprf2trace_int_i[25];
|
||||
assign mprf_int_alias.INT_26_S10 = mprf2trace_int_i[26];
|
||||
assign mprf_int_alias.INT_27_S11 = mprf2trace_int_i[27];
|
||||
assign mprf_int_alias.INT_28_T3 = mprf2trace_int_i[28];
|
||||
assign mprf_int_alias.INT_29_T4 = mprf2trace_int_i[29];
|
||||
assign mprf_int_alias.INT_30_T5 = mprf2trace_int_i[30];
|
||||
assign mprf_int_alias.INT_31_T6 = mprf2trace_int_i[31];
|
||||
`endif // SCR1_RVE_EXT
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Legacy time counter
|
||||
//-------------------------------------------------------------------------------
|
||||
// The counter is left for compatibility with the current UVM environment
|
||||
|
||||
int time_cnt;
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
time_cnt <= 0;
|
||||
end else begin
|
||||
time_cnt <= time_cnt + 1;
|
||||
end
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Initial part pipeline tracelog
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
`ifdef SCR1_TRACE_LOG_EN
|
||||
// Files opening and writing initial header
|
||||
initial begin
|
||||
$timeformat(-9, 0, " ns", 10);
|
||||
#1 hart.hextoa(soc2pipe_fuse_mhartid_i);
|
||||
|
||||
trace_fhandler_core = $fopen({"tracelog_core_", hart, ".log"}, "w");
|
||||
|
||||
// Writing initial header
|
||||
$fwrite(trace_fhandler_core, "# RTL_ID %h\n", SCR1_CSR_MIMPID);
|
||||
$fwrite(trace_fhandler_core, "#\n");
|
||||
// $fwrite(trace_fhandler_core, "# R - return from trap:\n");
|
||||
// $fwrite(trace_fhandler_core, "# 1 - MRET\n");
|
||||
// $fwrite(trace_fhandler_core, "# 0 - no return\n");
|
||||
$fwrite(trace_fhandler_core, "# Events:\n");
|
||||
$fwrite(trace_fhandler_core, "# N - no event\n");
|
||||
$fwrite(trace_fhandler_core, "# E - exception\n");
|
||||
$fwrite(trace_fhandler_core, "# I - interrupt\n");
|
||||
$fwrite(trace_fhandler_core, "# W - wakeup\n");
|
||||
end
|
||||
|
||||
// Core reset logging and header printing
|
||||
always @(posedge rst_n) begin
|
||||
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
|
||||
`ifndef VERILATOR
|
||||
$fwrite(trace_fhandler_core, "# %16d ns : Core Reset\n", $time());
|
||||
`else
|
||||
$fwrite(trace_fhandler_core, "# : Core Reset\n");
|
||||
`endif
|
||||
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
|
||||
$fwrite(trace_fhandler_core, "# Test: %s\n", test_name);
|
||||
$fwrite(trace_fhandler_core, "# Time ");
|
||||
// $fwrite(trace_fhandler_core, " R ");
|
||||
$fwrite(trace_fhandler_core, " Ev ");
|
||||
$fwrite(trace_fhandler_core, " Curr_PC ");
|
||||
$fwrite(trace_fhandler_core, " Instr ");
|
||||
$fwrite(trace_fhandler_core, " Next_PC ");
|
||||
$fwrite(trace_fhandler_core, " Reg ");
|
||||
$fwrite(trace_fhandler_core, " Value ");
|
||||
$fwrite(trace_fhandler_core, "\n");
|
||||
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Common trace part
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
assign trace_flag = 1'b1;
|
||||
assign trace_update = (exu2trace_update_pc_en_i | mprf2trace_wr_en_i) & trace_flag;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
current_time <= 0;
|
||||
event_type <= "N";
|
||||
|
||||
trace_pc <= 'x;
|
||||
trace_npc <= 'x;
|
||||
trace_instr <= 'x;
|
||||
|
||||
trace_update_r <= 1'b0;
|
||||
|
||||
mprf_up <= '0;
|
||||
mprf_addr <= '0;
|
||||
mprf_wdata <= '0;
|
||||
end else begin
|
||||
trace_update_r <= trace_update;
|
||||
if (trace_update) begin
|
||||
`ifdef VERILATOR
|
||||
current_time <= time_cnt;
|
||||
`else
|
||||
current_time <= $time();
|
||||
`endif
|
||||
trace_pc <= trace_npc;
|
||||
trace_npc <= exu2trace_update_pc_i;
|
||||
trace_instr <= ifu2trace_instr_i;
|
||||
|
||||
if (csr2trace_e_exc_i) begin
|
||||
// Exception
|
||||
event_type <= "E";
|
||||
end
|
||||
else if (csr2trace_e_irq_i) begin
|
||||
// IRQ
|
||||
event_type <= "I";
|
||||
end
|
||||
else if (pipe2trace_e_wake_i) begin
|
||||
// Wake
|
||||
event_type <= "W";
|
||||
end
|
||||
else begin
|
||||
// No event
|
||||
event_type <= "N";
|
||||
end
|
||||
end
|
||||
|
||||
// Write log signals
|
||||
mprf_up <= mprf2trace_wr_en_i;
|
||||
mprf_addr <= mprf2trace_wr_en_i ? mprf2trace_wr_addr_i : 'x;
|
||||
mprf_wdata <= mprf2trace_wr_en_i ? mprf2trace_wr_data_i : 'x;
|
||||
end
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Core MPRF logging
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge rst_n, posedge clk) begin
|
||||
if (~rst_n) begin
|
||||
end else begin
|
||||
if (trace_update_r) begin
|
||||
|
||||
trace_write_common();
|
||||
|
||||
case (event_type)
|
||||
"W" : begin
|
||||
// Wakeup
|
||||
if (csr_trace1.mip & csr_trace1.mie) begin
|
||||
$fwrite(trace_fhandler_core, " mip %08x\n", csr_trace1.mip );
|
||||
trace_write_common();
|
||||
$fwrite(trace_fhandler_core, " mie %08x", csr_trace1.mie );
|
||||
end
|
||||
end
|
||||
"N" : begin
|
||||
// Regular
|
||||
if (mprf_up && mprf_addr != 0) begin
|
||||
// $fwrite(trace_fhandler_core, " x%2d %08x", mprf_addr, mprf_wdata);
|
||||
trace_write_int_walias();
|
||||
$fwrite(trace_fhandler_core, " %08x", mprf_wdata);
|
||||
end else begin
|
||||
$fwrite(trace_fhandler_core, " --- --------");
|
||||
end
|
||||
end
|
||||
"R" : begin
|
||||
// MRET
|
||||
$fwrite(trace_fhandler_core, " mstatus %08x", csr_trace1.mstatus);
|
||||
end
|
||||
"E", "I": begin
|
||||
// IRQ/Exception
|
||||
$fwrite(trace_fhandler_core, " mstatus %08x\n", csr_trace1.mstatus);
|
||||
trace_write_common();
|
||||
$fwrite(trace_fhandler_core, " mepc %08x\n", csr_trace1.mepc);
|
||||
trace_write_common();
|
||||
$fwrite(trace_fhandler_core, " mcause %08x\n", csr_trace1.mcause);
|
||||
trace_write_common();
|
||||
$fwrite(trace_fhandler_core, " mtval %08x", csr_trace1.mtval);
|
||||
end
|
||||
default : begin
|
||||
$fwrite(trace_fhandler_core, "\n");
|
||||
end
|
||||
endcase
|
||||
$fwrite(trace_fhandler_core, "\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Core CSR logging
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
csr_trace1.mtvec = {csr2trace_mtvec_base_i, 4'd0, 2'(csr2trace_mtvec_mode_i)};
|
||||
csr_trace1.mepc =
|
||||
`ifdef SCR1_RVC_EXT
|
||||
{csr2trace_mepc_i, 1'b0};
|
||||
`else // SCR1_RVC_EXT
|
||||
{csr2trace_mepc_i, 2'b00};
|
||||
`endif // SCR1_RVC_EXT
|
||||
csr_trace1.mcause = {csr2trace_mcause_irq_i, type_scr1_csr_mcause_ec_v'(csr2trace_mcause_ec_i)};
|
||||
csr_trace1.mtval = csr2trace_mtval_i;
|
||||
|
||||
csr_trace1.mstatus = '0;
|
||||
csr_trace1.mie = '0;
|
||||
csr_trace1.mip = '0;
|
||||
|
||||
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MIE_OFFSET] = csr2trace_mstatus_mie_i;
|
||||
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPIE_OFFSET] = csr2trace_mstatus_mpie_i;
|
||||
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPP_OFFSET+1:SCR1_CSR_MSTATUS_MPP_OFFSET] = SCR1_CSR_MSTATUS_MPP;
|
||||
csr_trace1.mie[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mie_msie_i;
|
||||
csr_trace1.mie[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mie_mtie_i;
|
||||
csr_trace1.mie[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mie_meie_i;
|
||||
csr_trace1.mip[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mip_msip_i;
|
||||
csr_trace1.mip[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mip_mtip_i;
|
||||
csr_trace1.mip[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mip_meip_i;
|
||||
end
|
||||
|
||||
`endif // SCR1_TRACE_LOG_EN
|
||||
|
||||
endmodule : scr1_tracelog
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
32
src_ref/core/primitives/scr1_cg.sv
Normal file
32
src_ref/core/primitives/scr1_cg.sv
Normal file
@@ -0,0 +1,32 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_cg.sv>
|
||||
/// @brief SCR1 clock gate primitive
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
module scr1_cg (
|
||||
input logic clk,
|
||||
input logic clk_en,
|
||||
input logic test_mode,
|
||||
output logic clk_out
|
||||
);
|
||||
|
||||
// The code below is a clock gate model for simulation.
|
||||
// For synthesis, it should be replaced by implementation-specific
|
||||
// clock gate code.
|
||||
|
||||
logic latch_en;
|
||||
|
||||
always_latch begin
|
||||
if (~clk) begin
|
||||
latch_en <= test_mode | clk_en;
|
||||
end
|
||||
end
|
||||
|
||||
assign clk_out = latch_en & clk;
|
||||
|
||||
endmodule : scr1_cg
|
||||
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
231
src_ref/core/primitives/scr1_reset_cells.sv
Normal file
231
src_ref/core/primitives/scr1_reset_cells.sv
Normal file
@@ -0,0 +1,231 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_sync_rstn.sv>
|
||||
/// @brief Cells for reset handling
|
||||
///
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Reset Buffer Cell
|
||||
//--------------------------------------------------------------------
|
||||
module scr1_reset_buf_cell (
|
||||
input logic rst_n,
|
||||
input logic clk,
|
||||
input logic test_mode,
|
||||
input logic test_rst_n,
|
||||
input logic reset_n_in,
|
||||
output logic reset_n_out,
|
||||
output logic reset_n_status
|
||||
);
|
||||
|
||||
logic reset_n_ff;
|
||||
logic reset_n_status_ff;
|
||||
logic rst_n_mux;
|
||||
|
||||
assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n;
|
||||
|
||||
always_ff @(negedge rst_n_mux, posedge clk) begin
|
||||
if (~rst_n_mux) begin
|
||||
reset_n_ff <= 1'b0;
|
||||
end else begin
|
||||
reset_n_ff <= reset_n_in;
|
||||
end
|
||||
end
|
||||
|
||||
assign reset_n_out = (test_mode == 1'b1) ? test_rst_n : reset_n_ff;
|
||||
|
||||
always_ff @(negedge rst_n_mux, posedge clk) begin
|
||||
if (~rst_n_mux) begin
|
||||
reset_n_status_ff <= 1'b0;
|
||||
end else begin
|
||||
reset_n_status_ff <= reset_n_in;
|
||||
end
|
||||
end
|
||||
assign reset_n_status = reset_n_status_ff;
|
||||
|
||||
endmodule : scr1_reset_buf_cell
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Reset CDC Synchronization Cell
|
||||
//--------------------------------------------------------------------
|
||||
module scr1_reset_sync_cell #(
|
||||
parameter int unsigned STAGES_AMOUNT = 2
|
||||
) (
|
||||
input logic rst_n,
|
||||
input logic clk,
|
||||
input logic test_rst_n,
|
||||
input logic test_mode,
|
||||
input logic rst_n_in,
|
||||
output logic rst_n_out
|
||||
);
|
||||
|
||||
logic [STAGES_AMOUNT-1:0] rst_n_dff;
|
||||
logic local_rst_n_in;
|
||||
|
||||
assign local_rst_n_in = (test_mode == 1'b1) ? test_rst_n : rst_n;
|
||||
|
||||
generate
|
||||
|
||||
if (STAGES_AMOUNT == 1)
|
||||
|
||||
begin : gen_reset_sync_cell_single
|
||||
always_ff @(negedge local_rst_n_in, posedge clk) begin
|
||||
if (~local_rst_n_in) begin
|
||||
rst_n_dff <= 1'b0;
|
||||
end else begin
|
||||
rst_n_dff <= rst_n_in;
|
||||
end
|
||||
end
|
||||
end : gen_reset_sync_cell_single
|
||||
|
||||
else // STAGES_AMOUNT > 1
|
||||
|
||||
begin : gen_reset_sync_cell_multi
|
||||
always_ff @(negedge local_rst_n_in, posedge clk)
|
||||
begin
|
||||
if (~local_rst_n_in) begin
|
||||
rst_n_dff <= '0;
|
||||
end else begin
|
||||
rst_n_dff <= {rst_n_dff[STAGES_AMOUNT-2:0], rst_n_in};
|
||||
end
|
||||
end
|
||||
end : gen_reset_sync_cell_multi
|
||||
|
||||
endgenerate
|
||||
|
||||
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_dff[STAGES_AMOUNT-1];
|
||||
|
||||
endmodule : scr1_reset_sync_cell
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Data CDC/RDC Synchronization Cell
|
||||
//--------------------------------------------------------------------
|
||||
module scr1_data_sync_cell #(
|
||||
parameter int unsigned STAGES_AMOUNT = 1
|
||||
) (
|
||||
input logic rst_n,
|
||||
input logic clk,
|
||||
input logic data_in,
|
||||
output logic data_out
|
||||
);
|
||||
|
||||
logic [STAGES_AMOUNT-1:0] data_dff;
|
||||
|
||||
generate
|
||||
|
||||
if (STAGES_AMOUNT == 1)
|
||||
|
||||
begin : gen_data_sync_cell_single
|
||||
always_ff @(negedge rst_n, posedge clk)
|
||||
begin
|
||||
if (~rst_n) begin
|
||||
data_dff <= 1'b0;
|
||||
end else begin
|
||||
data_dff <= data_in;
|
||||
end
|
||||
end
|
||||
end : gen_data_sync_cell_single
|
||||
|
||||
else // STAGES_AMOUNT > 1
|
||||
|
||||
begin : gen_data_sync_cell_multi
|
||||
always_ff @(negedge rst_n, posedge clk)
|
||||
begin
|
||||
if (~rst_n) begin
|
||||
data_dff <= '0;
|
||||
end else begin
|
||||
data_dff <= {data_dff[STAGES_AMOUNT-2:0], data_in};
|
||||
end
|
||||
end
|
||||
end : gen_data_sync_cell_multi
|
||||
|
||||
endgenerate
|
||||
|
||||
assign data_out = data_dff[STAGES_AMOUNT-1];
|
||||
|
||||
endmodule : scr1_data_sync_cell
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Reset / RDC Qualifyer Adapter Cell
|
||||
// (Reset Generation Cell w/ RDC Qualifyer Adaptation circuitry)
|
||||
//--------------------------------------------------------------------
|
||||
// Total stages amount =
|
||||
// 1 Front Sync stage \
|
||||
// + 1 (delay introduced by the reset output buffer register)
|
||||
//--------------------------------------------------------------------
|
||||
module scr1_reset_qlfy_adapter_cell_sync (
|
||||
input logic rst_n,
|
||||
input logic clk,
|
||||
input logic test_rst_n,
|
||||
input logic test_mode,
|
||||
input logic reset_n_in_sync,
|
||||
output logic reset_n_out_qlfy,
|
||||
output logic reset_n_out,
|
||||
output logic reset_n_status
|
||||
);
|
||||
|
||||
logic rst_n_mux;
|
||||
logic reset_n_front_ff;
|
||||
|
||||
// Front sync stage
|
||||
assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n;
|
||||
|
||||
always_ff @(negedge rst_n_mux, posedge clk) begin
|
||||
if (~rst_n_mux) begin
|
||||
reset_n_front_ff <= 1'b0;
|
||||
end else begin
|
||||
reset_n_front_ff <= reset_n_in_sync;
|
||||
end
|
||||
end
|
||||
|
||||
// Sync reset output for all reset qualifier chains targeting this reset domain
|
||||
// (for reset-domain-crossings with the given reset domain as a destination).
|
||||
assign reset_n_out_qlfy = reset_n_front_ff;
|
||||
|
||||
// Reset output buffer
|
||||
scr1_reset_buf_cell
|
||||
i_reset_output_buf (
|
||||
.rst_n (rst_n),
|
||||
.clk (clk),
|
||||
.test_mode (test_mode),
|
||||
.test_rst_n (test_rst_n),
|
||||
.reset_n_in (reset_n_front_ff),
|
||||
.reset_n_out (reset_n_out),
|
||||
.reset_n_status (reset_n_status)
|
||||
);
|
||||
|
||||
endmodule : scr1_reset_qlfy_adapter_cell_sync
|
||||
|
||||
module scr1_reset_and2_cell (
|
||||
input logic [1:0] rst_n_in,
|
||||
input logic test_rst_n,
|
||||
input logic test_mode,
|
||||
output logic rst_n_out
|
||||
);
|
||||
|
||||
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in);
|
||||
|
||||
endmodule : scr1_reset_and2_cell
|
||||
|
||||
|
||||
module scr1_reset_and3_cell (
|
||||
input logic [2:0] rst_n_in,
|
||||
input logic test_rst_n,
|
||||
input logic test_mode,
|
||||
output logic rst_n_out
|
||||
);
|
||||
|
||||
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in);
|
||||
|
||||
endmodule : scr1_reset_and3_cell
|
||||
|
||||
|
||||
module scr1_reset_mux2_cell (
|
||||
input logic [1:0] rst_n_in,
|
||||
input logic select,
|
||||
input logic test_rst_n,
|
||||
input logic test_mode,
|
||||
output logic rst_n_out
|
||||
);
|
||||
|
||||
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_in[select];
|
||||
|
||||
endmodule : scr1_reset_mux2_cell
|
||||
55
src_ref/core/scr1_clk_ctrl.sv
Normal file
55
src_ref/core/scr1_clk_ctrl.sv
Normal file
@@ -0,0 +1,55 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_clk_ctrl.sv>
|
||||
/// @brief SCR1 clock control
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
module scr1_clk_ctrl (
|
||||
input logic clk, // Clock control module clock
|
||||
input logic rst_n, // Clock control module reset
|
||||
input logic test_mode, // DFT Test Mode
|
||||
input logic test_rst_n, // DFT Test reset
|
||||
|
||||
input logic pipe2clkctl_sleep_req_i, // CLK disable request from pipe
|
||||
input logic pipe2clkctl_wake_req_i, // CLK enable request from pipe
|
||||
|
||||
output logic clkctl2pipe_clk_alw_on_o, // Not gated pipe CLK
|
||||
output logic clkctl2pipe_clk_o, // Gated pipe
|
||||
output logic clkctl2pipe_clk_en_o, // CLK enabled flag
|
||||
output logic clkctl2pipe_clk_dbgc_o // CLK for pipe debug subsystem
|
||||
);
|
||||
|
||||
logic ctrl_rst_n;
|
||||
|
||||
assign clkctl2pipe_clk_alw_on_o = clk;
|
||||
assign clkctl2pipe_clk_dbgc_o = clk;
|
||||
assign ctrl_rst_n = (test_mode) ? test_rst_n : rst_n;
|
||||
|
||||
always_ff @(posedge clk, negedge ctrl_rst_n) begin
|
||||
if (~ctrl_rst_n) begin
|
||||
clkctl2pipe_clk_en_o <= 1'b1;
|
||||
end else begin
|
||||
if (clkctl2pipe_clk_en_o) begin
|
||||
if (pipe2clkctl_sleep_req_i & ~pipe2clkctl_wake_req_i) begin
|
||||
clkctl2pipe_clk_en_o <= 1'b0;
|
||||
end
|
||||
end else begin // ~clkctl2pipe_clk_en_o
|
||||
if (pipe2clkctl_wake_req_i) begin
|
||||
clkctl2pipe_clk_en_o <= 1'b1;
|
||||
end
|
||||
end // pipeline
|
||||
end
|
||||
end
|
||||
|
||||
scr1_cg i_scr1_cg_pipe (
|
||||
.clk (clk ),
|
||||
.clk_en (clkctl2pipe_clk_en_o),
|
||||
.test_mode (test_mode ),
|
||||
.clk_out (clkctl2pipe_clk_o )
|
||||
);
|
||||
|
||||
endmodule : scr1_clk_ctrl
|
||||
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
521
src_ref/core/scr1_core_top.sv
Normal file
521
src_ref/core/scr1_core_top.sv
Normal file
@@ -0,0 +1,521 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_core_top.sv>
|
||||
/// @brief SCR1 core top
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_arch_types.svh"
|
||||
`include "scr1_memif.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_tapc.svh"
|
||||
`include "scr1_dm.svh"
|
||||
`include "scr1_hdu.svh"
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_IPIC_EN
|
||||
`include "scr1_ipic.svh"
|
||||
`endif // SCR1_IPIC_EN
|
||||
|
||||
module scr1_core_top (
|
||||
// Common
|
||||
input logic pwrup_rst_n, // Power-Up reset
|
||||
input logic rst_n, // Regular reset
|
||||
input logic cpu_rst_n, // CPU reset
|
||||
input logic test_mode, // DFT Test Mode
|
||||
input logic test_rst_n, // DFT Test Reset
|
||||
input logic clk, // Core clock
|
||||
output logic core_rst_n_o, // Core reset
|
||||
output logic core_rdc_qlfy_o, // Core RDC qualifier
|
||||
`ifdef SCR1_DBG_EN
|
||||
output logic sys_rst_n_o, // System reset
|
||||
output logic sys_rdc_qlfy_o, // System RDC qualifier
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// Fuses
|
||||
input logic [`SCR1_XLEN-1:0] core_fuse_mhartid_i, // Fuse MHARTID value
|
||||
`ifdef SCR1_DBG_EN
|
||||
input logic [31:0] tapc_fuse_idcode_i, // Fuse IDCODE value
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// IRQ
|
||||
`ifdef SCR1_IPIC_EN
|
||||
input logic [SCR1_IRQ_LINES_NUM-1:0] core_irq_lines_i, // External interrupt request lines
|
||||
`else
|
||||
input logic core_irq_ext_i, // External interrupt request
|
||||
`endif // SCR1_IPIC_EN
|
||||
input logic core_irq_soft_i, // Software generated interrupt request
|
||||
input logic core_irq_mtimer_i, // Machine timer interrupt request
|
||||
|
||||
// Memory-mapped external timer
|
||||
input logic [63:0] core_mtimer_val_i, // Machine timer value
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Debug Interface
|
||||
input logic tapc_trst_n, // Test Reset (TRSTn)
|
||||
input logic tapc_tck, // Test Clock (TCK)
|
||||
input logic tapc_tms, // Test Mode Select (TMS)
|
||||
input logic tapc_tdi, // Test Data Input (TDI)
|
||||
output logic tapc_tdo, // Test Data Output (TDO)
|
||||
output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// Instruction Memory Interface
|
||||
input logic imem2core_req_ack_i, // IMEM request acknowledge
|
||||
output logic core2imem_req_o, // IMEM request
|
||||
output type_scr1_mem_cmd_e core2imem_cmd_o, // IMEM command
|
||||
output logic [`SCR1_IMEM_AWIDTH-1:0] core2imem_addr_o, // IMEM address
|
||||
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2core_rdata_i, // IMEM read data
|
||||
input type_scr1_mem_resp_e imem2core_resp_i, // IMEM response
|
||||
|
||||
// Data Memory Interface
|
||||
input logic dmem2core_req_ack_i, // DMEM request acknowledge
|
||||
output logic core2dmem_req_o, // DMEM request
|
||||
output type_scr1_mem_cmd_e core2dmem_cmd_o, // DMEM command
|
||||
output type_scr1_mem_width_e core2dmem_width_o, // DMEM data width
|
||||
output logic [`SCR1_DMEM_AWIDTH-1:0] core2dmem_addr_o, // DMEM address
|
||||
output logic [`SCR1_DMEM_DWIDTH-1:0] core2dmem_wdata_o, // DMEM write data
|
||||
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2core_rdata_i, // DMEM read data
|
||||
input type_scr1_mem_resp_e dmem2core_resp_i // DMEM response
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local parameters
|
||||
//-------------------------------------------------------------------------------
|
||||
localparam int unsigned SCR1_CORE_TOP_RST_SYNC_STAGES_NUM = 2;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// Reset Logic
|
||||
`ifdef SCR1_DBG_EN
|
||||
`else // SCR1_DBG_EN
|
||||
logic core_rst_n_in_sync;
|
||||
logic core_rst_n_qlfy;
|
||||
logic core_rst_n_status;
|
||||
`endif // SCR1_DBG_EN
|
||||
logic core_rst_n;
|
||||
logic core_rst_n_status_sync;
|
||||
logic core_rst_status;
|
||||
logic core2hdu_rdc_qlfy;
|
||||
logic core2dm_rdc_qlfy;
|
||||
logic pwrup_rst_n_sync;
|
||||
logic rst_n_sync;
|
||||
logic cpu_rst_n_sync;
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// TAPC-DM Interface
|
||||
logic tapc_dmi_ch_sel;
|
||||
logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id;
|
||||
logic tapc_dmi_ch_capture;
|
||||
logic tapc_dmi_ch_shift;
|
||||
logic tapc_dmi_ch_update;
|
||||
logic tapc_dmi_ch_tdi;
|
||||
logic tapc_dmi_ch_tdo;
|
||||
//
|
||||
logic tapc_dmi_ch_sel_tapout;
|
||||
logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id_tapout;
|
||||
logic tapc_dmi_ch_capture_tapout;
|
||||
logic tapc_dmi_ch_shift_tapout;
|
||||
logic tapc_dmi_ch_update_tapout;
|
||||
logic tapc_dmi_ch_tdi_tapout;
|
||||
logic tapc_dmi_ch_tdo_tapin;
|
||||
//
|
||||
logic dmi_req;
|
||||
logic dmi_wr;
|
||||
logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi_addr;
|
||||
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_wdata;
|
||||
logic dmi_resp;
|
||||
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_rdata;
|
||||
// TAPC-SCU Interface
|
||||
logic tapc_scu_ch_sel;
|
||||
logic tapc_scu_ch_sel_tapout;
|
||||
logic tapc_scu_ch_tdo;
|
||||
logic tapc_ch_tdo;
|
||||
// SCU nets
|
||||
logic sys_rst_n;
|
||||
logic sys_rst_status;
|
||||
logic hdu_rst_n;
|
||||
logic hdu2dm_rdc_qlfy;
|
||||
logic ndm_rst_n;
|
||||
logic dm_rst_n;
|
||||
logic hart_rst_n;
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// DM-Pipeline Interface
|
||||
// HART Run Control i/f
|
||||
logic dm_active;
|
||||
logic dm_cmd_req;
|
||||
type_scr1_hdu_dbgstates_e dm_cmd;
|
||||
logic dm_cmd_resp;
|
||||
logic dm_cmd_resp_qlfy;
|
||||
logic dm_cmd_rcode;
|
||||
logic dm_hart_event;
|
||||
logic dm_hart_event_qlfy;
|
||||
type_scr1_hdu_hartstatus_s dm_hart_status;
|
||||
type_scr1_hdu_hartstatus_s dm_hart_status_qlfy;
|
||||
|
||||
// Program Buffer - HART instruction execution i/f
|
||||
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr;
|
||||
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr_qlfy;
|
||||
logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm_pbuf_instr;
|
||||
|
||||
// HART Abstract Data regs i/f
|
||||
logic dm_dreg_req;
|
||||
logic dm_dreg_req_qlfy;
|
||||
logic dm_dreg_wr;
|
||||
logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_wdata;
|
||||
logic dm_dreg_resp;
|
||||
logic dm_dreg_fail;
|
||||
logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_rdata;
|
||||
|
||||
logic [`SCR1_XLEN-1 : 0] dm_pc_sample;
|
||||
logic [`SCR1_XLEN-1 : 0] dm_pc_sample_qlfy;
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
// Global clock gating logic
|
||||
logic sleep_pipe;
|
||||
logic wake_pipe;
|
||||
logic clk_pipe;
|
||||
logic clk_pipe_en;
|
||||
logic clk_dbgc;
|
||||
logic clk_alw_on;
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Reset Logic
|
||||
//-------------------------------------------------------------------------------
|
||||
`ifdef SCR1_DBG_EN
|
||||
scr1_scu i_scu (
|
||||
// Global signals
|
||||
.pwrup_rst_n (pwrup_rst_n ),
|
||||
.rst_n (rst_n ),
|
||||
.cpu_rst_n (cpu_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.clk (clk ),
|
||||
|
||||
// TAPC scan-chains
|
||||
.tapcsync2scu_ch_sel_i (tapc_scu_ch_sel ),
|
||||
.tapcsync2scu_ch_id_i ('0 ),
|
||||
.tapcsync2scu_ch_capture_i (tapc_dmi_ch_capture),
|
||||
.tapcsync2scu_ch_shift_i (tapc_dmi_ch_shift ),
|
||||
.tapcsync2scu_ch_update_i (tapc_dmi_ch_update ),
|
||||
.tapcsync2scu_ch_tdi_i (tapc_dmi_ch_tdi ),
|
||||
.scu2tapcsync_ch_tdo_o (tapc_scu_ch_tdo ),
|
||||
|
||||
// Input sync resets:
|
||||
.ndm_rst_n_i (ndm_rst_n ),
|
||||
.hart_rst_n_i (hart_rst_n ),
|
||||
|
||||
// Generated resets
|
||||
.sys_rst_n_o (sys_rst_n ),
|
||||
.core_rst_n_o (core_rst_n ),
|
||||
.dm_rst_n_o (dm_rst_n ),
|
||||
.hdu_rst_n_o (hdu_rst_n ),
|
||||
|
||||
// Resets statuses
|
||||
.sys_rst_status_o (sys_rst_status ),
|
||||
.core_rst_status_o (core_rst_status ),
|
||||
|
||||
// Reset Domain Crossing (RDC) qualifiers
|
||||
.sys_rdc_qlfy_o (sys_rdc_qlfy_o ),
|
||||
.core_rdc_qlfy_o (core_rdc_qlfy_o ),
|
||||
.core2hdu_rdc_qlfy_o (core2hdu_rdc_qlfy ),
|
||||
.core2dm_rdc_qlfy_o (core2dm_rdc_qlfy ),
|
||||
.hdu2dm_rdc_qlfy_o (hdu2dm_rdc_qlfy )
|
||||
);
|
||||
|
||||
assign sys_rst_n_o = sys_rst_n;
|
||||
|
||||
// Reset inputs are assumed synchronous
|
||||
assign pwrup_rst_n_sync = pwrup_rst_n;
|
||||
|
||||
`else // SCR1_DBG_EN
|
||||
|
||||
// Reset inputs are assumed synchronous
|
||||
assign pwrup_rst_n_sync = pwrup_rst_n;
|
||||
assign rst_n_sync = rst_n;
|
||||
assign cpu_rst_n_sync = cpu_rst_n;
|
||||
assign core_rst_n_in_sync = rst_n_sync & cpu_rst_n_sync;
|
||||
|
||||
// Core Reset: core_rst_n
|
||||
scr1_reset_qlfy_adapter_cell_sync i_core_rstn_qlfy_adapter_cell_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.reset_n_in_sync (core_rst_n_in_sync),
|
||||
.reset_n_out_qlfy (core_rst_n_qlfy ),
|
||||
.reset_n_out (core_rst_n ),
|
||||
.reset_n_status (core_rst_n_status )
|
||||
);
|
||||
|
||||
scr1_data_sync_cell #(
|
||||
.STAGES_AMOUNT (SCR1_CORE_TOP_RST_SYNC_STAGES_NUM)
|
||||
) i_core_rstn_status_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.data_in (core_rst_n_status ),
|
||||
.data_out (core_rst_n_status_sync)
|
||||
);
|
||||
|
||||
assign core_rst_status = ~core_rst_n_status_sync;
|
||||
assign core_rdc_qlfy_o = core_rst_n_qlfy;
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
assign core_rst_n_o = core_rst_n;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// SCR1 pipeline
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_pipe_top i_pipe_top (
|
||||
// Control
|
||||
.pipe_rst_n (core_rst_n ),
|
||||
`ifdef SCR1_DBG_EN
|
||||
.pipe2hdu_rdc_qlfy_i (core2hdu_rdc_qlfy ),
|
||||
.dbg_rst_n (hdu_rst_n ),
|
||||
`endif // SCR1_DBG_EN
|
||||
`ifndef SCR1_CLKCTRL_EN
|
||||
.clk (clk ),
|
||||
`else // SCR1_CLKCTRL_EN
|
||||
.clk (clk_pipe ),
|
||||
.pipe2clkctl_sleep_req_o (sleep_pipe ),
|
||||
.pipe2clkctl_wake_req_o (wake_pipe ),
|
||||
.clkctl2pipe_clk_alw_on_i (clk_alw_on ),
|
||||
.clkctl2pipe_clk_dbgc_i (clk_dbgc ),
|
||||
.clkctl2pipe_clk_en_i (clk_pipe_en ),
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
// Instruction memory interface
|
||||
.pipe2imem_req_o (core2imem_req_o ),
|
||||
.pipe2imem_cmd_o (core2imem_cmd_o ),
|
||||
.pipe2imem_addr_o (core2imem_addr_o ),
|
||||
.imem2pipe_req_ack_i (imem2core_req_ack_i ),
|
||||
.imem2pipe_rdata_i (imem2core_rdata_i ),
|
||||
.imem2pipe_resp_i (imem2core_resp_i ),
|
||||
|
||||
// Data memory interface
|
||||
.pipe2dmem_req_o (core2dmem_req_o ),
|
||||
.pipe2dmem_cmd_o (core2dmem_cmd_o ),
|
||||
.pipe2dmem_width_o (core2dmem_width_o ),
|
||||
.pipe2dmem_addr_o (core2dmem_addr_o ),
|
||||
.pipe2dmem_wdata_o (core2dmem_wdata_o ),
|
||||
.dmem2pipe_req_ack_i (dmem2core_req_ack_i ),
|
||||
.dmem2pipe_rdata_i (dmem2core_rdata_i ),
|
||||
.dmem2pipe_resp_i (dmem2core_resp_i ),
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
// Debug interface:
|
||||
.dbg_en (1'b1 ),
|
||||
// Debug interface:
|
||||
// DM <-> Pipeline: HART Run Control i/f
|
||||
.dm2pipe_active_i (dm_active ),
|
||||
.dm2pipe_cmd_req_i (dm_cmd_req ),
|
||||
.dm2pipe_cmd_i (dm_cmd ),
|
||||
.pipe2dm_cmd_resp_o (dm_cmd_resp ),
|
||||
.pipe2dm_cmd_rcode_o (dm_cmd_rcode ),
|
||||
.pipe2dm_hart_event_o (dm_hart_event ),
|
||||
.pipe2dm_hart_status_o (dm_hart_status ),
|
||||
|
||||
// DM <-> Pipeline: Program Buffer - HART instruction execution i/f
|
||||
.pipe2dm_pbuf_addr_o (dm_pbuf_addr ),
|
||||
.dm2pipe_pbuf_instr_i (dm_pbuf_instr ),
|
||||
|
||||
// DM <-> Pipeline: HART Abstract Data regs i/f
|
||||
.pipe2dm_dreg_req_o (dm_dreg_req ),
|
||||
.pipe2dm_dreg_wr_o (dm_dreg_wr ),
|
||||
.pipe2dm_dreg_wdata_o (dm_dreg_wdata ),
|
||||
.dm2pipe_dreg_resp_i (dm_dreg_resp ),
|
||||
.dm2pipe_dreg_fail_i (dm_dreg_fail ),
|
||||
.dm2pipe_dreg_rdata_i (dm_dreg_rdata ),
|
||||
|
||||
// DM <-> Pipeline: PC i/f
|
||||
.pipe2dm_pc_sample_o (dm_pc_sample ),
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
// IRQ
|
||||
`ifdef SCR1_IPIC_EN
|
||||
.soc2pipe_irq_lines_i (core_irq_lines_i ),
|
||||
`else // SCR1_IPIC_EN
|
||||
.soc2pipe_irq_ext_i (core_irq_ext_i ),
|
||||
`endif // SCR1_IPIC_EN
|
||||
.soc2pipe_irq_soft_i (core_irq_soft_i ),
|
||||
.soc2pipe_irq_mtimer_i (core_irq_mtimer_i ),
|
||||
|
||||
// Memory-mapped external timer
|
||||
.soc2pipe_mtimer_val_i (core_mtimer_val_i ),
|
||||
|
||||
// Fuse
|
||||
.soc2pipe_fuse_mhartid_i (core_fuse_mhartid_i )
|
||||
);
|
||||
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
//-------------------------------------------------------------------------------
|
||||
// TAP Controller (TAPC)
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_tapc i_tapc (
|
||||
// JTAG signals
|
||||
.tapc_trst_n (tapc_trst_n ),
|
||||
.tapc_tck (tapc_tck ),
|
||||
.tapc_tms (tapc_tms ),
|
||||
.tapc_tdi (tapc_tdi ),
|
||||
.tapc_tdo (tapc_tdo ),
|
||||
.tapc_tdo_en (tapc_tdo_en ),
|
||||
|
||||
// Fuses
|
||||
.soc2tapc_fuse_idcode_i (tapc_fuse_idcode_i ),
|
||||
|
||||
// DMI/SCU scan-chains
|
||||
.tapc2tapcsync_scu_ch_sel_o (tapc_scu_ch_sel_tapout ),
|
||||
.tapc2tapcsync_dmi_ch_sel_o (tapc_dmi_ch_sel_tapout ),
|
||||
.tapc2tapcsync_ch_id_o (tapc_dmi_ch_id_tapout ),
|
||||
.tapc2tapcsync_ch_capture_o (tapc_dmi_ch_capture_tapout),
|
||||
.tapc2tapcsync_ch_shift_o (tapc_dmi_ch_shift_tapout ),
|
||||
.tapc2tapcsync_ch_update_o (tapc_dmi_ch_update_tapout ),
|
||||
.tapc2tapcsync_ch_tdi_o (tapc_dmi_ch_tdi_tapout ),
|
||||
.tapcsync2tapc_ch_tdo_i (tapc_dmi_ch_tdo_tapin )
|
||||
);
|
||||
|
||||
scr1_tapc_synchronizer i_tapc_synchronizer (
|
||||
// System common signals
|
||||
.pwrup_rst_n (pwrup_rst_n_sync ),
|
||||
.dm_rst_n (dm_rst_n ),
|
||||
.clk (clk ),
|
||||
|
||||
// JTAG common signals
|
||||
.tapc_trst_n (tapc_trst_n ),
|
||||
.tapc_tck (tapc_tck ),
|
||||
|
||||
// DMI/SCU scan-chains
|
||||
.tapc2tapcsync_scu_ch_sel_i (tapc_scu_ch_sel_tapout ),
|
||||
.tapcsync2scu_ch_sel_o (tapc_scu_ch_sel ),
|
||||
.tapc2tapcsync_dmi_ch_sel_i (tapc_dmi_ch_sel_tapout ),
|
||||
.tapcsync2dmi_ch_sel_o (tapc_dmi_ch_sel ),
|
||||
|
||||
.tapc2tapcsync_ch_id_i (tapc_dmi_ch_id_tapout ),
|
||||
.tapcsync2core_ch_id_o (tapc_dmi_ch_id ),
|
||||
.tapc2tapcsync_ch_capture_i (tapc_dmi_ch_capture_tapout),
|
||||
.tapcsync2core_ch_capture_o (tapc_dmi_ch_capture ),
|
||||
.tapc2tapcsync_ch_shift_i (tapc_dmi_ch_shift_tapout ),
|
||||
.tapcsync2core_ch_shift_o (tapc_dmi_ch_shift ),
|
||||
.tapc2tapcsync_ch_update_i (tapc_dmi_ch_update_tapout ),
|
||||
.tapcsync2core_ch_update_o (tapc_dmi_ch_update ),
|
||||
.tapc2tapcsync_ch_tdi_i (tapc_dmi_ch_tdi_tapout ),
|
||||
.tapcsync2core_ch_tdi_o (tapc_dmi_ch_tdi ),
|
||||
.tapc2tapcsync_ch_tdo_i (tapc_dmi_ch_tdo_tapin ),
|
||||
.tapcsync2core_ch_tdo_o (tapc_ch_tdo )
|
||||
);
|
||||
assign tapc_ch_tdo = (tapc_scu_ch_tdo & tapc_scu_ch_sel)
|
||||
| (tapc_dmi_ch_tdo & tapc_dmi_ch_sel);
|
||||
|
||||
scr1_dmi i_dmi (
|
||||
.rst_n (dm_rst_n ),
|
||||
.clk (clk ),
|
||||
|
||||
// TAP scan-chains
|
||||
.tapcsync2dmi_ch_sel_i (tapc_dmi_ch_sel ),
|
||||
.tapcsync2dmi_ch_id_i (tapc_dmi_ch_id ),
|
||||
.tapcsync2dmi_ch_capture_i (tapc_dmi_ch_capture),
|
||||
.tapcsync2dmi_ch_shift_i (tapc_dmi_ch_shift ),
|
||||
.tapcsync2dmi_ch_update_i (tapc_dmi_ch_update ),
|
||||
.tapcsync2dmi_ch_tdi_i (tapc_dmi_ch_tdi ),
|
||||
.dmi2tapcsync_ch_tdo_o (tapc_dmi_ch_tdo ),
|
||||
|
||||
// DMI
|
||||
.dm2dmi_resp_i (dmi_resp ),
|
||||
.dm2dmi_rdata_i (dmi_rdata ),
|
||||
.dmi2dm_req_o (dmi_req ),
|
||||
.dmi2dm_wr_o (dmi_wr ),
|
||||
.dmi2dm_addr_o (dmi_addr ),
|
||||
.dmi2dm_wdata_o (dmi_wdata )
|
||||
);
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Debug Module (DM)
|
||||
//-------------------------------------------------------------------------------
|
||||
assign dm_cmd_resp_qlfy = dm_cmd_resp & {$bits(dm_cmd_resp){hdu2dm_rdc_qlfy}};
|
||||
assign dm_hart_event_qlfy = dm_hart_event & {$bits(dm_hart_event){hdu2dm_rdc_qlfy}};
|
||||
assign dm_hart_status_qlfy.dbg_state = hdu2dm_rdc_qlfy ? dm_hart_status.dbg_state
|
||||
: SCR1_HDU_DBGSTATE_RESET;
|
||||
assign dm_hart_status_qlfy.except = dm_hart_status.except;
|
||||
assign dm_hart_status_qlfy.ebreak = dm_hart_status.ebreak;
|
||||
assign dm_pbuf_addr_qlfy = dm_pbuf_addr & {$bits(dm_pbuf_addr){hdu2dm_rdc_qlfy}};
|
||||
assign dm_dreg_req_qlfy = dm_dreg_req & {$bits(dm_dreg_req){hdu2dm_rdc_qlfy}};
|
||||
assign dm_pc_sample_qlfy = dm_pc_sample & {$bits(dm_pc_sample){core2dm_rdc_qlfy}};
|
||||
|
||||
scr1_dm i_dm (
|
||||
// Common signals
|
||||
.rst_n (dm_rst_n ),
|
||||
.clk (clk ),
|
||||
|
||||
// DM internal interface
|
||||
.dmi2dm_req_i (dmi_req ),
|
||||
.dmi2dm_wr_i (dmi_wr ),
|
||||
.dmi2dm_addr_i (dmi_addr ),
|
||||
.dmi2dm_wdata_i (dmi_wdata ),
|
||||
.dm2dmi_resp_o (dmi_resp ),
|
||||
.dm2dmi_rdata_o (dmi_rdata ),
|
||||
|
||||
// DM <-> Pipeline: HART Run Control i/f
|
||||
.ndm_rst_n_o (ndm_rst_n ),
|
||||
.hart_rst_n_o (hart_rst_n ),
|
||||
.dm2pipe_active_o (dm_active ),
|
||||
.dm2pipe_cmd_req_o (dm_cmd_req ),
|
||||
.dm2pipe_cmd_o (dm_cmd ),
|
||||
.pipe2dm_cmd_resp_i (dm_cmd_resp_qlfy ),
|
||||
.pipe2dm_cmd_rcode_i (dm_cmd_rcode ),
|
||||
.pipe2dm_hart_event_i (dm_hart_event_qlfy ),
|
||||
.pipe2dm_hart_status_i (dm_hart_status_qlfy ),
|
||||
|
||||
.soc2dm_fuse_mhartid_i (core_fuse_mhartid_i ),
|
||||
.pipe2dm_pc_sample_i (dm_pc_sample_qlfy ),
|
||||
|
||||
// DM <-> Pipeline: HART Abstract Command / Program Buffer i/f
|
||||
.pipe2dm_pbuf_addr_i (dm_pbuf_addr_qlfy ),
|
||||
.dm2pipe_pbuf_instr_o (dm_pbuf_instr ),
|
||||
|
||||
// DM <-> Pipeline: HART Abstract Data regs i/f
|
||||
.pipe2dm_dreg_req_i (dm_dreg_req_qlfy ),
|
||||
.pipe2dm_dreg_wr_i (dm_dreg_wr ),
|
||||
.pipe2dm_dreg_wdata_i (dm_dreg_wdata ),
|
||||
.dm2pipe_dreg_resp_o (dm_dreg_resp ),
|
||||
.dm2pipe_dreg_fail_o (dm_dreg_fail ),
|
||||
.dm2pipe_dreg_rdata_o (dm_dreg_rdata )
|
||||
);
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
|
||||
`ifdef SCR1_CLKCTRL_EN
|
||||
//-------------------------------------------------------------------------------
|
||||
// Global clock gating logic
|
||||
//-------------------------------------------------------------------------------
|
||||
scr1_clk_ctrl i_clk_ctrl (
|
||||
.clk (clk ),
|
||||
.rst_n (core_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
|
||||
// Sleep/wake interface
|
||||
.pipe2clkctl_sleep_req_i (sleep_pipe ),
|
||||
.pipe2clkctl_wake_req_i (wake_pipe ),
|
||||
|
||||
// Clocks
|
||||
.clkctl2pipe_clk_alw_on_o (clk_alw_on ),
|
||||
.clkctl2pipe_clk_o (clk_pipe ),
|
||||
.clkctl2pipe_clk_en_o (clk_pipe_en),
|
||||
.clkctl2pipe_clk_dbgc_o (clk_dbgc )
|
||||
);
|
||||
`endif // SCR1_CLKCTRL_EN
|
||||
|
||||
endmodule : scr1_core_top
|
||||
1427
src_ref/core/scr1_dm.sv
Normal file
1427
src_ref/core/scr1_dm.sv
Normal file
File diff suppressed because it is too large
Load Diff
182
src_ref/core/scr1_dmi.sv
Normal file
182
src_ref/core/scr1_dmi.sv
Normal file
@@ -0,0 +1,182 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @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
|
||||
516
src_ref/core/scr1_scu.sv
Normal file
516
src_ref/core/scr1_scu.sv
Normal file
@@ -0,0 +1,516 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_scu.sv>
|
||||
/// @brief System Control Unit (SCU)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Generates System, Core, HDU and DM resets and their qualifier signals
|
||||
// - Provides debugger with software System and Core resets generation functionality
|
||||
// - Allows to set the behavior of DM and HDU resets
|
||||
// - Shows resets Statuses and Sticky Statuses
|
||||
|
||||
// Structure:
|
||||
// - TAPC scan-chain interface
|
||||
// - SCU CSRs write/read interface
|
||||
// - SCU CSRS:
|
||||
// - CONTROL register
|
||||
// - MODE register
|
||||
// - STATUS register
|
||||
// - STICKY_STATUS register
|
||||
// - Reset logic
|
||||
// - System Reset
|
||||
// - Core Reset
|
||||
// - DM Reset
|
||||
// - HDU Reset
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
`include "scr1_scu.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
|
||||
module scr1_scu (
|
||||
// Global signals
|
||||
input logic pwrup_rst_n, // Power-Up Reset
|
||||
input logic rst_n, // Regular Reset
|
||||
input logic cpu_rst_n, // CPU Reset
|
||||
input logic test_mode, // DFT Test Mode
|
||||
input logic test_rst_n, // DFT Test Reset
|
||||
input logic clk, // SCU clock
|
||||
|
||||
// TAPC scan-chains
|
||||
input logic tapcsync2scu_ch_sel_i, // TAPC Chain Select
|
||||
input logic tapcsync2scu_ch_id_i, // TAPC Chain ID
|
||||
input logic tapcsync2scu_ch_capture_i, // TAPC Chain Capture
|
||||
input logic tapcsync2scu_ch_shift_i, // TAPC Chain Shift
|
||||
input logic tapcsync2scu_ch_update_i, // TAPC Chain Update
|
||||
input logic tapcsync2scu_ch_tdi_i, // TAPC Chain TDI
|
||||
output logic scu2tapcsync_ch_tdo_o, // TAPC Chain TDO
|
||||
|
||||
// Input sync resets:
|
||||
input logic ndm_rst_n_i, // Non-DM Reset input from DM
|
||||
input logic hart_rst_n_i, // HART Reset from DM
|
||||
|
||||
// Generated resets
|
||||
output logic sys_rst_n_o, // System/Cluster Reset
|
||||
output logic core_rst_n_o, // Core Reset
|
||||
output logic dm_rst_n_o, // Debug Module Reset
|
||||
output logic hdu_rst_n_o, // HART Debug Unit Reset
|
||||
|
||||
// Resets statuses
|
||||
output logic sys_rst_status_o, // System Reset Status (sync'ed to POR reset domain)
|
||||
output logic core_rst_status_o, // Core Reset Status (sync'ed to POR reset domain)
|
||||
|
||||
// Reset Domain Crossing (RDC) qualifiers
|
||||
output logic sys_rdc_qlfy_o, // System/Cluster-to-ExternalSOC Reset Domain Crossing Qualifier
|
||||
output logic core_rdc_qlfy_o, // Core-to-ExternalSOC Reset Domain Crossing Qualifier
|
||||
output logic core2hdu_rdc_qlfy_o, // Core-to-HDU Reset Domain Crossing Qualifier
|
||||
output logic core2dm_rdc_qlfy_o, // Core-to-DM Reset Domain Crossing Qualifier
|
||||
output logic hdu2dm_rdc_qlfy_o // HDU-to-DM Reset Domain Crossing Qualifier
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local Parameters
|
||||
//======================================================================================================================
|
||||
localparam int unsigned SCR1_SCU_RST_SYNC_STAGES_NUM = 2;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local Signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// SCU CSR write/read i/f
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TAPC scan-chain control logic
|
||||
logic scu_csr_req;
|
||||
logic tapc_dr_cap_req;
|
||||
logic tapc_dr_shft_req;
|
||||
logic tapc_dr_upd_req;
|
||||
|
||||
// TAPC shift register signals
|
||||
logic tapc_shift_upd;
|
||||
type_scr1_scu_sysctrl_dr_s tapc_shift_ff;
|
||||
type_scr1_scu_sysctrl_dr_s tapc_shift_next;
|
||||
|
||||
// TAPC shadow register signals
|
||||
type_scr1_scu_sysctrl_dr_s tapc_shadow_ff;
|
||||
|
||||
// SCU CSR write/read i/f
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_wdata;
|
||||
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_rdata;
|
||||
|
||||
// SCU CSRs signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Control register
|
||||
type_scr1_scu_sysctrl_control_reg_s scu_control_ff;
|
||||
logic scu_control_wr_req;
|
||||
|
||||
// Mode register
|
||||
type_scr1_scu_sysctrl_mode_reg_s scu_mode_ff;
|
||||
logic scu_mode_wr_req;
|
||||
|
||||
// Status register
|
||||
type_scr1_scu_sysctrl_status_reg_s scu_status_ff;
|
||||
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_dly;
|
||||
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_posedge;
|
||||
|
||||
// Sticky Status register
|
||||
type_scr1_scu_sysctrl_status_reg_s scu_sticky_sts_ff;
|
||||
logic scu_sticky_sts_wr_req;
|
||||
|
||||
// Reset logic signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Input resets synchronization signals
|
||||
logic pwrup_rst_n_sync;
|
||||
logic rst_n_sync;
|
||||
logic cpu_rst_n_sync;
|
||||
|
||||
// System Reset signals
|
||||
logic sys_rst_n_in;
|
||||
logic sys_rst_n_status;
|
||||
logic sys_rst_n_status_sync;
|
||||
logic sys_rst_n_qlfy;
|
||||
logic sys_reset_n;
|
||||
|
||||
// Core Reset signals
|
||||
logic core_rst_n_in_sync;
|
||||
logic core_rst_n_status;
|
||||
logic core_rst_n_status_sync;
|
||||
logic core_rst_n_qlfy;
|
||||
logic core_reset_n;
|
||||
|
||||
// HDU Reset signals
|
||||
logic hdu_rst_n_in_sync;
|
||||
logic hdu_rst_n_status;
|
||||
logic hdu_rst_n_status_sync;
|
||||
logic hdu_rst_n_qlfy;
|
||||
|
||||
// DM Reset signals
|
||||
logic dm_rst_n_in;
|
||||
logic dm_rst_n_status;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAPC scan-chain i/f
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Consists of the following functional units:
|
||||
// - TAPC scan-chain control logic
|
||||
// - TAPC shift register
|
||||
// - TAPC shadow register
|
||||
//
|
||||
|
||||
// TAPC scan-chain control logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign scu_csr_req = tapcsync2scu_ch_sel_i & (tapcsync2scu_ch_id_i == '0);
|
||||
assign tapc_dr_cap_req = scu_csr_req & tapcsync2scu_ch_capture_i;
|
||||
assign tapc_dr_shft_req = scu_csr_req & tapcsync2scu_ch_shift_i;
|
||||
assign tapc_dr_upd_req = scu_csr_req & tapcsync2scu_ch_update_i;
|
||||
|
||||
// TAPC shift register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign tapc_shift_upd = tapc_dr_cap_req | tapc_dr_shft_req;
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
tapc_shift_ff <= '0;
|
||||
end else if (tapc_shift_upd) begin
|
||||
tapc_shift_ff <= tapc_shift_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tapc_shift_next = tapc_dr_cap_req ? tapc_shadow_ff
|
||||
: tapc_dr_shft_req ? {tapcsync2scu_ch_tdi_i, tapc_shift_ff[$bits(type_scr1_scu_sysctrl_dr_s)-1:1]}
|
||||
: tapc_shift_ff;
|
||||
|
||||
// TAPC shadow register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
tapc_shadow_ff <= '0;
|
||||
end else if (tapc_dr_upd_req) begin
|
||||
tapc_shadow_ff.op <= tapc_shift_ff.op;
|
||||
tapc_shadow_ff.addr <= tapc_shift_ff.addr;
|
||||
tapc_shadow_ff.data <= scu_csr_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
assign scu2tapcsync_ch_tdo_o = tapc_shift_ff[0];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SCU CSRs write/read interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Write interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Register selection logic
|
||||
always_comb begin
|
||||
scu_control_wr_req = 1'b0;
|
||||
scu_mode_wr_req = 1'b0;
|
||||
scu_sticky_sts_wr_req = 1'b0;
|
||||
|
||||
if (tapc_dr_upd_req && (tapc_shift_ff.op != SCR1_SCU_SYSCTRL_OP_READ)) begin
|
||||
case (tapc_shift_ff.addr)
|
||||
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_control_wr_req = 1'b1;
|
||||
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_mode_wr_req = 1'b1;
|
||||
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_sticky_sts_wr_req = (tapc_shift_ff.op == SCR1_SCU_SYSCTRL_OP_CLRBITS);
|
||||
default : begin end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// Write data construction
|
||||
always_comb begin
|
||||
scu_csr_wdata = '0;
|
||||
|
||||
if (tapc_dr_upd_req) begin
|
||||
case (tapc_shift_ff.op)
|
||||
SCR1_SCU_SYSCTRL_OP_WRITE : scu_csr_wdata = tapc_shift_ff.data;
|
||||
SCR1_SCU_SYSCTRL_OP_READ : scu_csr_wdata = scu_csr_rdata;
|
||||
SCR1_SCU_SYSCTRL_OP_SETBITS: scu_csr_wdata = scu_csr_rdata | tapc_shift_ff.data;
|
||||
SCR1_SCU_SYSCTRL_OP_CLRBITS: scu_csr_wdata = scu_csr_rdata & (~tapc_shift_ff.data);
|
||||
default : begin end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// Read interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Read data multiplexer
|
||||
always_comb begin
|
||||
scu_csr_rdata = '0;
|
||||
|
||||
if (tapc_dr_upd_req) begin
|
||||
case (tapc_shift_ff.addr)
|
||||
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_csr_rdata = scu_control_ff;
|
||||
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_csr_rdata = scu_mode_ff;
|
||||
SCR1_SCU_SYSCTRL_ADDR_STATUS : scu_csr_rdata = scu_status_ff;
|
||||
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_csr_rdata = scu_sticky_sts_ff;
|
||||
default : scu_csr_rdata = 'x;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SCU CSRs
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Registers:
|
||||
// - CONTROL register
|
||||
// - MODE register
|
||||
// - STATUS register
|
||||
// - STICKY_STATUS register
|
||||
//
|
||||
|
||||
// CONTROL register
|
||||
//------------------------------------------------------------------------------
|
||||
// Allows debugger to generate System and Core resets
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
scu_control_ff <= '0;
|
||||
end else if (scu_control_wr_req) begin
|
||||
scu_control_ff <= scu_csr_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
// MODE register
|
||||
//------------------------------------------------------------------------------
|
||||
// Sets reset behavior for DM Reset and HDU Reset signals
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
scu_mode_ff <= '0;
|
||||
end else if (scu_mode_wr_req) begin
|
||||
scu_mode_ff <= scu_csr_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
// STATUS register
|
||||
//------------------------------------------------------------------------------
|
||||
// Holds the status of every output reset signal (System, Core, DM and HDU)
|
||||
|
||||
assign scu_status_ff.sys_reset = sys_rst_status_o ;
|
||||
assign scu_status_ff.core_reset = core_rst_status_o;
|
||||
assign scu_status_ff.dm_reset = ~dm_rst_n_status;
|
||||
assign scu_status_ff.hdu_reset = ~hdu_rst_n_status_sync;
|
||||
|
||||
// Status Register positive edge detection logic
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
scu_status_ff_dly <= '0;
|
||||
end else begin
|
||||
scu_status_ff_dly <= scu_status_ff;
|
||||
end
|
||||
end
|
||||
|
||||
assign scu_status_ff_posedge = scu_status_ff & ~scu_status_ff_dly;
|
||||
|
||||
// STICKY_STATUS register
|
||||
//------------------------------------------------------------------------------
|
||||
// For every output reset signal shows if it was asserted since the last bit clearing
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
|
||||
if (~pwrup_rst_n_sync) begin
|
||||
scu_sticky_sts_ff <= '0;
|
||||
end else begin
|
||||
for (int unsigned i = 0; i < $bits(type_scr1_scu_sysctrl_status_reg_s); ++i) begin
|
||||
if (scu_status_ff_posedge[i]) begin
|
||||
scu_sticky_sts_ff[i] <= 1'b1;
|
||||
end else if (scu_sticky_sts_wr_req) begin
|
||||
scu_sticky_sts_ff[i] <= scu_csr_wdata[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Reset logic
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Consists of the following functional units:
|
||||
// - System Reset logic
|
||||
// - Core Reset logic
|
||||
// - Hart Debug Unit Reset logic
|
||||
// - Debug Module Reset logic
|
||||
//
|
||||
|
||||
// Reset inputs are assumed synchronous
|
||||
assign pwrup_rst_n_sync = pwrup_rst_n;
|
||||
assign rst_n_sync = rst_n;
|
||||
assign cpu_rst_n_sync = cpu_rst_n;
|
||||
|
||||
// Intermediate resets:
|
||||
assign sys_reset_n = ~scu_control_ff.sys_reset;
|
||||
assign core_reset_n = ~scu_control_ff.core_reset;
|
||||
|
||||
// System/Cluster Reset: sys_rst_n_o
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
scr1_reset_qlfy_adapter_cell_sync i_sys_rstn_qlfy_adapter_cell_sync (
|
||||
.rst_n (pwrup_rst_n_sync),
|
||||
.clk (clk ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.reset_n_in_sync (sys_rst_n_in ),
|
||||
.reset_n_out_qlfy (sys_rst_n_qlfy ),
|
||||
.reset_n_out (sys_rst_n_o ),
|
||||
.reset_n_status (sys_rst_n_status)
|
||||
);
|
||||
|
||||
assign sys_rst_n_in = sys_reset_n & ndm_rst_n_i & rst_n_sync;
|
||||
|
||||
scr1_data_sync_cell #(
|
||||
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
|
||||
) i_sys_rstn_status_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.data_in (sys_rst_n_status ),
|
||||
.data_out (sys_rst_n_status_sync)
|
||||
);
|
||||
|
||||
assign sys_rst_status_o = ~sys_rst_n_status_sync;
|
||||
|
||||
// System/Cluster-to-ExternalSOC RDC qualifier
|
||||
assign sys_rdc_qlfy_o = sys_rst_n_qlfy;
|
||||
|
||||
// Core Reset: core_rst_n_o
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
scr1_reset_qlfy_adapter_cell_sync i_core_rstn_qlfy_adapter_cell_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.reset_n_in_sync (core_rst_n_in_sync),
|
||||
.reset_n_out_qlfy (core_rst_n_qlfy ),
|
||||
.reset_n_out (core_rst_n_o ),
|
||||
.reset_n_status (core_rst_n_status )
|
||||
);
|
||||
|
||||
assign core_rst_n_in_sync = sys_rst_n_in & hart_rst_n_i & core_reset_n & cpu_rst_n_sync;
|
||||
|
||||
scr1_data_sync_cell #(
|
||||
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
|
||||
) i_core_rstn_status_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.data_in (core_rst_n_status ),
|
||||
.data_out (core_rst_n_status_sync)
|
||||
);
|
||||
|
||||
assign core_rst_status_o = ~core_rst_n_status_sync;
|
||||
|
||||
// Core Reset RDC Qualifiers:
|
||||
// - Core-to-ExternalSOC RDC Qlfy
|
||||
assign core_rdc_qlfy_o = core_rst_n_qlfy;
|
||||
// - Core-to-HDU RDC Qlfy
|
||||
assign core2hdu_rdc_qlfy_o = core_rst_n_qlfy;
|
||||
// - Core-to-DebugModule RDC Qlfy
|
||||
assign core2dm_rdc_qlfy_o = core_rst_n_qlfy;
|
||||
|
||||
// Hart Debug Unit Reset: hdu_rst_n_o
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
scr1_reset_qlfy_adapter_cell_sync i_hdu_rstn_qlfy_adapter_cell_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.test_mode (test_mode ),
|
||||
.reset_n_in_sync (hdu_rst_n_in_sync),
|
||||
.reset_n_out_qlfy (hdu_rst_n_qlfy ),
|
||||
.reset_n_out (hdu_rst_n_o ),
|
||||
.reset_n_status (hdu_rst_n_status )
|
||||
);
|
||||
|
||||
assign hdu_rst_n_in_sync = scu_mode_ff.hdu_rst_bhv | core_rst_n_in_sync;
|
||||
|
||||
scr1_data_sync_cell #(
|
||||
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
|
||||
) i_hdu_rstn_status_sync (
|
||||
.rst_n (pwrup_rst_n_sync ),
|
||||
.clk (clk ),
|
||||
.data_in (hdu_rst_n_status ),
|
||||
.data_out (hdu_rst_n_status_sync)
|
||||
);
|
||||
|
||||
// Hart Debug Unit Reset RDC Qualifiers:
|
||||
// - HDU-to-DebugModule RDC Qlfy
|
||||
assign hdu2dm_rdc_qlfy_o = hdu_rst_n_qlfy;
|
||||
|
||||
// Debug Module Reset: dm_rst_n_o
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
scr1_reset_buf_cell i_dm_rstn_buf_cell (
|
||||
.rst_n (pwrup_rst_n_sync),
|
||||
.clk (clk ),
|
||||
.test_mode (test_mode ),
|
||||
.test_rst_n (test_rst_n ),
|
||||
.reset_n_in (dm_rst_n_in ),
|
||||
.reset_n_out (dm_rst_n_o ),
|
||||
.reset_n_status (dm_rst_n_status )
|
||||
);
|
||||
|
||||
assign dm_rst_n_in = ~scu_mode_ff.dm_rst_bhv | sys_reset_n;
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//--------------------------------------------------------------------
|
||||
// Assertions
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
`ifndef VERILATOR
|
||||
// Preventing some assertions to be raised at 0 sim time or in the first cycle
|
||||
initial begin
|
||||
$assertoff(0, scr1_scu);
|
||||
repeat (2) @(posedge clk) begin end
|
||||
$asserton(0, scr1_scu);
|
||||
end
|
||||
`endif // VERILATOR
|
||||
|
||||
// X checks
|
||||
SCR1_SVA_SCU_RESETS_XCHECK : assert property (
|
||||
@(negedge clk)
|
||||
!$isunknown({pwrup_rst_n, rst_n, cpu_rst_n, ndm_rst_n_i, hart_rst_n_i})
|
||||
) else $error("SCU resets error: unknown values of input resets");
|
||||
|
||||
// Qualifiers checks
|
||||
SCR1_SVA_SCU_SYS2SOC_QLFY_CHECK : assert property (
|
||||
@(negedge clk) disable iff (~pwrup_rst_n)
|
||||
$fell(sys_rst_n_o) |-> $fell($past(sys_rdc_qlfy_o))
|
||||
) else $error("SCU sys2soc qlfy error: qlfy wasn't raised prior to reset");
|
||||
|
||||
SCR1_SVA_SCU_CORE2SOC_QLFY_CHECK : assert property (
|
||||
@(negedge clk) disable iff (~pwrup_rst_n)
|
||||
$fell(core_rst_n_o) |-> $fell($past(core_rdc_qlfy_o))
|
||||
) else $error("SCU core2soc qlfy error: qlfy wasn't raised prior to reset");
|
||||
|
||||
SCR1_SVA_SCU_CORE2HDU_QLFY_CHECK : assert property (
|
||||
@(negedge clk) disable iff (~pwrup_rst_n)
|
||||
$fell(core_rst_n_o) |-> $fell($past(core2hdu_rdc_qlfy_o))
|
||||
) else $error("SCU core2hdu qlfy error: qlfy wasn't raised prior to reset");
|
||||
|
||||
SCR1_SVA_SCU_CORE2DM_QLFY_CHECK : assert property (
|
||||
@(negedge clk) disable iff (~pwrup_rst_n)
|
||||
$fell(core_rst_n_o) |-> $fell($past(core2dm_rdc_qlfy_o))
|
||||
) else $error("SCU core2dm qlfy error: qlfy wasn't raised prior to reset");
|
||||
|
||||
SCR1_SVA_SCU_HDU2DM_QLFY_CHECK : assert property (
|
||||
@(negedge clk) disable iff (~pwrup_rst_n)
|
||||
$fell(hdu_rst_n_o) |-> $fell($past(hdu2dm_rdc_qlfy_o))
|
||||
) else $error("SCU hdu2dm qlfy error: qlfy wasn't raised prior to reset");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_scu
|
||||
`endif // SCR1_DBG_EN
|
||||
|
||||
457
src_ref/core/scr1_tapc.sv
Normal file
457
src_ref/core/scr1_tapc.sv
Normal file
@@ -0,0 +1,457 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_tapc.sv>
|
||||
/// @brief TAP Controller (TAPC)
|
||||
///
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functionality:
|
||||
// - Controls TAP operation
|
||||
// - Allows debugger to access TAP Data registers and DMI/SCU scan-chains via
|
||||
// command written in Instruction register
|
||||
//
|
||||
// Structure:
|
||||
// - Synchronous reset generation
|
||||
// - TAPC FSM
|
||||
// - TAPC Instruction Registers
|
||||
// - TAPC DRs/DMI/SCU scan-chains
|
||||
// - TAPC TDO enable and output Registers
|
||||
// - TAPC Data Registers
|
||||
// - BYPASS
|
||||
// - IDCODE
|
||||
// - BUILD ID
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_tapc.svh"
|
||||
`include "scr1_dm.svh"
|
||||
|
||||
module scr1_tapc (
|
||||
// JTAG signals
|
||||
input logic tapc_trst_n, // Test Reset (TRSTn)
|
||||
input logic tapc_tck, // Test Clock (TCK)
|
||||
input logic tapc_tms, // Test Mode Select (TMS)
|
||||
input logic tapc_tdi, // Test Data Input (TDI)
|
||||
output logic tapc_tdo, // Test Data Output (TDO)
|
||||
output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control
|
||||
|
||||
// Fuses:
|
||||
input logic [31:0] soc2tapc_fuse_idcode_i, // IDCODE value from fuses
|
||||
|
||||
// DMI/SCU scan-chains
|
||||
output logic tapc2tapcsync_scu_ch_sel_o, // SCU Chain Select
|
||||
output logic tapc2tapcsync_dmi_ch_sel_o, // DMI Chain Select
|
||||
output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_o, // DMI/SCU Chain Identifier
|
||||
output logic tapc2tapcsync_ch_capture_o, // DMI/SCU Chain Capture
|
||||
output logic tapc2tapcsync_ch_shift_o, // DMI/SCU Chain Shift
|
||||
output logic tapc2tapcsync_ch_update_o, // DMI/SCU Chain Update
|
||||
output logic tapc2tapcsync_ch_tdi_o, // DMI/SCU Chain TDI
|
||||
input logic tapcsync2tapc_ch_tdo_i // DMI/SCU Chain TDO
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local Signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
logic trst_n_int; // Sync reset signal
|
||||
|
||||
// TAPC FSM signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type_scr1_tap_state_e tap_fsm_ff; // TAP's current state
|
||||
type_scr1_tap_state_e tap_fsm_next; // TAP's next state
|
||||
|
||||
// Control signals
|
||||
logic tap_fsm_reset;
|
||||
logic tap_fsm_ir_upd;
|
||||
logic tap_fsm_ir_cap;
|
||||
logic tap_fsm_ir_shft;
|
||||
|
||||
// Registered control signals
|
||||
logic tap_fsm_ir_shift_ff;
|
||||
logic tap_fsm_ir_shift_next;
|
||||
logic tap_fsm_dr_capture_ff;
|
||||
logic tap_fsm_dr_capture_next;
|
||||
logic tap_fsm_dr_shift_ff;
|
||||
logic tap_fsm_dr_shift_next;
|
||||
logic tap_fsm_dr_update_ff;
|
||||
logic tap_fsm_dr_update_next;
|
||||
|
||||
// TAPC Instruction Registers signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_ff; // Instruction Shift Register
|
||||
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_next; // Instruction Shift Register next value
|
||||
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_ff; // Instruction Register
|
||||
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_next; // Instruction Register next value
|
||||
|
||||
// TAPC Data Registers signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// BYPASS register
|
||||
logic dr_bypass_sel;
|
||||
logic dr_bypass_tdo;
|
||||
|
||||
// IDCODE register
|
||||
logic dr_idcode_sel;
|
||||
logic dr_idcode_tdo;
|
||||
|
||||
// BUILD ID register
|
||||
logic dr_bld_id_sel;
|
||||
logic dr_bld_id_tdo;
|
||||
|
||||
logic dr_out;
|
||||
|
||||
// TDO registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TDO enable register
|
||||
logic tdo_en_ff;
|
||||
logic tdo_en_next;
|
||||
|
||||
// TDO output register
|
||||
logic tdo_out_ff;
|
||||
logic tdo_out_next;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAPC Synchronous Reset logic
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
trst_n_int <= 1'b0;
|
||||
end else begin
|
||||
trst_n_int <= ~tap_fsm_reset;
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAP's FSM
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_fsm_ff <= SCR1_TAP_STATE_RESET;
|
||||
end else begin
|
||||
tap_fsm_ff <= tap_fsm_next;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
case (tap_fsm_ff)
|
||||
SCR1_TAP_STATE_RESET : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IDLE;
|
||||
SCR1_TAP_STATE_IDLE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
|
||||
SCR1_TAP_STATE_DR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_SEL_SCAN : SCR1_TAP_STATE_DR_CAPTURE;
|
||||
SCR1_TAP_STATE_DR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT;
|
||||
SCR1_TAP_STATE_DR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT;
|
||||
SCR1_TAP_STATE_DR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_PAUSE;
|
||||
SCR1_TAP_STATE_DR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT2 : SCR1_TAP_STATE_DR_PAUSE;
|
||||
SCR1_TAP_STATE_DR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_SHIFT;
|
||||
SCR1_TAP_STATE_DR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
|
||||
SCR1_TAP_STATE_IR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IR_CAPTURE;
|
||||
SCR1_TAP_STATE_IR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT;
|
||||
SCR1_TAP_STATE_IR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT;
|
||||
SCR1_TAP_STATE_IR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_PAUSE;
|
||||
SCR1_TAP_STATE_IR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT2 : SCR1_TAP_STATE_IR_PAUSE;
|
||||
SCR1_TAP_STATE_IR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_SHIFT;
|
||||
SCR1_TAP_STATE_IR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
|
||||
`ifdef SCR1_XPROP_EN
|
||||
default : tap_fsm_next = SCR1_TAP_STATE_XXX;
|
||||
`else // SCR1_XPROP_EN
|
||||
default : tap_fsm_next = tap_fsm_ff;
|
||||
`endif // SCR1_XPROP_EN
|
||||
endcase
|
||||
end
|
||||
|
||||
assign tap_fsm_reset = (tap_fsm_ff == SCR1_TAP_STATE_RESET);
|
||||
assign tap_fsm_ir_upd = (tap_fsm_ff == SCR1_TAP_STATE_IR_UPDATE);
|
||||
assign tap_fsm_ir_cap = (tap_fsm_ff == SCR1_TAP_STATE_IR_CAPTURE);
|
||||
assign tap_fsm_ir_shft = (tap_fsm_ff == SCR1_TAP_STATE_IR_SHIFT);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAPC Instruction Registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TAPC Instruction Shift register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_ir_shift_ff <= '0;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_ir_shift_ff <= '0;
|
||||
end else begin
|
||||
tap_ir_shift_ff <= tap_ir_shift_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_ir_shift_next = tap_fsm_ir_cap ? {{($bits(tap_ir_shift_ff)-1){1'b0}}, 1'b1}
|
||||
: tap_fsm_ir_shft ? {tapc_tdi, tap_ir_shift_ff[$left(tap_ir_shift_ff):1]}
|
||||
: tap_ir_shift_ff;
|
||||
|
||||
// TAPC Instruction register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_ir_ff <= SCR1_TAP_INSTR_IDCODE;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_ir_ff <= SCR1_TAP_INSTR_IDCODE;
|
||||
end else begin
|
||||
tap_ir_ff <= tap_ir_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_ir_next = tap_fsm_ir_upd ? tap_ir_shift_ff : tap_ir_ff;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Control signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_fsm_ir_shift_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_fsm_ir_shift_ff <= 1'b0;
|
||||
end else begin
|
||||
tap_fsm_ir_shift_ff <= tap_fsm_ir_shift_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_fsm_ir_shift_next = (tap_fsm_next == SCR1_TAP_STATE_IR_SHIFT);
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_fsm_dr_capture_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_fsm_dr_capture_ff <= 1'b0;
|
||||
end else begin
|
||||
tap_fsm_dr_capture_ff <= tap_fsm_dr_capture_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_fsm_dr_capture_next = (tap_fsm_next == SCR1_TAP_STATE_DR_CAPTURE);
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_fsm_dr_shift_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_fsm_dr_shift_ff <= 1'b0;
|
||||
end else begin
|
||||
tap_fsm_dr_shift_ff <= tap_fsm_dr_shift_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_fsm_dr_shift_next = (tap_fsm_next == SCR1_TAP_STATE_DR_SHIFT);
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tap_fsm_dr_update_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tap_fsm_dr_update_ff <= 1'b0;
|
||||
end else begin
|
||||
tap_fsm_dr_update_ff <= tap_fsm_dr_update_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tap_fsm_dr_update_next = (tap_fsm_next == SCR1_TAP_STATE_DR_UPDATE);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAPC DRs/DMI/SCU scan-chains
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Consists of the following functional units:
|
||||
// - Data source/destination decoder
|
||||
// - DMI channel ID decoder
|
||||
|
||||
// - Read data multiplexer
|
||||
// Data source/destination decoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
dr_bypass_sel = 1'b0;
|
||||
dr_idcode_sel = 1'b0;
|
||||
dr_bld_id_sel = 1'b0;
|
||||
tapc2tapcsync_scu_ch_sel_o = 1'b0;
|
||||
tapc2tapcsync_dmi_ch_sel_o = 1'b0;
|
||||
case (tap_ir_ff)
|
||||
SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_dmi_ch_sel_o = 1'b1;
|
||||
SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_dmi_ch_sel_o = 1'b1;
|
||||
SCR1_TAP_INSTR_IDCODE : dr_idcode_sel = 1'b1;
|
||||
SCR1_TAP_INSTR_BYPASS : dr_bypass_sel = 1'b1;
|
||||
SCR1_TAP_INSTR_BLD_ID : dr_bld_id_sel = 1'b1;
|
||||
SCR1_TAP_INSTR_SCU_ACCESS: tapc2tapcsync_scu_ch_sel_o = 1'b1;
|
||||
default : dr_bypass_sel = 1'b1;
|
||||
endcase
|
||||
end
|
||||
|
||||
// DMI channel ID decoder
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
tapc2tapcsync_ch_id_o = '0;
|
||||
case (tap_ir_ff)
|
||||
SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_ch_id_o = 'd1;
|
||||
SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_ch_id_o = 'd2;
|
||||
default : tapc2tapcsync_ch_id_o = '0;
|
||||
endcase
|
||||
end
|
||||
|
||||
// Read data multiplexer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_comb begin
|
||||
dr_out = 1'b0;
|
||||
case (tap_ir_ff)
|
||||
SCR1_TAP_INSTR_DTMCS : dr_out = tapcsync2tapc_ch_tdo_i;
|
||||
SCR1_TAP_INSTR_DMI_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i;
|
||||
SCR1_TAP_INSTR_IDCODE : dr_out = dr_idcode_tdo;
|
||||
SCR1_TAP_INSTR_BYPASS : dr_out = dr_bypass_tdo;
|
||||
SCR1_TAP_INSTR_BLD_ID : dr_out = dr_bld_id_tdo;
|
||||
SCR1_TAP_INSTR_SCU_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i;
|
||||
default : dr_out = dr_bypass_tdo;
|
||||
endcase
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TDO enable and output registers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TDO enable register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tdo_en_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tdo_en_ff <= 1'b0;
|
||||
end else begin
|
||||
tdo_en_ff <= tdo_en_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tdo_en_next = tap_fsm_dr_shift_ff | tap_fsm_ir_shift_ff;
|
||||
|
||||
// TDO output register
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tdo_out_ff <= 1'b0;
|
||||
end else if (~trst_n_int) begin
|
||||
tdo_out_ff <= 1'b0;
|
||||
end else begin
|
||||
tdo_out_ff <= tdo_out_next;
|
||||
end
|
||||
end
|
||||
|
||||
assign tdo_out_next = tap_fsm_dr_shift_ff ? dr_out
|
||||
: tap_fsm_ir_shift_ff ? tap_ir_shift_ff[0]
|
||||
: 1'b0;
|
||||
|
||||
// TAPC TDO signals
|
||||
assign tapc_tdo_en = tdo_en_ff;
|
||||
assign tapc_tdo = tdo_out_ff;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TAPC Data Registers
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Registers:
|
||||
// - BYPASS register
|
||||
// - IDCODE register
|
||||
// - BUILD ID register
|
||||
|
||||
// BYPASS register
|
||||
//------------------------------------------------------------------------------
|
||||
// 1-bit mandatory IEEE 1149.1 compliant register
|
||||
|
||||
scr1_tapc_shift_reg #(
|
||||
.SCR1_WIDTH (SCR1_TAP_DR_BYPASS_WIDTH),
|
||||
.SCR1_RESET_VALUE (SCR1_TAP_DR_BYPASS_WIDTH'(0))
|
||||
) i_bypass_reg (
|
||||
.clk (tapc_tck ),
|
||||
.rst_n (tapc_trst_n ),
|
||||
.rst_n_sync (trst_n_int ),
|
||||
.fsm_dr_select (dr_bypass_sel ),
|
||||
.fsm_dr_capture (tap_fsm_dr_capture_ff),
|
||||
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
|
||||
.din_serial (tapc_tdi ),
|
||||
.din_parallel (1'b0 ),
|
||||
.dout_serial (dr_bypass_tdo ),
|
||||
.dout_parallel ( )
|
||||
);
|
||||
|
||||
// IDCODE register
|
||||
//------------------------------------------------------------------------------
|
||||
// Holds the Device ID value (mandatory IEEE 1149.1 compliant register)
|
||||
|
||||
scr1_tapc_shift_reg #(
|
||||
.SCR1_WIDTH (SCR1_TAP_DR_IDCODE_WIDTH),
|
||||
.SCR1_RESET_VALUE (SCR1_TAP_DR_IDCODE_WIDTH'(0))
|
||||
) i_tap_idcode_reg (
|
||||
.clk (tapc_tck ),
|
||||
.rst_n (tapc_trst_n ),
|
||||
.rst_n_sync (trst_n_int ),
|
||||
.fsm_dr_select (dr_idcode_sel ),
|
||||
.fsm_dr_capture (tap_fsm_dr_capture_ff ),
|
||||
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
|
||||
.din_serial (tapc_tdi ),
|
||||
.din_parallel (soc2tapc_fuse_idcode_i),
|
||||
.dout_serial (dr_idcode_tdo ),
|
||||
.dout_parallel ( )
|
||||
);
|
||||
|
||||
// BUILD ID register
|
||||
//------------------------------------------------------------------------------
|
||||
// Holds the BUILD ID value
|
||||
|
||||
scr1_tapc_shift_reg #(
|
||||
.SCR1_WIDTH (SCR1_TAP_DR_BLD_ID_WIDTH),
|
||||
.SCR1_RESET_VALUE (SCR1_TAP_DR_BLD_ID_WIDTH'(0))
|
||||
) i_tap_dr_bld_id_reg (
|
||||
.clk (tapc_tck ),
|
||||
.rst_n (tapc_trst_n ),
|
||||
.rst_n_sync (trst_n_int ),
|
||||
.fsm_dr_select (dr_bld_id_sel ),
|
||||
.fsm_dr_capture (tap_fsm_dr_capture_ff),
|
||||
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
|
||||
.din_serial (tapc_tdi ),
|
||||
.din_parallel (SCR1_TAP_BLD_ID_VALUE),
|
||||
.dout_serial (dr_bld_id_tdo ),
|
||||
.dout_parallel ( )
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// DMI/SCU scan-chains signals
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
assign tapc2tapcsync_ch_tdi_o = tapc_tdi;
|
||||
assign tapc2tapcsync_ch_capture_o = tap_fsm_dr_capture_ff;
|
||||
assign tapc2tapcsync_ch_shift_o = tap_fsm_dr_shift_ff;
|
||||
assign tapc2tapcsync_ch_update_o = tap_fsm_dr_update_ff;
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// X checks
|
||||
SCR1_SVA_TAPC_XCHECK : assert property (
|
||||
@(posedge tapc_tck) disable iff (~tapc_trst_n)
|
||||
!$isunknown({tapc_tms, tapc_tdi})
|
||||
) else $error("TAPC error: unknown values");
|
||||
|
||||
SCR1_SVA_TAPC_XCHECK_NEGCLK : assert property (
|
||||
@(negedge tapc_tck) disable iff (tap_fsm_ff != SCR1_TAP_STATE_DR_SHIFT)
|
||||
!$isunknown({tapcsync2tapc_ch_tdo_i})
|
||||
) else $error("TAPC @negedge error: unknown values");
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_tapc
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
112
src_ref/core/scr1_tapc_shift_reg.sv
Normal file
112
src_ref/core/scr1_tapc_shift_reg.sv
Normal file
@@ -0,0 +1,112 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_tapc_shift_reg.sv>
|
||||
/// @brief TAPC shift register. Parameterized implementation of JTAG TAPC's Shift Register.
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
module scr1_tapc_shift_reg #(
|
||||
parameter int unsigned SCR1_WIDTH = 8, // Register width, bits
|
||||
parameter logic [SCR1_WIDTH-1:0] SCR1_RESET_VALUE = '0 // Register's value after reset
|
||||
) (
|
||||
input logic clk, // Clock
|
||||
input logic rst_n, // Async reset
|
||||
input logic rst_n_sync, // Sync reset
|
||||
// TAP FSM's control signals:
|
||||
input logic fsm_dr_select, // - for this DR selection (operation enabling);
|
||||
input logic fsm_dr_capture, // - to capture parallel input's data into shift register;
|
||||
input logic fsm_dr_shift, // - to enable data shifting;
|
||||
// Inputs:
|
||||
input logic din_serial, // - serial (shift_reg[msb/SCR1_WIDTH]);
|
||||
input logic [SCR1_WIDTH-1:0] din_parallel, // - parallel (shift register's input).
|
||||
// Outputs:
|
||||
output logic dout_serial, // - serial (shift_reg[0]);
|
||||
output logic [SCR1_WIDTH-1:0] dout_parallel // - parallel (shift register's output).
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
logic [SCR1_WIDTH-1:0] shift_reg;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Shift register
|
||||
//-------------------------------------------------------------------------------
|
||||
generate
|
||||
if (SCR1_WIDTH > 1)
|
||||
begin : dr_shift_reg
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (~rst_n) begin
|
||||
shift_reg <= SCR1_RESET_VALUE;
|
||||
end
|
||||
else if (~rst_n_sync) begin
|
||||
shift_reg <= SCR1_RESET_VALUE;
|
||||
end
|
||||
else if (fsm_dr_select & fsm_dr_capture) begin
|
||||
shift_reg <= din_parallel;
|
||||
end
|
||||
else if (fsm_dr_select & fsm_dr_shift) begin
|
||||
shift_reg <= {din_serial, shift_reg[SCR1_WIDTH-1:1]};
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
else begin : dr_shift_reg
|
||||
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin
|
||||
if (~rst_n) begin
|
||||
shift_reg <= SCR1_RESET_VALUE;
|
||||
end
|
||||
else if (~rst_n_sync) begin
|
||||
shift_reg <= SCR1_RESET_VALUE;
|
||||
end
|
||||
else if (fsm_dr_select & fsm_dr_capture) begin
|
||||
shift_reg <= din_parallel;
|
||||
end
|
||||
else if (fsm_dr_select & fsm_dr_shift) begin
|
||||
shift_reg <= din_serial;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Parallel output
|
||||
//-------------------------------------------------------------------------------
|
||||
assign dout_parallel = shift_reg;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Serial output
|
||||
//-------------------------------------------------------------------------------
|
||||
assign dout_serial = shift_reg[0];
|
||||
|
||||
`ifdef SCR1_TRGT_SIMULATION
|
||||
//-------------------------------------------------------------------------------
|
||||
// Assertion
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
// X checks
|
||||
SCR1_SVA_TAPC_SHIFTREG_XCHECK : assert property (
|
||||
@(negedge clk) disable iff (~rst_n)
|
||||
!$isunknown({
|
||||
rst_n_sync,
|
||||
fsm_dr_select,
|
||||
fsm_dr_capture,
|
||||
fsm_dr_shift,
|
||||
din_serial,
|
||||
din_parallel
|
||||
})
|
||||
) else begin
|
||||
$error("TAPC Shift Reg error: unknown values");
|
||||
end
|
||||
|
||||
`endif // SCR1_TRGT_SIMULATION
|
||||
|
||||
endmodule : scr1_tapc_shift_reg
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
183
src_ref/core/scr1_tapc_synchronizer.sv
Normal file
183
src_ref/core/scr1_tapc_synchronizer.sv
Normal file
@@ -0,0 +1,183 @@
|
||||
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
||||
/// @file <scr1_tapc_synchronizer.sv>
|
||||
/// @brief TAPC clock domain crossing synchronizer
|
||||
///
|
||||
|
||||
`include "scr1_arch_description.svh"
|
||||
|
||||
`ifdef SCR1_DBG_EN
|
||||
`include "scr1_tapc.svh"
|
||||
`include "scr1_dm.svh"
|
||||
|
||||
module scr1_tapc_synchronizer (
|
||||
// System common signals
|
||||
input logic pwrup_rst_n, // Power-Up Reset
|
||||
input logic dm_rst_n, // Debug Module Reset
|
||||
input logic clk, // System Clock (SysCLK)
|
||||
|
||||
// JTAG common signals
|
||||
input logic tapc_trst_n, // JTAG Test Reset (TRSTn)
|
||||
input logic tapc_tck, // JTAG Test Clock (TCK)
|
||||
|
||||
|
||||
// DMI/SCU scan-chains
|
||||
input logic tapc2tapcsync_scu_ch_sel_i, // SCU Chain Select input (TCK domain)
|
||||
output logic tapcsync2scu_ch_sel_o, // SCU Chain Select output (SysCLK domain)
|
||||
input logic tapc2tapcsync_dmi_ch_sel_i, // DMI Chain Select input (TCK domain)
|
||||
output logic tapcsync2dmi_ch_sel_o, // DMI Chain Select output (SysCLK domain)
|
||||
|
||||
input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_i, // DMI/SCU Chain Identifier input (TCK domain)
|
||||
output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2core_ch_id_o, // DMI/SCU Chain Identifier output (SysCLK domain)
|
||||
|
||||
input logic tapc2tapcsync_ch_capture_i, // DMI/SCU Chain Capture input (TCK domain)
|
||||
output logic tapcsync2core_ch_capture_o, // DMI/SCU Chain Capture output (SysCLK domain)
|
||||
|
||||
input logic tapc2tapcsync_ch_shift_i, // DMI/SCU Chain Shift input (TCK domain)
|
||||
output logic tapcsync2core_ch_shift_o, // DMI/SCU Chain Shift output (SysCLK domain)
|
||||
|
||||
input logic tapc2tapcsync_ch_update_i, // DMI/SCU Chain Update input (TCK domain)
|
||||
output logic tapcsync2core_ch_update_o, // DMI/SCU Chain Update output (SysCLK domain)
|
||||
|
||||
input logic tapc2tapcsync_ch_tdi_i, // DMI/SCU Chain TDI input (TCK domain)
|
||||
output logic tapcsync2core_ch_tdi_o, // DMI/SCU Chain TDI output (SysCLK domain)
|
||||
|
||||
output logic tapc2tapcsync_ch_tdo_i, // DMI/SCU Chain TDO output (TCK domain)
|
||||
input logic tapcsync2core_ch_tdo_o // DMI/SCU Chain TDO input (SysCLK domain)
|
||||
);
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Local signals declaration
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
logic tck_divpos;
|
||||
logic tck_divneg;
|
||||
logic tck_rise_load;
|
||||
logic tck_rise_reset;
|
||||
logic tck_fall_load;
|
||||
logic tck_fall_reset;
|
||||
logic [3:0] tck_divpos_sync;
|
||||
logic [3:0] tck_divneg_sync;
|
||||
logic [2:0] dmi_ch_capture_sync;
|
||||
logic [2:0] dmi_ch_shift_sync;
|
||||
logic [2:0] dmi_ch_tdi_sync;
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Logic
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tck_divpos <= 1'b0;
|
||||
end else begin
|
||||
tck_divpos <= ~tck_divpos;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
tck_divneg <= 1'b0;
|
||||
end else begin
|
||||
tck_divneg <= ~tck_divneg;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
tck_divpos_sync <= 4'd0;
|
||||
tck_divneg_sync <= 4'd0;
|
||||
end else begin
|
||||
tck_divpos_sync <= {tck_divpos_sync[2:0], tck_divpos};
|
||||
tck_divneg_sync <= {tck_divneg_sync[2:0], tck_divneg};
|
||||
end
|
||||
end
|
||||
|
||||
assign tck_rise_load = tck_divpos_sync[2] ^ tck_divpos_sync[1];
|
||||
assign tck_rise_reset = tck_divpos_sync[3] ^ tck_divpos_sync[2];
|
||||
assign tck_fall_load = tck_divneg_sync[2] ^ tck_divneg_sync[1];
|
||||
assign tck_fall_reset = tck_divneg_sync[3] ^ tck_divneg_sync[2];
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
tapcsync2core_ch_update_o <= '0;
|
||||
end else begin
|
||||
if (tck_fall_load) begin
|
||||
tapcsync2core_ch_update_o <= tapc2tapcsync_ch_update_i;
|
||||
end else if (tck_fall_reset) begin
|
||||
tapcsync2core_ch_update_o <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
|
||||
if (~tapc_trst_n) begin
|
||||
dmi_ch_capture_sync[0] <= '0;
|
||||
dmi_ch_shift_sync[0] <= '0;
|
||||
end else begin
|
||||
dmi_ch_capture_sync[0] <= tapc2tapcsync_ch_capture_i;
|
||||
dmi_ch_shift_sync[0] <= tapc2tapcsync_ch_shift_i;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
dmi_ch_capture_sync[2:1] <= '0;
|
||||
dmi_ch_shift_sync[2:1] <= '0;
|
||||
end else begin
|
||||
dmi_ch_capture_sync[2:1] <= {dmi_ch_capture_sync[1], dmi_ch_capture_sync[0]};
|
||||
dmi_ch_shift_sync[2:1] <= {dmi_ch_shift_sync[1], dmi_ch_shift_sync[0]};
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
dmi_ch_tdi_sync <= '0;
|
||||
end else begin
|
||||
dmi_ch_tdi_sync <= {dmi_ch_tdi_sync[1:0], tapc2tapcsync_ch_tdi_i};
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
tapcsync2core_ch_capture_o <= '0;
|
||||
tapcsync2core_ch_shift_o <= '0;
|
||||
tapcsync2core_ch_tdi_o <= '0;
|
||||
end else begin
|
||||
if (tck_rise_load) begin
|
||||
tapcsync2core_ch_capture_o <= dmi_ch_capture_sync[2];
|
||||
tapcsync2core_ch_shift_o <= dmi_ch_shift_sync[2];
|
||||
tapcsync2core_ch_tdi_o <= dmi_ch_tdi_sync[2];
|
||||
end else if (tck_rise_reset) begin
|
||||
tapcsync2core_ch_capture_o <= '0;
|
||||
tapcsync2core_ch_shift_o <= '0;
|
||||
tapcsync2core_ch_tdi_o <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge dm_rst_n) begin
|
||||
if (~dm_rst_n) begin
|
||||
tapcsync2dmi_ch_sel_o <= '0;
|
||||
tapcsync2core_ch_id_o <= '0;
|
||||
end else begin
|
||||
if (tck_rise_load) begin
|
||||
tapcsync2dmi_ch_sel_o <= tapc2tapcsync_dmi_ch_sel_i;
|
||||
tapcsync2core_ch_id_o <= tapc2tapcsync_ch_id_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk, negedge pwrup_rst_n) begin
|
||||
if (~pwrup_rst_n) begin
|
||||
tapcsync2scu_ch_sel_o <= '0;
|
||||
end else begin
|
||||
if (tck_rise_load) begin
|
||||
tapcsync2scu_ch_sel_o <= tapc2tapcsync_scu_ch_sel_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign tapc2tapcsync_ch_tdo_i = tapcsync2core_ch_tdo_o;
|
||||
|
||||
endmodule : scr1_tapc_synchronizer
|
||||
|
||||
`endif // SCR1_DBG_EN
|
||||
Reference in New Issue
Block a user