Skip to content

CL-CLINT Register Handling to Support Multiple Clusters #21

Description

@mridul-tosil

The existing implementation of the CL-CLINT register handling in banshee-pulp is limited to a single cluster. Specifically, the code directly checks the x value against a single base address (self.engine.config.address.cl_clint) and its offset (+ 0x8) to determine whether it is a "set" or "clear" operation.

x if x >= self.engine.config.address.cl_clint

x if x == self.engine.config.address.cl_clint => {

This implementation does not support systems with multiple clusters where each cluster has its own CLINT register mapped to different addresses.

Existing implementation

x if x >= self.engine.config.address.cl_clint

 x if x >= self.engine.config.address.cl_clint
&& x < self.engine.config.address.cl_clint + 0x8 =>
{
0
}

Proposed implementation

 x if (0..self.engine.num_clusters).any(|i| {
x >= (self.engine.config.address.cl_clint
+ self.engine.config.memory.periphs.offset * i as u32)
&& x <= (self.engine.config.address.cl_clint
+ self.engine.config.memory.periphs.offset * i as u32
+ 0x8) // Original size for cl_clint
}) =>
{
0
}

Existing implementation

x if x == self.engine.config.address.cl_clint => {

 x if x == self.engine.config.address.cl_clint => {
// clint set register
let old_entry = self
.cl_clint
.fetch_or((value & mask) as usize, Ordering::SeqCst);
// wake cores affected by this write
let hart_base = (self.cluster_id * self.num_cores) as u32;
for i in 0..32 {
if ((!old_entry & (value & mask) as usize) & (1 << i)) != 0 {
trace!(
" wakeup_wus.req[{}] from cluster-local CLINT",
(hart_base + i) as usize
);
self.wake((hart_base + i) as u32);
}
}
}
x if x == self.engine.config.address.cl_clint + 0x8 => {
// clint clear register
self.cl_clint
.fetch_and(!(value & mask) as usize, Ordering::SeqCst);
}

Proposed implementation

 x if (0..self.engine.num_clusters).any(|i| {
let base = self.engine.config.address.cl_clint
+ self.engine.config.memory.periphs.offset * i as u32;
x >= base && x <= base + 0x8
}) =>
{
let id = (0..self.engine.num_clusters)
.position(|i| {
let base = self.engine.config.address.cl_clint
+ self.engine.config.memory.periphs.offset * i as u32;
addr >= base && addr <= base + 0x8
})
.unwrap();
let offset = addr
- (self.engine.config.address.cl_clint
+ self.engine.config.memory.periphs.offset * id as u32);
match offset {
0 => {
// clint set register
let old_entry = self
.cl_clint
.fetch_or((value & mask) as usize, Ordering::SeqCst);
// wake cores affected by this write
let hart_base = (id * self.num_cores) as u32;
for i in 0..32 {
if ((!old_entry & (value & mask) as usize) & (1 << i)) != 0 {
trace!(
" wakeup_wus.req[{}] from cluster-local CLINT",
(hart_base + i) as usize
);
self.wake((hart_base + i) as u32);
}
}
}
0x8 => {
// clint clear register
self.cl_clint
.fetch_and(!(value & mask) as usize, Ordering::SeqCst);
}
_ => (),
}
}

Additional Note:
I would like to mention that I am new to Rust programming and still learning the best practices. I apologize in advance if the code provided or the approach taken is not optimal.

@SamuelRiedel@paulsc96

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions