-
Notifications
You must be signed in to change notification settings - Fork 70
Expose ports #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Expose ports #239
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,11 +7,9 @@ | |
|
||
`include "common_cells/assertions.svh" | ||
|
||
/// This module multiplexes many narrow ports and one wide port onto many narrow | ||
/// ports. The wide or narrow ports can be selected by using the `sel_wide_i` signal. | ||
/// | ||
/// `1` selects the wide port. | ||
/// `0` selects the narrow port. | ||
/// This module multiplexes many narrow ports, one wide port, and one external port onto many narrow | ||
/// ports. Arbitration is done statically: the wide port has the highest priority, | ||
/// followed by the external port, and finally the narrow ports. | ||
/// | ||
/// ## Constraint | ||
/// | ||
|
@@ -21,7 +19,7 @@ | |
/// ## Caution | ||
/// | ||
/// As of now this module's request always need an immediate grant in case | ||
/// `sel_wide_i` is high. Any delayed grant will break the module's behavior. | ||
/// `in_wide_req_i.q_valid` is high. Any delayed grant will break the module's behavior. | ||
module mem_wide_narrow_mux #( | ||
/// Width of narrow data. | ||
parameter int unsigned NarrowDataWidth = 0, | ||
|
@@ -37,6 +35,10 @@ module mem_wide_narrow_mux #( | |
parameter type mem_wide_req_t = logic, | ||
/// Response type of wide inputs. | ||
parameter type mem_wide_rsp_t = logic, | ||
/// Request type of ext inputs. | ||
parameter type mem_ext_req_t = logic, | ||
/// Response type of ext inputs. | ||
parameter type mem_ext_rsp_t = logic, | ||
/// Derived. *Do not override* | ||
/// Number of narrow inputs. | ||
parameter int unsigned NrPorts = WideDataWidth / NarrowDataWidth | ||
|
@@ -50,11 +52,12 @@ module mem_wide_narrow_mux #( | |
/// Wide side. | ||
input mem_wide_req_t in_wide_req_i, | ||
output mem_wide_rsp_t in_wide_rsp_o, | ||
/// External side. | ||
input mem_ext_req_t in_ext_req_i, | ||
output mem_ext_rsp_t in_ext_rsp_o, | ||
// Multiplexed output. | ||
output mem_narrow_req_t [NrPorts-1:0] out_req_o, | ||
input mem_narrow_rsp_t [NrPorts-1:0] out_rsp_i, | ||
/// `0`: Use narrow port, `1`: Use wide port | ||
input logic sel_wide_i | ||
input mem_narrow_rsp_t [NrPorts-1:0] out_rsp_i | ||
); | ||
|
||
localparam int unsigned NarrowStrbWidth = NarrowDataWidth/8; | ||
|
@@ -67,18 +70,20 @@ module mem_wide_narrow_mux #( | |
// Broadcast data from all banks. | ||
for (int i = 0; i < NrPorts; i++) begin | ||
in_wide_rsp_o.p[i*NarrowDataWidth+:NarrowDataWidth] = out_rsp_i[i].p.data; | ||
in_ext_rsp_o.p[i*NarrowDataWidth+:NarrowDataWidth] = out_rsp_i[i].p.data; | ||
end | ||
|
||
// --------------- | ||
// Forward Channel | ||
// --------------- | ||
// By default feed through narrow requests. | ||
out_req_o = in_narrow_req_i; | ||
// Tie-off wide by default. | ||
// Tie-off wide and ext by default. | ||
in_wide_rsp_o.q_ready = 1'b0; | ||
in_ext_rsp_o.q_ready = 1'b0; | ||
|
||
// The wide port is selected. | ||
if (sel_wide_i) begin | ||
// The wide port has the highest priority | ||
if (in_wide_req_i.q_valid) begin | ||
for (int i = 0; i < NrPorts; i++) begin | ||
out_req_o[i].q_valid = in_wide_req_i.q_valid; | ||
// Block access from narrow ports. | ||
|
@@ -92,9 +97,25 @@ module mem_wide_narrow_mux #( | |
user: in_wide_req_i.q.user | ||
}; | ||
// The protocol requires that the response is always granted | ||
// immediately (at least when `sel_wide_i` is high). | ||
// immediately (at least when `in_wide_req_i.q_valid` is high). | ||
in_wide_rsp_o.q_ready = 1'b1; | ||
end | ||
end else if (in_ext_req_i.q_valid) begin // The ext port has the second highest priority | ||
for (int i = 0; i < NrPorts; i++) begin | ||
out_req_o[i].q_valid = in_ext_req_i.q_valid; | ||
// Block access from narrow ports. | ||
in_narrow_rsp_o[i].q_ready = 1'b0; | ||
out_req_o[i].q = '{ | ||
addr: in_ext_req_i.q.addr, | ||
write: in_ext_req_i.q.write, | ||
amo: reqrsp_pkg::AMONone, | ||
data: in_ext_req_i.q.data[i*NarrowDataWidth+:NarrowDataWidth], | ||
strb: in_ext_req_i.q.strb[i*NarrowStrbWidth+:NarrowStrbWidth], | ||
user: in_ext_req_i.q.user | ||
}; | ||
|
||
in_ext_rsp_o.q_ready = 1'b1; | ||
end | ||
end | ||
end | ||
|
||
|
@@ -108,21 +129,23 @@ module mem_wide_narrow_mux #( | |
logic [NrPorts-1:0] q_valid_flat; | ||
logic [NrPorts-1:0][NarrowDataWidth-1:0] q_data; | ||
logic [NrPorts-1:0][NarrowStrbWidth-1:0] q_strb; | ||
// verilog_lint: waive-start line-length | ||
`ASSERT(ImmediateGrantWide, in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) | ||
for (genvar i = 0; i < NrPorts; i++) begin : gen_per_port | ||
assign q_valid_flat[i] = out_req_o[i].q_valid; | ||
assign q_data[i] = out_req_o[i].q.data; | ||
assign q_strb[i] = out_req_o[i].q.strb; | ||
`ASSERT(ImmediateGrantOut, sel_wide_i & out_req_o[i].q_valid |-> out_rsp_i[i].q_ready) | ||
`ASSERT(SilentNarrow, sel_wide_i |-> !in_narrow_rsp_o[i].q_ready) | ||
`ASSERT(NarrowPassThrough, !sel_wide_i & in_narrow_req_i[i].q_valid |-> out_req_o[i].q_valid) | ||
`ASSERT(ImmediateGrantOut, in_wide_req_i.q_valid & out_req_o[i].q_valid |-> out_rsp_i[i].q_ready) | ||
`ASSERT(SilentNarrow, in_wide_req_i.q_valid |-> !in_narrow_rsp_o[i].q_ready) | ||
`ASSERT(NarrowPassThrough, !in_wide_req_i.q_valid & in_narrow_req_i[i].q_valid |-> out_req_o[i].q_valid) | ||
end | ||
`ASSERT(DmaSelected, sel_wide_i & in_wide_req_i.q_valid |-> &q_valid_flat) | ||
`ASSERT(DmaSelected, in_wide_req_i.q_valid & in_wide_req_i.q_valid |-> &q_valid_flat) | ||
`ASSERT(DmaSelectedReadyWhenValid, | ||
sel_wide_i & in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) | ||
in_wide_req_i.q_valid & in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) | ||
`ASSERT(DMAWriteDataCorrect, | ||
in_wide_req_i.q_valid & in_wide_rsp_o.q_ready |-> | ||
(in_wide_req_i.q.data == q_data) && (in_wide_req_i.q.strb == q_strb)) | ||
// verilog_lint: waive-stop line-length | ||
|
||
Comment on lines
+132
to
149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably should extend these to cover also the newly added external port. Let's come back to this next week. |
||
endmodule | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,7 +127,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
logic interrupt, ecall, ebreak; | ||
logic zero_lsb; | ||
|
||
logic meip, mtip, msip, mcip; | ||
logic meip, mtip, msip, mcip, mxip; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What exactly is the mxip? What does it stand for? Accelerator, external...? Why is it needed? Can the existing meip not be used instead? |
||
logic seip, stip, ssip, scip; | ||
logic interrupts_enabled; | ||
logic any_interrupt_pending; | ||
|
@@ -266,6 +266,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
logic [1:0] tie_d, tie_q; | ||
logic [1:0] sie_d, sie_q; | ||
logic [1:0] cie_d, cie_q; | ||
logic [1:0] xie_d, xie_q; | ||
logic seip_d, seip_q; | ||
logic stip_d, stip_q; | ||
logic ssip_d, ssip_q; | ||
|
@@ -299,6 +300,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
`FFAR(tie_q, tie_d, '0, clk_i, rst_i) | ||
`FFAR(sie_q, sie_d, '0, clk_i, rst_i) | ||
`FFAR(cie_q, cie_d, '0, clk_i, rst_i) | ||
`FFAR(xie_q, xie_d, '0, clk_i, rst_i) | ||
`FFAR(seip_q, seip_d, '0, clk_i, rst_i) | ||
`FFAR(stip_q, stip_d, '0, clk_i, rst_i) | ||
`FFAR(ssip_q, ssip_d, '0, clk_i, rst_i) | ||
|
@@ -2296,14 +2298,15 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
assign mtip = irq_i.mtip & tie_q[M]; | ||
assign msip = irq_i.msip & sie_q[M]; | ||
assign mcip = irq_i.mcip & cie_q[M]; | ||
assign mxip = irq_i.mxip & xie_q[M]; | ||
|
||
assign seip = seip_q & eie_q[S]; | ||
assign stip = stip_q & tie_q[S]; | ||
assign ssip = ssip_q & sie_q[S]; | ||
assign scip = scip_q & cie_q[S]; | ||
|
||
assign interrupts_enabled = ((priv_lvl_q == PrivLvlM) & ie_q[M]) || (priv_lvl_q != PrivLvlM); | ||
assign any_interrupt_pending = meip | mtip | msip | mcip | seip | stip | ssip | scip; | ||
assign any_interrupt_pending = meip | mtip | msip | mcip | mxip | seip | stip | ssip | scip; | ||
assign interrupt = interrupts_enabled & any_interrupt_pending; | ||
|
||
// CSR logic | ||
|
@@ -2333,6 +2336,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
tie_d = tie_q; | ||
sie_d = sie_q; | ||
cie_d = cie_q; | ||
xie_d = xie_q; | ||
seip_d = seip_q; | ||
stip_d = stip_q; | ||
ssip_d = ssip_q; | ||
|
@@ -2462,6 +2466,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
csr_rvalue[MTI] = irq_i.mtip; | ||
csr_rvalue[MSI] = irq_i.msip; | ||
csr_rvalue[MCI] = irq_i.mcip; | ||
csr_rvalue[MXI] = irq_i.mxip; | ||
csr_rvalue[SEI] = seip_q; | ||
csr_rvalue[STI] = stip_q; | ||
csr_rvalue[SSI] = ssip_q; | ||
|
@@ -2478,6 +2483,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
csr_rvalue[MTI] = tie_q[M]; | ||
csr_rvalue[MSI] = sie_q[M]; | ||
csr_rvalue[MCI] = cie_q[M]; | ||
csr_rvalue[MXI] = xie_q[M]; | ||
csr_rvalue[SEI] = eie_q[S]; | ||
csr_rvalue[STI] = tie_q[S]; | ||
csr_rvalue[SSI] = sie_q[S]; | ||
|
@@ -2487,6 +2493,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
tie_d[M] = alu_result[MTI]; | ||
sie_d[M] = alu_result[MSI]; | ||
cie_d[M] = alu_result[MCI]; | ||
xie_d[M] = alu_result[MXI]; | ||
eie_d[S] = alu_result[SEI]; | ||
tie_d[S] = alu_result[STI]; | ||
sie_d[S] = alu_result[SSI]; | ||
|
@@ -2610,6 +2617,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( | |
else if (mtip) cause_d[M] = MTI; | ||
else if (msip) cause_d[M] = MSI; | ||
else if (mcip) cause_d[M] = MCI; | ||
else if (mxip) cause_d[M] = MXI; | ||
else if (seip) cause_d[M] = SEI; | ||
else if (stip) cause_d[M] = STI; | ||
else if (ssip) cause_d[M] = SSI; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
mem_wide_narrow_mux_intf
module at the end of the file should also be adapted. In my view, we could also just get rid of it entirely otherwise.