-
Notifications
You must be signed in to change notification settings - Fork 51
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
Plic inc support #133
base: main
Are you sure you want to change the base?
Plic inc support #133
Changes from 2 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 |
---|---|---|
|
@@ -71,6 +71,10 @@ module ibex_demo_system #( | |
parameter logic [31:0] SIM_CTRL_START = 32'h20000; | ||
parameter logic [31:0] SIM_CTRL_MASK = ~(SIM_CTRL_SIZE-1); | ||
|
||
localparam logic [31:0] PLIC_SIZE = 4 * 1024; // 4 KiB | ||
localparam logic [31:0] PLIC_START = 32'h80005000; | ||
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. It's probably best to keep the 8000X000 addresses for those that are only 1 KiB in size. Maybe create it at 0x8010000? 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. I corrected this in latest commit. |
||
localparam logic [31:0] PLIC_MASK = ~(PLIC_SIZE-1); | ||
|
||
// Debug functionality is optional. | ||
localparam bit DBG = 1; | ||
localparam int unsigned DbgHwBreakNum = (DBG == 1) ? 2 : 0; | ||
|
@@ -89,10 +93,11 @@ module ibex_demo_system #( | |
Timer, | ||
Spi, | ||
SimCtrl, | ||
Plic, | ||
DbgDev | ||
} bus_device_e; | ||
|
||
localparam int NrDevices = DBG ? 8 : 7; | ||
localparam int NrDevices = DBG ? 9 : 8; | ||
localparam int NrHosts = DBG ? 2 : 1; | ||
|
||
// Interrupts. | ||
|
@@ -164,6 +169,8 @@ module ibex_demo_system #( | |
assign cfg_device_addr_mask[Spi] = SPI_MASK; | ||
assign cfg_device_addr_base[SimCtrl] = SIM_CTRL_START; | ||
assign cfg_device_addr_mask[SimCtrl] = SIM_CTRL_MASK; | ||
assign cfg_device_addr_base[Plic] = PLIC_START; | ||
assign cfg_device_addr_mask[Plic] = PLIC_MASK; | ||
|
||
if (DBG) begin : g_dbg_device_cfg | ||
assign cfg_device_addr_base[DbgDev] = DEBUG_START; | ||
|
@@ -178,6 +185,7 @@ module ibex_demo_system #( | |
assign device_err[Uart] = 1'b0; | ||
assign device_err[Spi] = 1'b0; | ||
assign device_err[SimCtrl] = 1'b0; | ||
assign device_err[Plic] = 1'b0; | ||
|
||
bus #( | ||
.NrDevices ( NrDevices ), | ||
|
@@ -276,8 +284,8 @@ module ibex_demo_system #( | |
|
||
.irq_software_i(1'b0), | ||
.irq_timer_i (timer_irq), | ||
.irq_external_i(1'b0), | ||
.irq_fast_i ({14'b0, uart_irq}), | ||
.irq_external_i(irq_external), | ||
.irq_fast_i (1'b0), | ||
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. This should still be 15 bits right? 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. Corrected in the latest commit. |
||
.irq_nm_i (1'b0), | ||
|
||
.scramble_key_valid_i('0), | ||
|
@@ -494,6 +502,39 @@ module ibex_demo_system #( | |
assign ndmreset_req = 1'b0; | ||
end | ||
|
||
assign irq_sources = { | ||
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. Is irq_sources defined somewhere? If so what is its width? 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. I declared irq_sources now. |
||
16'b0, // Reserved | ||
15'b0, // Reserved | ||
14'b0, // Reserved | ||
uart_irq // Source 0 | ||
}; | ||
|
||
plic #( | ||
.SOURCES (32), // Number of interrupt sources | ||
.TARGETS (1), // Number of interrupt targets (cores) | ||
.PRIORITIES (3), // Number of priority levels (0-7) | ||
.MAX_PENDING (32) // Maximum number of pending interrupts | ||
) u_plic ( | ||
.clk_i (clk_sys_i), | ||
.rst_ni (rst_sys_ni), | ||
|
||
// Bus interface | ||
.req_i (device_req[Plic]), | ||
.addr_i (device_addr[Plic]), | ||
.we_i (device_we[Plic]), | ||
.be_i (device_be[Plic]), | ||
.wdata_i (device_wdata[Plic]), | ||
.rvalid_o (device_rvalid[Plic]), | ||
.rdata_o (device_rdata[Plic]), | ||
|
||
// Interrupt sources | ||
.irq_sources_i (irq_sources), | ||
.irq_pending_o (irq_pending), | ||
|
||
// Interrupt notification to target (core) | ||
.irq_o (irq_external) | ||
); | ||
|
||
`ifdef VERILATOR | ||
|
||
export "DPI-C" function mhpmcounter_num; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
module plic #( | ||
parameter int SOURCES = 32, | ||
parameter int TARGETS = 1, | ||
parameter int PRIORITIES = 3, | ||
parameter int MAX_PENDING = 32 | ||
) ( | ||
input logic clk_i, | ||
input logic rst_ni, | ||
|
||
// Bus interface | ||
input logic req_i, | ||
input logic [31:0] addr_i, | ||
input logic we_i, | ||
input logic [3:0] be_i, | ||
input logic [31:0] wdata_i, | ||
output logic rvalid_o, | ||
output logic [31:0] rdata_o, | ||
|
||
// Interrupt sources | ||
input logic [SOURCES-1:0] irq_sources_i, | ||
output logic [SOURCES-1:0] irq_pending_o, | ||
|
||
// Interrupt notification to target | ||
output logic [TARGETS-1:0] irq_o | ||
); | ||
|
||
// Register map | ||
localparam int PRIORITY_BASE = 'h000000; // Source priority registers | ||
localparam int PENDING_BASE = 'h001000; // Pending bits | ||
localparam int ENABLE_BASE = 'h002000; // Enable bits | ||
localparam int THRESHOLD_BASE = 'h200000; // Priority threshold | ||
localparam int CLAIM_COMPLETE = 'h200004; // Claim/complete | ||
|
||
// Internal registers | ||
logic [PRIORITIES-1:0] priorities [SOURCES]; | ||
logic [SOURCES-1:0] enables; | ||
logic [PRIORITIES-1:0] threshold; | ||
logic [SOURCES-1:0] pending; | ||
logic [$clog2(SOURCES)-1:0] claimed_irq; | ||
|
||
// Register interface | ||
logic [31:0] reg_rdata; | ||
logic reg_write; | ||
logic reg_read; | ||
|
||
assign reg_write = req_i & we_i; | ||
assign reg_read = req_i & ~we_i; | ||
|
||
// Write handling | ||
always_ff @(posedge clk_i or negedge rst_ni) begin | ||
if (!rst_ni) begin | ||
for (int i = 0; i < SOURCES; i++) begin | ||
priorities[i] <= '0; | ||
end | ||
enables <= '0; | ||
threshold <= '0; | ||
end else if (reg_write) begin | ||
case (addr_i[15:12]) | ||
4'h0: begin // Priority registers | ||
if (addr_i[11:2] < SOURCES) begin | ||
priorities[addr_i[11:2]] <= wdata_i[PRIORITIES-1:0]; | ||
end | ||
end | ||
4'h2: begin // Enable registers | ||
if (addr_i[11:2] == 0) enables <= wdata_i[SOURCES-1:0]; | ||
end | ||
4'h20: begin // Threshold and claim/complete | ||
if (addr_i[3:2] == 0) threshold <= wdata_i[PRIORITIES-1:0]; | ||
else if (addr_i[3:2] == 1) begin | ||
// Handle interrupt completion | ||
if (wdata_i < SOURCES) pending[wdata_i] <= 1'b0; | ||
end | ||
end | ||
default: begin end | ||
endcase | ||
end | ||
end | ||
|
||
// Read handling | ||
always_comb begin | ||
reg_rdata = '0; | ||
case (addr_i[15:12]) | ||
4'h0: begin // Priority registers | ||
if (addr_i[11:2] < SOURCES) begin | ||
reg_rdata = {{(32-PRIORITIES){1'b0}}, priorities[addr_i[11:2]]}; | ||
end | ||
end | ||
4'h1: begin // Pending registers | ||
if (addr_i[11:2] == 0) reg_rdata = pending; | ||
end | ||
4'h2: begin // Enable registers | ||
if (addr_i[11:2] == 0) reg_rdata = enables; | ||
end | ||
4'h20: begin // Threshold and claim/complete | ||
if (addr_i[3:2] == 0) begin | ||
reg_rdata = {{(32-PRIORITIES){1'b0}}, threshold}; | ||
end else if (addr_i[3:2] == 1) begin | ||
// Return highest priority pending interrupt | ||
reg_rdata = claimed_irq; | ||
end | ||
end | ||
default: reg_rdata = '0; | ||
endcase | ||
end | ||
|
||
// Interrupt handling logic | ||
always_ff @(posedge clk_i or negedge rst_ni) begin | ||
if (!rst_ni) begin | ||
pending <= '0; | ||
end else begin | ||
for (int i = 0; i < SOURCES; i++) begin | ||
if (irq_sources_i[i] && enables[i]) pending[i] <= 1'b1; | ||
end | ||
end | ||
end | ||
|
||
// Find highest priority pending interrupt | ||
always_comb begin | ||
logic found_irq; | ||
logic [$clog2(SOURCES)-1:0] highest_irq; | ||
logic [PRIORITIES-1:0] highest_priority; | ||
|
||
found_irq = 1'b0; | ||
highest_irq = '0; | ||
highest_priority = '0; | ||
|
||
for (int i = 0; i < SOURCES; i++) begin | ||
if (pending[i] && enables[i] && (priorities[i] > threshold) && | ||
(!found_irq || priorities[i] > highest_priority)) begin | ||
found_irq = 1'b1; | ||
highest_irq = i; | ||
highest_priority = priorities[i]; | ||
end | ||
end | ||
|
||
claimed_irq = highest_irq; | ||
irq_o = found_irq; | ||
end | ||
|
||
assign irq_pending_o = pending; | ||
|
||
// Response valid signal | ||
always_ff @(posedge clk_i or negedge rst_ni) begin | ||
if (!rst_ni) begin | ||
rvalid_o <= 1'b0; | ||
end else begin | ||
rvalid_o <= req_i; | ||
end | ||
end | ||
|
||
assign rdata_o = reg_rdata; | ||
|
||
endmodule | ||
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. Nit: fix end line 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. Corrected. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
add_library(common OBJECT demo_system.c uart.c timer.c gpio.c pwm.c spi.c crt0.S) | ||
add_library(common OBJECT demo_system.c uart.c timer.c gpio.c pwm.c spi.c plic.c crt0.S) | ||
target_include_directories(common INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#include "plic.h" | ||
#include "demo_system.h" | ||
#include "dev_access.h" | ||
|
||
void plic_init(void) { | ||
// Enable machine external interrupts | ||
enable_interrupts(1 << 11); // Set mie.meie bit | ||
|
||
// Set threshold to 0 (allow all priorities) | ||
plic_set_threshold(0); | ||
} | ||
|
||
void plic_set_priority(uint32_t source, uint32_t priority) { | ||
uint32_t addr = PLIC_BASE + PLIC_PRIORITY_BASE + (source * 4); | ||
DEV_WRITE(addr, priority & PLIC_PRIORITY_MASK); | ||
} | ||
|
||
void plic_enable_interrupt(uint32_t source) { | ||
uint32_t addr = PLIC_BASE + PLIC_ENABLE_BASE; | ||
uint32_t current = DEV_READ(addr); | ||
DEV_WRITE(addr, current | (1 << source)); | ||
} | ||
|
||
void plic_disable_interrupt(uint32_t source) { | ||
uint32_t addr = PLIC_BASE + PLIC_ENABLE_BASE; | ||
uint32_t current = DEV_READ(addr); | ||
DEV_WRITE(addr, current & ~(1 << source)); | ||
} | ||
|
||
void plic_set_threshold(uint32_t threshold) { | ||
DEV_WRITE(PLIC_BASE + PLIC_THRESHOLD_BASE, threshold & PLIC_PRIORITY_MASK); | ||
} | ||
|
||
uint32_t plic_claim_interrupt(void) { | ||
return DEV_READ(PLIC_BASE + PLIC_CLAIM_BASE); | ||
} | ||
|
||
void plic_complete_interrupt(uint32_t source) { | ||
DEV_WRITE(PLIC_BASE + PLIC_CLAIM_BASE, source); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#ifndef PLIC_H__ | ||
#define PLIC_H__ | ||
|
||
#include <stdint.h> | ||
|
||
// Initialize PLIC | ||
void plic_init(void); | ||
|
||
// Set priority for an interrupt source | ||
void plic_set_priority(uint32_t source, uint32_t priority); | ||
|
||
// Enable/disable interrupt source | ||
void plic_enable_interrupt(uint32_t source); | ||
void plic_disable_interrupt(uint32_t source); | ||
|
||
// Set priority threshold | ||
void plic_set_threshold(uint32_t threshold); | ||
|
||
// Claim and complete interrupts | ||
uint32_t plic_claim_interrupt(void); | ||
void plic_complete_interrupt(uint32_t source); | ||
|
||
#endif // PLIC_H__ |
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.
Is this enough? I thought this needed to be 64 MiB?
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.
Corrected.