Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions sw/device/lib/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
/* inline assembly */
#define asm __asm__

/* count trailing zeroes */
#define ctz(x) (__builtin_ctz((x)))

/* checked arithmetic intrinsics
* these return true if x op y causes overflow */
#define uaddl_overflow(x, y, sum) (__builtin_uaddl_overflow((x), (y), (sum)))
Expand Down
2 changes: 1 addition & 1 deletion sw/device/lib/hal/mocha.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ timer_t mocha_system_timer(void)
plic_t mocha_system_plic(void)
{
#if defined(__riscv_zcherihybrid)
return (plic_t)create_mmio_capability(plic_base, 0x4004004u);
return (plic_t)create_mmio_capability(plic_base, sizeof(struct plic_memory_layout));
#else /* !defined(__riscv_zcherihybrid) */
return (plic_t)plic_base;
#endif /* defined(__riscv_zcherihybrid) */
Expand Down
2 changes: 1 addition & 1 deletion sw/device/lib/hal/mocha.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum : uint64_t {

static const uintptr_t dram_base = 0x80000000ul;

// In order of memory map.
/* In order of memory map */
mailbox_t mocha_system_mailbox(void);
gpio_t mocha_system_gpio(void);
clkmgr_t mocha_system_clkmgr(void);
Expand Down
45 changes: 45 additions & 0 deletions sw/device/lib/hal/mocha_irq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright lowRISC contributors (COSMIC project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// Mocha IRQ mapping.

#pragma once

#include <stdint.h>

/* device IRQs at the PLIC */
enum [[clang::flag_enum]] mocha_system_irq : uint32_t {
mocha_system_irq_invalid = (1u << 0),
mocha_system_irq_unmapped_1 = (1u << 1),
mocha_system_irq_unmapped_2 = (1u << 2),
mocha_system_irq_unmapped_3 = (1u << 3),
mocha_system_irq_unmapped_4 = (1u << 4),
mocha_system_irq_unmapped_5 = (1u << 5),
mocha_system_irq_i2c = (1u << 6),
mocha_system_irq_spi_device = (1u << 7),
mocha_system_irq_uart = (1u << 8),
mocha_system_irq_gpio = (1u << 9),
mocha_system_irq_pwrmgr = (1u << 10),
mocha_system_irq_mailbox = (1u << 11),
mocha_system_irq_unmapped_12 = (1u << 12),
mocha_system_irq_unmapped_13 = (1u << 13),
mocha_system_irq_unmapped_14 = (1u << 14),
mocha_system_irq_unmapped_15 = (1u << 15),
mocha_system_irq_unmapped_16 = (1u << 16),
mocha_system_irq_unmapped_17 = (1u << 17),
mocha_system_irq_unmapped_18 = (1u << 18),
mocha_system_irq_unmapped_19 = (1u << 19),
mocha_system_irq_unmapped_20 = (1u << 20),
mocha_system_irq_unmapped_21 = (1u << 21),
mocha_system_irq_unmapped_22 = (1u << 22),
mocha_system_irq_unmapped_23 = (1u << 23),
mocha_system_irq_unmapped_24 = (1u << 24),
mocha_system_irq_unmapped_25 = (1u << 25),
mocha_system_irq_unmapped_26 = (1u << 26),
mocha_system_irq_unmapped_27 = (1u << 27),
mocha_system_irq_unmapped_28 = (1u << 28),
mocha_system_irq_unmapped_29 = (1u << 29),
mocha_system_irq_unmapped_30 = (1u << 30),
mocha_system_irq_unmapped_31 = (1u << 31),
};
134 changes: 87 additions & 47 deletions sw/device/lib/hal/plic.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,117 +3,157 @@
// SPDX-License-Identifier: Apache-2.0

#include "hal/plic.h"
#include "builtin.h"
#include "hal/mmio.h"
#include "hal/mocha_irq.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

uint8_t plic_interrupt_priority_get(plic_t plic, uint8_t intr_id)
void plic_init(plic_t plic)
{
if (intr_id >= PLIC_NUM_SRC) {
return 0;
}
return (DEV_READ(plic + PLIC_PRIO_REG + 4 * intr_id) & PLIC_PRIO_MASK);
plic_machine_interrupt_enable_write(plic, 0u);
plic_supervisor_interrupt_enable_write(plic, 0u);
}

void plic_interrupt_priority_set(plic_t plic, uint8_t intr_id, uint8_t prio)
uint8_t plic_interrupt_priority_read(plic_t plic, enum mocha_system_irq intr)
{
if (intr_id < PLIC_NUM_SRC) {
DEV_WRITE(plic + PLIC_PRIO_REG + 4 * intr_id, prio & PLIC_PRIO_MASK);
if (intr == 0u) {
return 0u;
}
/* TODO: panic if more than one irq bit is set */
size_t id = ctz(intr);
plic_prio prio = VOLATILE_READ(plic->prio[id]);
return prio.prio;
}

bool plic_interrupt_is_pending(plic_t plic, uint8_t intr_id)
void plic_interrupt_priority_write(plic_t plic, enum mocha_system_irq intr_set, uint8_t priority)
{
return ((DEV_READ(plic + PLIC_IP_REG) & (1 << intr_id)) != 0);
if (intr_set == 0u) {
return;
}

enum mocha_system_irq remain = intr_set;
do {
size_t id = ctz(remain);
remain &= ~(1u << id);
plic_prio prio = { .prio = priority };
VOLATILE_WRITE(plic->prio[id], prio);
} while (remain != 0u);
}

bool plic_machine_interrupt_enable_get(plic_t plic, uint8_t intr_id)
enum mocha_system_irq plic_machine_interrupt_enable_read(plic_t plic)
{
return ((DEV_READ(plic + PLIC_IE0_REG) & (1 << intr_id)) != 0);
return (enum mocha_system_irq)VOLATILE_READ(plic->ie0);
}

bool plic_supervisor_interrupt_enable_get(plic_t plic, uint8_t intr_id)
enum mocha_system_irq plic_supervisor_interrupt_enable_read(plic_t plic)
{
return ((DEV_READ(plic + PLIC_IE1_REG) & (1 << intr_id)) != 0);
return (enum mocha_system_irq)VOLATILE_READ(plic->ie1);
}

void plic_machine_interrupt_enable(plic_t plic, uint8_t intr_id)
void plic_machine_interrupt_enable_write(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE0_REG, DEV_READ(plic + PLIC_IE0_REG) | (1 << intr_id));
VOLATILE_WRITE(plic->ie0, intr_set);
}

void plic_supervisor_interrupt_enable(plic_t plic, uint8_t intr_id)
void plic_supervisor_interrupt_enable_write(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE1_REG, DEV_READ(plic + PLIC_IE1_REG) | (1 << intr_id));
VOLATILE_WRITE(plic->ie1, intr_set);
}

void plic_machine_interrupt_disable(plic_t plic, uint8_t intr_id)
void plic_machine_interrupt_enable_set(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE0_REG, DEV_READ(plic + PLIC_IE0_REG) & ~(1 << intr_id));
uint32_t ie0 = VOLATILE_READ(plic->ie0);
ie0 |= intr_set;
VOLATILE_WRITE(plic->ie0, ie0);
}

void plic_supervisor_interrupt_disable(plic_t plic, uint8_t intr_id)
void plic_supervisor_interrupt_enable_set(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE1_REG, DEV_READ(plic + PLIC_IE1_REG) & ~(1 << intr_id));
Comment thread
ziuziakowska marked this conversation as resolved.
uint32_t ie1 = VOLATILE_READ(plic->ie1);
ie1 |= intr_set;
VOLATILE_WRITE(plic->ie1, ie1);
}

void plic_machine_interrupt_disable_all(plic_t plic)
void plic_machine_interrupt_enable_clear(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE0_REG, 0);
uint32_t ie0 = VOLATILE_READ(plic->ie0);
ie0 &= ~intr_set;
VOLATILE_WRITE(plic->ie0, ie0);
}

void plic_supervisor_interrupt_disable_all(plic_t plic)
void plic_supervisor_interrupt_enable_clear(plic_t plic, enum mocha_system_irq intr_set)
{
DEV_WRITE(plic + PLIC_IE1_REG, 0);
uint32_t ie1 = VOLATILE_READ(plic->ie1);
ie1 &= ~intr_set;
VOLATILE_WRITE(plic->ie1, ie1);
}

uint8_t plic_machine_priority_threshold_get(plic_t plic)
bool plic_interrupt_all_pending(plic_t plic, enum mocha_system_irq intr_set)
{
return (DEV_READ(plic + PLIC_THRESHOLD0_REG) & PLIC_PRIO_MASK);
return (VOLATILE_READ(plic->ip) & intr_set) == intr_set;
}

uint8_t plic_supervisor_priority_threshold_get(plic_t plic)
bool plic_interrupt_any_pending(plic_t plic, enum mocha_system_irq intr_set)
{
return (DEV_READ(plic + PLIC_THRESHOLD1_REG) & PLIC_PRIO_MASK);
return (VOLATILE_READ(plic->ip) & intr_set) != 0u;
}

void plic_machine_priority_threshold_set(plic_t plic, uint8_t prio)
uint8_t plic_machine_priority_threshold_read(plic_t plic)
{
DEV_WRITE(plic + PLIC_THRESHOLD0_REG, prio & PLIC_PRIO_MASK);
plic_threshold0 threshold = VOLATILE_READ(plic->threshold0);
return threshold.threshold0;
}

void plic_supervisor_priority_threshold_set(plic_t plic, uint8_t prio)
uint8_t plic_supervisor_priority_threshold_read(plic_t plic)
{
DEV_WRITE(plic + PLIC_THRESHOLD1_REG, prio & PLIC_PRIO_MASK);
plic_threshold1 threshold = VOLATILE_READ(plic->threshold1);
return threshold.threshold1;
}

uint8_t plic_machine_interrupt_claim(plic_t plic)
void plic_machine_priority_threshold_write(plic_t plic, uint8_t priority)
{
return (uint8_t)DEV_READ(plic + PLIC_CC0_REG);
plic_threshold0 threshold = { .threshold0 = priority };
VOLATILE_WRITE(plic->threshold0, threshold);
}

uint8_t plic_supervisor_interrupt_claim(plic_t plic)
void plic_supervisor_priority_threshold_write(plic_t plic, uint8_t priority)
{
return (uint8_t)DEV_READ(plic + PLIC_CC1_REG);
plic_threshold1 threshold = { .threshold1 = priority };
VOLATILE_WRITE(plic->threshold1, threshold);
}

void plic_machine_interrupt_complete(plic_t plic, uint8_t intr_id)
enum mocha_system_irq plic_machine_interrupt_claim(plic_t plic)
{
DEV_WRITE(plic + PLIC_CC0_REG, (uint32_t)intr_id);
plic_cc0 claim = VOLATILE_READ(plic->cc0);
return (enum mocha_system_irq)(1u << claim.cc0);
}

void plic_supervisor_interrupt_complete(plic_t plic, uint8_t intr_id)
enum mocha_system_irq plic_supervisor_interrupt_claim(plic_t plic)
{
DEV_WRITE(plic + PLIC_CC1_REG, (uint32_t)intr_id);
plic_cc1 claim = VOLATILE_READ(plic->cc1);
return (enum mocha_system_irq)(1u << claim.cc1);
}

void plic_alert_trigger(plic_t plic)
void plic_machine_interrupt_complete(plic_t plic, enum mocha_system_irq intr)
{
DEV_WRITE(plic + PLIC_ALERT_TEST_REG, 1);
if (intr == 0u) {
return;
}
/* TODO: panic if more than one irq bit is set */
size_t id = ctz(intr);
plic_cc0 complete = { .cc0 = id };
VOLATILE_WRITE(plic->cc0, complete);
}

void plic_init(plic_t plic)
void plic_supervisor_interrupt_complete(plic_t plic, enum mocha_system_irq intr)
{
plic_machine_interrupt_disable_all(plic);
plic_supervisor_interrupt_disable_all(plic);
if (intr == 0u) {
return;
}
/* TODO: panic if more than one irq bit is set */
size_t id = ctz(intr);
plic_cc1 complete = { .cc1 = id };
VOLATILE_WRITE(plic->cc1, complete);
}
102 changes: 63 additions & 39 deletions sw/device/lib/hal/plic.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,70 @@

#pragma once

#include "autogen/plic.h"
#include "mocha_irq.h"
#include <stdbool.h>
#include <stdint.h>

#define PLIC_PRIO_REG (0x0)
#define PLIC_PRIO_MASK (0x3)

#define PLIC_IP_REG (0x1000)
#define PLIC_IE0_REG (0x2000)
#define PLIC_IE1_REG (0x2100)
#define PLIC_THRESHOLD0_REG (0x200000)
#define PLIC_THRESHOLD1_REG (0x201000)
#define PLIC_CC0_REG (0x200004)
#define PLIC_CC1_REG (0x201004)
#define PLIC_MSIP0_REG (0x4000000)
#define PLIC_MSIP1_REG (0x4000004)
#define PLIC_ALERT_TEST_REG (0x4004000)

#define PLIC_NUM_SRC (32)

typedef void *plic_t;

uint8_t plic_interrupt_priority_get(plic_t plic, uint8_t intr_id);
void plic_interrupt_priority_set(plic_t plic, uint8_t intr_id, uint8_t prio);
bool plic_interrupt_is_pending(plic_t plic, uint8_t intr_id);
bool plic_machine_interrupt_enable_get(plic_t plic, uint8_t intr_id);
bool plic_supervisor_interrupt_enable_get(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_enable(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_enable(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_disable(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_disable(plic_t plic, uint8_t intr_id);
void plic_machine_interrupt_disable_all(plic_t plic);
void plic_supervisor_interrupt_disable_all(plic_t plic);
uint8_t plic_machine_priority_threshold_get(plic_t plic);
uint8_t plic_supervisor_priority_threshold_get(plic_t plic);
void plic_machine_priority_threshold_set(plic_t plic, uint8_t prio);
void plic_supervisor_priority_threshold_set(plic_t plic, uint8_t prio);
uint8_t plic_machine_interrupt_claim(plic_t plic);
uint8_t plic_supervisor_interrupt_claim(plic_t plic);
void plic_machine_interrupt_complete(plic_t plic, uint8_t intr_id);
void plic_supervisor_interrupt_complete(plic_t plic, uint8_t intr_id);
void plic_alert_trigger(plic_t plic);

/* initialistation */
void plic_init(plic_t plic);

/* get the priority of the single interrupt 'intr' */
uint8_t plic_interrupt_priority_read(plic_t plic, enum mocha_system_irq intr);

/* set the priority of each interrupt in the set 'intr_set' to 'priority' */
void plic_interrupt_priority_write(plic_t plic, enum mocha_system_irq intr_set, uint8_t priority);
Comment thread
ziuziakowska marked this conversation as resolved.

/* get the set of enabled external interrupts for M-mode */
enum mocha_system_irq plic_machine_interrupt_enable_read(plic_t plic);

/* get the set of enabled external interrupts for S-mode */
enum mocha_system_irq plic_supervisor_interrupt_enable_read(plic_t plic);

/* set the interrupts enabled for M-mode to the interrupts in 'intr_set' */
void plic_machine_interrupt_enable_write(plic_t plic, enum mocha_system_irq intr_set);

/* set the interrupts enabled for S-mode to the interrupts in 'intr_set' */
void plic_supervisor_interrupt_enable_write(plic_t plic, enum mocha_system_irq intr_set);

/* add the interrupts in 'intr_set' to the set of interrupts enabled for M-mode */
void plic_machine_interrupt_enable_set(plic_t plic, enum mocha_system_irq intr_set);

/* add the interrupts in 'intr_set' to the set of interrupts enabled for S-mode */
void plic_supervisor_interrupt_enable_set(plic_t plic, enum mocha_system_irq intr_set);

/* remove the interrupts in 'intr_set' from the set of interrupts enabled for M-mode */
void plic_machine_interrupt_enable_clear(plic_t plic, enum mocha_system_irq intr_set);

/* remove the interrupts in 'intr_set' from the set of interrupts enabled for S-mode */
void plic_supervisor_interrupt_enable_clear(plic_t plic, enum mocha_system_irq intr_set);

/* returns whether all of the interrupts in 'intr_set' are pending */
bool plic_interrupt_all_pending(plic_t plic, enum mocha_system_irq intr_set);

/* returns whether any of the interrupts in 'intr_set' are pending */
bool plic_interrupt_any_pending(plic_t plic, enum mocha_system_irq intr_set);

/* get the interrupt priority threshold for M-mode */
uint8_t plic_machine_priority_threshold_read(plic_t plic);

/* get the interrupt priority threshold for S-mode */
uint8_t plic_supervisor_priority_threshold_read(plic_t plic);

/* set the interrupt priority threshold for M-mode to 'priority' */
void plic_machine_priority_threshold_write(plic_t plic, uint8_t priority);

/* set the interrupt priority threshold for S-mode to 'priority' */
void plic_supervisor_priority_threshold_write(plic_t plic, uint8_t priority);

/* claim a single interrupt for M-mode */
enum mocha_system_irq plic_machine_interrupt_claim(plic_t plic);

/* claim a single interrupt for S-mode */
enum mocha_system_irq plic_supervisor_interrupt_claim(plic_t plic);

/* complete a single interrupt for M-mode */
void plic_machine_interrupt_complete(plic_t plic, enum mocha_system_irq intr);

/* complete a single interrupt for S-mode */
void plic_supervisor_interrupt_complete(plic_t plic, enum mocha_system_irq intr);
Loading