Folder rename

This commit is contained in:
Mikhail Yenuchenko
2026-01-20 17:48:32 +03:00
parent 306061a76d
commit 23e0e58f8b
57 changed files with 37 additions and 37 deletions

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

182
src_ref/core/scr1_dmi.sv Normal file
View 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
View 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
View 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

View 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

View 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