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

CL-CLINT Register Handling to Support Multiple Clusters #21

Open
mridul-tosil opened this issue Jan 6, 2025 · 0 comments
Open

CL-CLINT Register Handling to Support Multiple Clusters #21

mridul-tosil opened this issue Jan 6, 2025 · 0 comments

Comments

@mridul-tosil
Copy link

mridul-tosil commented Jan 6, 2025

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant