Skip to content
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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ibex_demo_system_core.core
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ filesets:
- rtl/system/uart.sv
- rtl/system/spi_host.sv
- rtl/system/spi_top.sv
- rtl/system/plic.sv
file_type: systemVerilogSource

targets:
Expand Down
47 changes: 44 additions & 3 deletions rtl/system/ibex_demo_system.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

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?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

localparam logic [31:0] PLIC_START = 32'h80005000;
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Author

Choose a reason for hiding this comment

The 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;
Expand All @@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -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 ),
Expand Down Expand Up @@ -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),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should still be 15 bits right?

Copy link
Author

Choose a reason for hiding this comment

The 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),
Expand Down Expand Up @@ -494,6 +502,39 @@ module ibex_demo_system #(
assign ndmreset_req = 1'b0;
end

assign irq_sources = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is irq_sources defined somewhere? If so what is its width?

Copy link
Author

Choose a reason for hiding this comment

The 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;
Expand Down
153 changes: 153 additions & 0 deletions rtl/system/plic.sv
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: fix end line

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected.

2 changes: 1 addition & 1 deletion sw/c/common/CMakeLists.txt
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}")
17 changes: 17 additions & 0 deletions sw/c/common/demo_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@

#define DEFAULT_SPI SPI_FROM_BASE_ADDR(SPI0_BASE)

// Add PLIC definitions
#define PLIC_BASE 0x80005000

// PLIC Register offsets
#define PLIC_PRIORITY_BASE 0x000000
#define PLIC_PENDING_BASE 0x001000
#define PLIC_ENABLE_BASE 0x002000
#define PLIC_THRESHOLD_BASE 0x200000
#define PLIC_CLAIM_BASE 0x200004

// PLIC configuration
#define PLIC_MAX_PRIORITY 7
#define PLIC_PRIORITY_MASK 0x7

// Source IDs
#define PLIC_SOURCE_UART0 0

/**
* Writes character to default UART. Signature matches c stdlib function
* of the same name.
Expand Down
40 changes: 40 additions & 0 deletions sw/c/common/plic.c
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);
}
23 changes: 23 additions & 0 deletions sw/c/common/plic.h
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__
9 changes: 8 additions & 1 deletion sw/c/common/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@

#include "demo_system.h"
#include "dev_access.h"
#include "plic.h"

void uart_enable_rx_int(void) {
enable_interrupts(UART_IRQ);
// Set UART interrupt priority (e.g., priority 2)
plic_set_priority(PLIC_SOURCE_UART0, 2);

// Enable UART interrupt in PLIC
plic_enable_interrupt(PLIC_SOURCE_UART0);

// Enable global interrupts
set_global_interrupt_enable(1);
}

Expand Down
Loading
Loading