Skip to content

Commit 6c15b73

Browse files
committed
Add hardware support for PLIC
1 parent a1201cf commit 6c15b73

File tree

3 files changed

+198
-3
lines changed

3 files changed

+198
-3
lines changed

ibex_demo_system_core.core

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ filesets:
2020
- rtl/system/uart.sv
2121
- rtl/system/spi_host.sv
2222
- rtl/system/spi_top.sv
23+
- rtl/system/plic.sv
2324
file_type: systemVerilogSource
2425

2526
targets:

rtl/system/ibex_demo_system.sv

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ module ibex_demo_system #(
7171
parameter logic [31:0] SIM_CTRL_START = 32'h20000;
7272
parameter logic [31:0] SIM_CTRL_MASK = ~(SIM_CTRL_SIZE-1);
7373

74+
localparam logic [31:0] PLIC_SIZE = 4 * 1024; // 4 KiB
75+
localparam logic [31:0] PLIC_START = 32'h80005000;
76+
localparam logic [31:0] PLIC_MASK = ~(PLIC_SIZE-1);
77+
7478
// Debug functionality is optional.
7579
localparam bit DBG = 1;
7680
localparam int unsigned DbgHwBreakNum = (DBG == 1) ? 2 : 0;
@@ -89,10 +93,11 @@ module ibex_demo_system #(
8993
Timer,
9094
Spi,
9195
SimCtrl,
96+
Plic,
9297
DbgDev
9398
} bus_device_e;
9499

95-
localparam int NrDevices = DBG ? 8 : 7;
100+
localparam int NrDevices = DBG ? 9 : 8;
96101
localparam int NrHosts = DBG ? 2 : 1;
97102

98103
// Interrupts.
@@ -164,6 +169,8 @@ module ibex_demo_system #(
164169
assign cfg_device_addr_mask[Spi] = SPI_MASK;
165170
assign cfg_device_addr_base[SimCtrl] = SIM_CTRL_START;
166171
assign cfg_device_addr_mask[SimCtrl] = SIM_CTRL_MASK;
172+
assign cfg_device_addr_base[Plic] = PLIC_START;
173+
assign cfg_device_addr_mask[Plic] = PLIC_MASK;
167174

168175
if (DBG) begin : g_dbg_device_cfg
169176
assign cfg_device_addr_base[DbgDev] = DEBUG_START;
@@ -178,6 +185,7 @@ module ibex_demo_system #(
178185
assign device_err[Uart] = 1'b0;
179186
assign device_err[Spi] = 1'b0;
180187
assign device_err[SimCtrl] = 1'b0;
188+
assign device_err[Plic] = 1'b0;
181189

182190
bus #(
183191
.NrDevices ( NrDevices ),
@@ -276,8 +284,8 @@ module ibex_demo_system #(
276284

277285
.irq_software_i(1'b0),
278286
.irq_timer_i (timer_irq),
279-
.irq_external_i(1'b0),
280-
.irq_fast_i ({14'b0, uart_irq}),
287+
.irq_external_i(irq_external),
288+
.irq_fast_i (1'b0),
281289
.irq_nm_i (1'b0),
282290

283291
.scramble_key_valid_i('0),
@@ -494,6 +502,39 @@ module ibex_demo_system #(
494502
assign ndmreset_req = 1'b0;
495503
end
496504

505+
assign irq_sources = {
506+
16'b0, // Reserved
507+
15'b0, // Reserved
508+
14'b0, // Reserved
509+
uart_irq // Source 0
510+
};
511+
512+
plic #(
513+
.SOURCES (32), // Number of interrupt sources
514+
.TARGETS (1), // Number of interrupt targets (cores)
515+
.PRIORITIES (3), // Number of priority levels (0-7)
516+
.MAX_PENDING (32) // Maximum number of pending interrupts
517+
) u_plic (
518+
.clk_i (clk_sys_i),
519+
.rst_ni (rst_sys_ni),
520+
521+
// Bus interface
522+
.req_i (device_req[Plic]),
523+
.addr_i (device_addr[Plic]),
524+
.we_i (device_we[Plic]),
525+
.be_i (device_be[Plic]),
526+
.wdata_i (device_wdata[Plic]),
527+
.rvalid_o (device_rvalid[Plic]),
528+
.rdata_o (device_rdata[Plic]),
529+
530+
// Interrupt sources
531+
.irq_sources_i (irq_sources),
532+
.irq_pending_o (irq_pending),
533+
534+
// Interrupt notification to target (core)
535+
.irq_o (irq_external)
536+
);
537+
497538
`ifdef VERILATOR
498539

499540
export "DPI-C" function mhpmcounter_num;

rtl/system/plic.sv

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
module plic #(
2+
parameter int SOURCES = 32,
3+
parameter int TARGETS = 1,
4+
parameter int PRIORITIES = 3,
5+
parameter int MAX_PENDING = 32
6+
) (
7+
input logic clk_i,
8+
input logic rst_ni,
9+
10+
// Bus interface
11+
input logic req_i,
12+
input logic [31:0] addr_i,
13+
input logic we_i,
14+
input logic [3:0] be_i,
15+
input logic [31:0] wdata_i,
16+
output logic rvalid_o,
17+
output logic [31:0] rdata_o,
18+
19+
// Interrupt sources
20+
input logic [SOURCES-1:0] irq_sources_i,
21+
output logic [SOURCES-1:0] irq_pending_o,
22+
23+
// Interrupt notification to target
24+
output logic [TARGETS-1:0] irq_o
25+
);
26+
27+
// Register map
28+
localparam int PRIORITY_BASE = 'h000000; // Source priority registers
29+
localparam int PENDING_BASE = 'h001000; // Pending bits
30+
localparam int ENABLE_BASE = 'h002000; // Enable bits
31+
localparam int THRESHOLD_BASE = 'h200000; // Priority threshold
32+
localparam int CLAIM_COMPLETE = 'h200004; // Claim/complete
33+
34+
// Internal registers
35+
logic [PRIORITIES-1:0] priorities [SOURCES];
36+
logic [SOURCES-1:0] enables;
37+
logic [PRIORITIES-1:0] threshold;
38+
logic [SOURCES-1:0] pending;
39+
logic [$clog2(SOURCES)-1:0] claimed_irq;
40+
41+
// Register interface
42+
logic [31:0] reg_rdata;
43+
logic reg_write;
44+
logic reg_read;
45+
46+
assign reg_write = req_i & we_i;
47+
assign reg_read = req_i & ~we_i;
48+
49+
// Write handling
50+
always_ff @(posedge clk_i or negedge rst_ni) begin
51+
if (!rst_ni) begin
52+
for (int i = 0; i < SOURCES; i++) begin
53+
priorities[i] <= '0;
54+
end
55+
enables <= '0;
56+
threshold <= '0;
57+
end else if (reg_write) begin
58+
case (addr_i[15:12])
59+
4'h0: begin // Priority registers
60+
if (addr_i[11:2] < SOURCES) begin
61+
priorities[addr_i[11:2]] <= wdata_i[PRIORITIES-1:0];
62+
end
63+
end
64+
4'h2: begin // Enable registers
65+
if (addr_i[11:2] == 0) enables <= wdata_i[SOURCES-1:0];
66+
end
67+
4'h20: begin // Threshold and claim/complete
68+
if (addr_i[3:2] == 0) threshold <= wdata_i[PRIORITIES-1:0];
69+
else if (addr_i[3:2] == 1) begin
70+
// Handle interrupt completion
71+
if (wdata_i < SOURCES) pending[wdata_i] <= 1'b0;
72+
end
73+
end
74+
default: begin end
75+
endcase
76+
end
77+
end
78+
79+
// Read handling
80+
always_comb begin
81+
reg_rdata = '0;
82+
case (addr_i[15:12])
83+
4'h0: begin // Priority registers
84+
if (addr_i[11:2] < SOURCES) begin
85+
reg_rdata = {{(32-PRIORITIES){1'b0}}, priorities[addr_i[11:2]]};
86+
end
87+
end
88+
4'h1: begin // Pending registers
89+
if (addr_i[11:2] == 0) reg_rdata = pending;
90+
end
91+
4'h2: begin // Enable registers
92+
if (addr_i[11:2] == 0) reg_rdata = enables;
93+
end
94+
4'h20: begin // Threshold and claim/complete
95+
if (addr_i[3:2] == 0) begin
96+
reg_rdata = {{(32-PRIORITIES){1'b0}}, threshold};
97+
end else if (addr_i[3:2] == 1) begin
98+
// Return highest priority pending interrupt
99+
reg_rdata = claimed_irq;
100+
end
101+
end
102+
default: reg_rdata = '0;
103+
endcase
104+
end
105+
106+
// Interrupt handling logic
107+
always_ff @(posedge clk_i or negedge rst_ni) begin
108+
if (!rst_ni) begin
109+
pending <= '0;
110+
end else begin
111+
for (int i = 0; i < SOURCES; i++) begin
112+
if (irq_sources_i[i] && enables[i]) pending[i] <= 1'b1;
113+
end
114+
end
115+
end
116+
117+
// Find highest priority pending interrupt
118+
always_comb begin
119+
logic found_irq;
120+
logic [$clog2(SOURCES)-1:0] highest_irq;
121+
logic [PRIORITIES-1:0] highest_priority;
122+
123+
found_irq = 1'b0;
124+
highest_irq = '0;
125+
highest_priority = '0;
126+
127+
for (int i = 0; i < SOURCES; i++) begin
128+
if (pending[i] && enables[i] && (priorities[i] > threshold) &&
129+
(!found_irq || priorities[i] > highest_priority)) begin
130+
found_irq = 1'b1;
131+
highest_irq = i;
132+
highest_priority = priorities[i];
133+
end
134+
end
135+
136+
claimed_irq = highest_irq;
137+
irq_o = found_irq;
138+
end
139+
140+
assign irq_pending_o = pending;
141+
142+
// Response valid signal
143+
always_ff @(posedge clk_i or negedge rst_ni) begin
144+
if (!rst_ni) begin
145+
rvalid_o <= 1'b0;
146+
end else begin
147+
rvalid_o <= req_i;
148+
end
149+
end
150+
151+
assign rdata_o = reg_rdata;
152+
153+
endmodule

0 commit comments

Comments
 (0)