hw/ip/rv_core_ibex/rtl/rv_core_ibex.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4:
5: /**
6: * Ibex RISC-V core
7: *
8: * 32 bit RISC-V core supporting the RV32I + optionally EMC instruction sets.
9: * Instruction and data bus are 32 bit wide TileLink-UL (TL-UL).
10: */
11: module rv_core_ibex #(
12: parameter bit PMPEnable = 1'b0,
13: parameter int unsigned PMPGranularity = 0,
14: parameter int unsigned PMPNumRegions = 4,
15: parameter int unsigned MHPMCounterNum = 8,
16: parameter int unsigned MHPMCounterWidth = 40,
17: parameter bit RV32E = 0,
18: parameter bit RV32M = 1,
19: parameter int unsigned DmHaltAddr = 32'h1A110800,
20: parameter int unsigned DmExceptionAddr = 32'h1A110808,
21: parameter bit PipeLine = 0
22: ) (
23: // Clock and Reset
24: input logic clk_i,
25: input logic rst_ni,
26:
27: input logic test_en_i, // enable all clock gates for testing
28:
29: input logic [31:0] hart_id_i,
30: input logic [31:0] boot_addr_i,
31:
32: // Instruction memory interface
33: output tlul_pkg::tl_h2d_t tl_i_o,
34: input tlul_pkg::tl_d2h_t tl_i_i,
35:
36: // Data memory interface
37: output tlul_pkg::tl_h2d_t tl_d_o,
38: input tlul_pkg::tl_d2h_t tl_d_i,
39:
40: // Interrupt inputs
41: input logic irq_software_i,
42: input logic irq_timer_i,
43: input logic irq_external_i,
44: input logic [14:0] irq_fast_i,
45: input logic irq_nm_i,
46:
47: // Debug Interface
48: input logic debug_req_i,
49:
50: // CPU Control Signals
51: input logic fetch_enable_i,
52: output logic core_sleep_o
53: );
54:
55: import top_pkg::*;
56: import tlul_pkg::*;
57:
58: // if pipeline=1, do not allow pass through and always break the path
59: // if pipeline is 0, passthrough the fifo completely
60: localparam int FifoPass = PipeLine ? 1'b0 : 1'b1;
61: localparam int FifoDepth = PipeLine ? 4'h2 : 4'h0;
62: localparam int WordSize = $clog2(TL_DW / 8);
63:
64: // Inst interface (internal)
65: logic instr_req_o;
66: logic instr_gnt_i;
67: logic instr_rvalid_i;
68: logic [31:0] instr_addr_o;
69: logic [31:0] instr_rdata_i;
70: logic instr_err_i;
71:
72: logic data_req_o;
73: logic data_gnt_i;
74: logic data_rvalid_i;
75: logic data_we_o;
76: logic [3:0] data_be_o;
77: logic [31:0] data_addr_o;
78: logic [31:0] data_wdata_o;
79: logic [31:0] data_rdata_i;
80: logic data_err_i;
81:
82: // Pipeline interfaces
83: tl_h2d_t tl_i_ibex2fifo;
84: tl_d2h_t tl_i_fifo2ibex;
85: tl_h2d_t tl_d_ibex2fifo;
86: tl_d2h_t tl_d_fifo2ibex;
87:
88: `ifdef RVFI
89: logic rvfi_valid;
90: logic [63:0] rvfi_order;
91: logic [31:0] rvfi_insn;
92: logic rvfi_trap;
93: logic rvfi_halt;
94: logic rvfi_intr;
95: logic [ 1:0] rvfi_mode;
96: logic [ 4:0] rvfi_rs1_addr;
97: logic [ 4:0] rvfi_rs2_addr;
98: logic [31:0] rvfi_rs1_rdata;
99: logic [31:0] rvfi_rs2_rdata;
100: logic [ 4:0] rvfi_rd_addr;
101: logic [31:0] rvfi_rd_wdata;
102: logic [31:0] rvfi_pc_rdata;
103: logic [31:0] rvfi_pc_wdata;
104: logic [31:0] rvfi_mem_addr;
105: logic [ 3:0] rvfi_mem_rmask;
106: logic [ 3:0] rvfi_mem_wmask;
107: logic [31:0] rvfi_mem_rdata;
108: logic [31:0] rvfi_mem_wdata;
109: `endif
110:
111: ibex_core #(
112: .PMPEnable ( PMPEnable ),
113: .PMPGranularity ( PMPGranularity ),
114: .PMPNumRegions ( PMPNumRegions ),
115: .MHPMCounterNum ( MHPMCounterNum ),
116: .MHPMCounterWidth ( MHPMCounterWidth ),
117: .RV32E ( RV32E ),
118: .RV32M ( RV32M ),
119: .DmHaltAddr ( DmHaltAddr ),
120: .DmExceptionAddr ( DmExceptionAddr )
121: ) u_core (
122: .clk_i,
123: .rst_ni,
124:
125: .test_en_i,
126:
127: .hart_id_i,
128: .boot_addr_i,
129:
130: .instr_req_o,
131: .instr_gnt_i,
132: .instr_rvalid_i,
133: .instr_addr_o,
134: .instr_rdata_i,
135: .instr_err_i,
136:
137: .data_req_o,
138: .data_gnt_i,
139: .data_rvalid_i,
140: .data_we_o,
141: .data_be_o,
142: .data_addr_o,
143: .data_wdata_o,
144: .data_rdata_i,
145: .data_err_i,
146:
147: .irq_software_i,
148: .irq_timer_i,
149: .irq_external_i,
150: .irq_fast_i,
151: .irq_nm_i,
152:
153: .debug_req_i,
154:
155: `ifdef RVFI
156: .rvfi_valid,
157: .rvfi_order,
158: .rvfi_insn,
159: .rvfi_trap,
160: .rvfi_halt,
161: .rvfi_intr,
162: .rvfi_mode,
163: .rvfi_rs1_addr,
164: .rvfi_rs2_addr,
165: .rvfi_rs1_rdata,
166: .rvfi_rs2_rdata,
167: .rvfi_rd_addr,
168: .rvfi_rd_wdata,
169: .rvfi_pc_rdata,
170: .rvfi_pc_wdata,
171: .rvfi_mem_addr,
172: .rvfi_mem_rmask,
173: .rvfi_mem_wmask,
174: .rvfi_mem_rdata,
175: .rvfi_mem_wdata,
176: `endif
177:
178: .fetch_enable_i,
179: .core_sleep_o
180: );
181:
182: //
183: // Convert ibex data/instruction bus to TL-UL
184: //
185:
186: // Generate a_source fields by toggling between 0 and 1
187: logic tl_i_source, tl_d_source;
188: always_ff @(posedge clk_i or negedge rst_ni) begin
189: if (!rst_ni) begin
190: {tl_i_source, tl_d_source} <= '0;
191: end else begin
192: if (instr_req_o && instr_gnt_i) tl_i_source <= !tl_i_source;
193: if (data_req_o && data_gnt_i) tl_d_source <= !tl_d_source;
194: end
195: end
196:
197: // Convert core instruction interface to TL-UL
198: // The outgoing address is always word aligned
199: assign tl_i_ibex2fifo = '{
200: a_valid: instr_req_o,
201: a_opcode: tlul_pkg::Get,
202: a_param: 3'h0,
203: a_size: 2'(WordSize),
204: a_mask: {TL_DBW{1'b1}},
205: a_source: TL_AIW'(tl_i_source),
206: a_address: {instr_addr_o[31:WordSize], {WordSize{1'b0}}},
207: a_data: {TL_DW{1'b0}},
208: a_user: '{default:'0},
209:
210: d_ready: 1'b1
211: };
212:
213: assign instr_gnt_i = tl_i_fifo2ibex.a_ready & tl_i_ibex2fifo.a_valid;
214: assign instr_rvalid_i = tl_i_fifo2ibex.d_valid;
215: assign instr_rdata_i = tl_i_fifo2ibex.d_data;
216: assign instr_err_i = tl_i_fifo2ibex.d_error;
217:
218: tlul_fifo_sync #(
219: .ReqPass(FifoPass),
220: .RspPass(FifoPass),
221: .ReqDepth(FifoDepth),
222: .RspDepth(FifoDepth)
223: ) fifo_i (
224: .clk_i,
225: .rst_ni,
226: .tl_h_i (tl_i_ibex2fifo),
227: .tl_h_o (tl_i_fifo2ibex),
228: .tl_d_o (tl_i_o),
229: .tl_d_i (tl_i_i),
230: .spare_req_i (1'b0),
231: .spare_req_o (),
232: .spare_rsp_i (1'b0),
233: .spare_rsp_o ());
234:
235: // Convert core data interface to TL-UL
236: // The outgoing address is always word aligned. If it's a write access that occupies
237: // all lanes, then the operation is always PutFullData; otherwise it is always PutPartialData
238: // When in partial opertaion, tlul allows writes smaller than the operation size, thus
239: // size / mask information can be directly passed through
240: assign tl_d_ibex2fifo = '{
241: a_valid: data_req_o,
242: a_opcode: (~data_we_o) ? tlul_pkg::Get :
243: (data_be_o == 4'hf) ? tlul_pkg::PutFullData :
244: tlul_pkg::PutPartialData,
245: a_param: 3'h0,
246: a_size: 2'(WordSize),
247: a_mask: data_be_o,
248: a_source: TL_AIW'(tl_d_source),
249: a_address: {data_addr_o[31:WordSize], {WordSize{1'b0}}},
250: a_data: data_wdata_o,
251: a_user: '{default:'0},
252:
253: d_ready: 1'b1
254: };
255: assign data_gnt_i = tl_d_fifo2ibex.a_ready & tl_d_ibex2fifo.a_valid;
256: assign data_rvalid_i = tl_d_fifo2ibex.d_valid;
257: assign data_rdata_i = tl_d_fifo2ibex.d_data;
258: assign data_err_i = tl_d_fifo2ibex.d_error;
259:
260: tlul_fifo_sync #(
261: .ReqPass(FifoPass),
262: .RspPass(FifoPass),
263: .ReqDepth(FifoDepth),
264: .RspDepth(FifoDepth)
265: ) fifo_d (
266: .clk_i,
267: .rst_ni,
268: .tl_h_i (tl_d_ibex2fifo),
269: .tl_h_o (tl_d_fifo2ibex),
270: .tl_d_o (tl_d_o),
271: .tl_d_i (tl_d_i),
272: .spare_req_i (1'b0),
273: .spare_req_o (),
274: .spare_rsp_i (1'b0),
275: .spare_rsp_o ());
276:
277:
278: `ifdef RVFI
279: ibex_tracer ibex_tracer_i (
280: .clk_i,
281: .rst_ni,
282:
283: .hart_id_i,
284:
285: .rvfi_valid,
286: .rvfi_order,
287: .rvfi_insn,
288: .rvfi_trap,
289: .rvfi_halt,
290: .rvfi_intr,
291: .rvfi_mode,
292: .rvfi_rs1_addr,
293: .rvfi_rs2_addr,
294: .rvfi_rs1_rdata,
295: .rvfi_rs2_rdata,
296: .rvfi_rd_addr,
297: .rvfi_rd_wdata,
298: .rvfi_pc_rdata,
299: .rvfi_pc_wdata,
300: .rvfi_mem_addr,
301: .rvfi_mem_rmask,
302: .rvfi_mem_wmask,
303: .rvfi_mem_rdata,
304: .rvfi_mem_wdata
305: );
306: `endif
307:
308:
309: endmodule
310: