summaryrefslogtreecommitdiff
path: root/bsp/ultrarisc/arch
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/ultrarisc/arch')
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/SConscript12
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/cache.c45
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/cache.h92
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/interrupt.c92
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/interrupt.h46
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/opcode.h40
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/plic.c255
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/plic.h81
-rw-r--r--bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h195
9 files changed, 858 insertions, 0 deletions
diff --git a/bsp/ultrarisc/arch/ur-cp100/SConscript b/bsp/ultrarisc/arch/ur-cp100/SConscript
new file mode 100644
index 0000000000..640ac340f6
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/SConscript
@@ -0,0 +1,12 @@
+# RT-Thread building script for component
+
+from building import *
+cwd = GetCurrentDir()
+src = Glob('*.c') + Glob('*.cpp')
+CPPPATH = [cwd]
+
+group = DefineGroup('arch', src, depend = [''], CPPPATH = CPPPATH)
+
+objs = [group]
+
+Return('objs')
diff --git a/bsp/ultrarisc/arch/ur-cp100/cache.c b/bsp/ultrarisc/arch/ur-cp100/cache.c
new file mode 100644
index 0000000000..57f47e7bed
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/cache.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-29 lizhirui first version
+ * 2025-05-29 Zhang Jing remove redundant code
+ */
+
+#include <rthw.h>
+#include <rtdef.h>
+#include <board.h>
+#include <riscv.h>
+#include <cache.h>
+
+void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_INVALIDATE)
+ {
+ rt_hw_cpu_icache_invalidate(addr, size);
+ }
+ return;
+}
+
+void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
+{
+ if (ops == RT_HW_CACHE_FLUSH)
+ {
+ rt_hw_cpu_dcache_clean(addr, size);
+ }
+ else
+ {
+ rt_hw_cpu_dcache_invalidate(addr, size);
+ }
+ return;
+}
+
+void rt_hw_sync_cache_local(void *addr, int size)
+{
+ rt_hw_cpu_dcache_clean_local(addr, size);
+ rt_hw_cpu_icache_invalidate_local(addr, size);
+ return;
+} \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/cache.h b/bsp/ultrarisc/arch/ur-cp100/cache.h
new file mode 100644
index 0000000000..55d532f958
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/cache.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-09 RT-Thread The first version
+ */
+#ifndef __CACHE_H__
+#define __CACHE_H__
+
+#include <rtdef.h>
+
+/**
+ * @brief These APIs may not be supported by a specified architecture
+ * But we have to include to all the cases to be 'general purpose'
+ */
+
+rt_always_inline void rt_hw_cpu_dcache_clean_local(void *addr, int size)
+{
+ RT_UNUSED(addr);
+ RT_UNUSED(size);
+}
+
+rt_always_inline void rt_hw_cpu_dcache_invalidate_local(void *addr, int size)
+{
+ RT_UNUSED(addr);
+ RT_UNUSED(size);
+}
+
+rt_always_inline void rt_hw_cpu_dcache_clean_and_invalidate_local(void *addr, int size)
+{
+ RT_UNUSED(addr);
+ RT_UNUSED(size);
+}
+
+rt_always_inline void rt_hw_cpu_dcache_clean_all_local(void)
+{
+}
+
+rt_always_inline void rt_hw_cpu_dcache_invalidate_all_local(void)
+{
+}
+
+rt_always_inline void rt_hw_cpu_dcache_clean_and_invalidate_all_local(void)
+{
+}
+
+/*use fence.i to invalidate all icache*/
+rt_always_inline void rt_hw_cpu_icache_invalidate_local(void *addr, int size)
+{
+ __asm__ __volatile__("fence.i" ::: "memory");
+}
+/*use fence.i to invalidate all icache*/
+rt_always_inline void rt_hw_cpu_icache_invalidate_all_local(void)
+{
+ __asm__ __volatile__("fence.i" ::: "memory");
+}
+
+/**
+ * @brief Multi-core
+ */
+
+#define rt_hw_cpu_dcache_clean rt_hw_cpu_dcache_clean_local
+#define rt_hw_cpu_dcache_invalidate rt_hw_cpu_dcache_invalidate_local
+#define rt_hw_cpu_dcache_clean_and_invalidate rt_hw_cpu_dcache_clean_and_invalidate_local
+
+#define rt_hw_cpu_dcache_clean_all rt_hw_cpu_dcache_clean_all_local
+#define rt_hw_cpu_dcache_invalidate_all rt_hw_cpu_dcache_invalidate_all_local
+#define rt_hw_cpu_dcache_clean_and_invalidate_all rt_hw_cpu_dcache_clean_and_invalidate_all_local
+
+#define rt_hw_cpu_icache_invalidate rt_hw_cpu_icache_invalidate_local
+#define rt_hw_cpu_icache_invalidate_all rt_hw_cpu_icache_invalidate_all_local
+
+#define rt_hw_icache_invalidate_all rt_hw_cpu_icache_invalidate_all
+
+/** instruction barrier */
+static inline void rt_hw_cpu_sync(void)
+{
+ __asm__ __volatile__("fence.i" ::: "memory");
+}
+
+/**
+ * @brief local cpu icahce & dcache synchronization
+ *
+ * @param addr
+ * @param size
+ */
+void rt_hw_sync_cache_local(void *addr, int size);
+
+#endif /* __CACHE_H__ */ \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/interrupt.c b/bsp/ultrarisc/arch/ur-cp100/interrupt.c
new file mode 100644
index 0000000000..67947cd627
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/interrupt.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018/10/01 Bernard The first version
+ * 2018/12/27 Jesven Change irq enable/disable to cpu0
+ */
+#include <plic.h>
+#include "encoding.h"
+#include "riscv.h"
+#include "interrupt.h"
+
+struct rt_irq_desc irq_desc[MAX_HANDLERS];
+
+static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
+{
+ rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
+ return RT_NULL;
+}
+
+int rt_hw_plic_irq_enable(int irq_number)
+{
+ plic_irq_enable(irq_number);
+ return 0;
+}
+
+int rt_hw_plic_irq_disable(int irq_number)
+{
+ plic_irq_disable(irq_number);
+ return 0;
+}
+
+/**
+ * This function will un-mask a interrupt.
+ * @param vector the interrupt number
+ */
+void rt_hw_interrupt_umask(int vector)
+{
+ plic_set_priority(vector, 1);
+
+ rt_hw_plic_irq_enable(vector);
+}
+
+/**
+ * This function will install a interrupt service routine to a interrupt.
+ * @param vector the interrupt number
+ * @param new_handler the interrupt service routine to be installed
+ * @param old_handler the old interrupt service routine
+ */
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
+ void *param, const char *name)
+{
+ rt_isr_handler_t old_handler = RT_NULL;
+
+ if (vector < MAX_HANDLERS)
+ {
+ old_handler = irq_desc[vector].handler;
+ if (handler != RT_NULL)
+ {
+ irq_desc[vector].handler = (rt_isr_handler_t)handler;
+ irq_desc[vector].param = param;
+#ifdef RT_USING_INTERRUPT_INFO
+ rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
+ irq_desc[vector].counter = 0;
+#endif
+ }
+ }
+
+ return old_handler;
+}
+
+void rt_hw_interrupt_init()
+{
+ /* Enable machine external interrupts. */
+ /* set_csr(sie, SIP_SEIP); */
+ int idx = 0;
+ /* init exceptions table */
+ for (idx = 0; idx < MAX_HANDLERS; idx++)
+ {
+ irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
+ irq_desc[idx].param = RT_NULL;
+#ifdef RT_USING_INTERRUPT_INFO
+ rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
+ irq_desc[idx].counter = 0;
+#endif
+ }
+ /*init plic*/
+ plic_init();
+} \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/interrupt.h b/bsp/ultrarisc/arch/ur-cp100/interrupt.h
new file mode 100644
index 0000000000..cda387087a
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/interrupt.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic The first version
+ */
+
+#ifndef INTERRUPT_H__
+#define INTERRUPT_H__
+
+#define MAX_HANDLERS 128
+
+#include <rthw.h>
+#include "stack.h"
+
+enum
+{
+ EP_INSTRUCTION_ADDRESS_MISALIGNED = 0,
+ EP_INSTRUCTION_ACCESS_FAULT,
+ EP_ILLEGAL_INSTRUCTION,
+ EP_BREAKPOINT,
+ EP_LOAD_ADDRESS_MISALIGNED,
+ EP_LOAD_ACCESS_FAULT,
+ EP_STORE_ADDRESS_MISALIGNED,
+ EP_STORE_ACCESS_FAULT,
+ EP_ENVIRONMENT_CALL_U_MODE,
+ EP_ENVIRONMENT_CALL_S_MODE,
+ EP_RESERVED10,
+ EP_ENVIRONMENT_CALL_M_MODE,
+ EP_INSTRUCTION_PAGE_FAULT, /* page attr */
+ EP_LOAD_PAGE_FAULT, /* read data */
+ EP_RESERVED14,
+ EP_STORE_PAGE_FAULT, /* write data */
+};
+
+int rt_hw_plic_irq_enable(int irq_number);
+int rt_hw_plic_irq_disable(int irq_number);
+void rt_hw_interrupt_init(void);
+void rt_hw_interrupt_mask(int vector);
+rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name);
+void handle_trap(rt_size_t xcause, rt_size_t xtval, rt_size_t xepc, struct rt_hw_stack_frame *sp);
+
+#endif \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/opcode.h b/bsp/ultrarisc/arch/ur-cp100/opcode.h
new file mode 100644
index 0000000000..8bdf4afe35
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/opcode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-09 Shell Add portable asm support
+ */
+#ifndef __OPCODE_H__
+#define __OPCODE_H__
+
+/**
+ * @brief binary opcode pseudo operations
+ * Used to bypass toolchain restriction on extension ISA
+ *
+ */
+
+/**
+ * @brief RISC-V instruction formats
+ */
+
+/**
+ * R type: .insn r opcode6, func3, func7, rd, rs1, rs2
+ *
+ * +-------+-----+-----+-------+----+---------+
+ * | func7 | rs2 | rs1 | func3 | rd | opcode6 |
+ * +-------+-----+-----+-------+----+---------+
+ * 31 25 20 15 12 7 0
+ */
+#define __OPC_INSN_FORMAT_R(opcode, func3, func7, rd, rs1, rs2) \
+ ".insn r "RT_STRINGIFY(opcode)","RT_STRINGIFY(func3)","RT_STRINGIFY(func7)","RT_STRINGIFY(rd)","RT_STRINGIFY(rs1)","RT_STRINGIFY(rs2)
+
+#ifdef _TOOLCHAIN_SUPP_ZIFENCEI_ISA_
+ #define OPC_FENCE_I "fence.i"
+#else /* !_TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
+ #define OPC_FENCE_I ".long 0x0000100F"
+#endif /* _TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
+
+#endif /* __OPCODE_H__ */ \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/plic.c b/bsp/ultrarisc/arch/ur-cp100/plic.c
new file mode 100644
index 0000000000..7317b5b85e
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/plic.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Support for RISC-V Platform-Level Interrupt Controller(PLIC)
+ * Specification Version 1.0.0, which is currently(3/12/2023) the
+ * lastest draft.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic first version
+ * 2022-09-16 WangXiaoyao Porting to rv64
+ * 2025-01-26 ZhangJing Porting to ultrarisc cp100
+ */
+#include <rthw.h>
+#include <rtthread.h>
+#include <stdint.h>
+#include "plic.h"
+#include <io.h>
+#include "encoding.h"
+#include <interrupt.h>
+#include <riscv_io.h>
+#include <riscv.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef RT_USING_SMART
+ #include <ioremap.h>
+#else
+ #define rt_ioremap(addr, ...) (addr)
+#endif
+
+/* plic_base should be initialized in the bsp*/
+size_t plic_base = 0 ;
+
+/*
+ * Each PLIC interrupt source can be assigned a priority by writing
+ * to its 32-bit memory-mapped priority register.
+ * Maximum priority is 7.
+ * A priority value of 0 is reserved to mean "never interrupt" and
+ * effectively disables the interrupt.
+ * Ties between global interrupts of the same priority are broken by
+ * the Interrupt ID; interrupts with the lowest ID have the highest
+ * effective priority.
+ */
+void plic_set_priority(int irq, int priority)
+{
+ writel(priority, (void *)PLIC_PRIORITY(irq));
+}
+
+/*
+ * Each global interrupt can be enabled by setting the corresponding
+ * bit in the enables registers.
+ */
+void plic_irq_enable(int irq)
+{
+ int hart = __raw_hartid();
+ void *enable = (void *)PLIC_ENABLE(hart) + (irq / 32) * sizeof(uint32_t);
+ rt_uint32_t val = readl(enable);
+ val |= (1 << (irq % 32));
+ writel(val, enable);
+ return;
+}
+
+/*
+ * Each global interrupt can be disabled by clearing the corresponding
+ * bit in the enables registers.
+ */
+void plic_irq_disable(int irq)
+{
+ int hart = __raw_hartid();
+ void *enable = (void *)PLIC_ENABLE(hart) + (irq / 32) * sizeof(uint32_t);
+ rt_uint32_t val = readl(enable);
+ val &= ~(1 << (irq % 32));
+ writel(val, enable);
+
+ return;
+}
+
+/*
+ * PLIC will mask all interrupts of a priority less than or equal to threshold.
+ * Maximum threshold is 7.
+ * For example, a threshold value of zero permits all interrupts with
+ * non-zero priority, whereas a value of 7 masks all interrupts.
+ * Notice, the threshold is global for PLIC, not for each interrupt source.
+ */
+void plic_set_threshold(int threshold)
+{
+ int hart = __raw_hartid();
+ writel(threshold, (void *)PLIC_THRESHOLD(hart));
+ return;
+}
+
+/*
+ * DESCRIPTION:
+ * Query the PLIC what interrupt we should serve.
+ * Perform an interrupt claim by reading the claim register, which
+ * returns the ID of the highest-priority pending interrupt or zero if there
+ * is no pending interrupt.
+ * A successful claim also atomically clears the corresponding pending bit
+ * on the interrupt source.
+ * RETURN VALUE:
+ * the ID of the highest-priority pending interrupt or zero if there
+ * is no pending interrupt.
+ */
+rt_uint32_t plic_claim(void)
+{
+ int hart = __raw_hartid();
+ void *claim = (void *)PLIC_CLAIM(hart);
+ return readl(claim);
+}
+
+/*
+ * DESCRIPTION:
+ * Writing the interrupt ID it received from the claim (irq) to the
+ * complete register would signal the PLIC we've served this IRQ.
+ * The PLIC does not check whether the completion ID is the same as the
+ * last claim ID for that target. If the completion ID does not match an
+ * interrupt source that is currently enabled for the target, the completion
+ * is silently ignored.
+ * RETURN VALUE: none
+ */
+void plic_complete(int irq)
+{
+ int hart = __raw_hartid();
+ void *complete = (void *)PLIC_COMPLETE(hart);
+ writel(irq, complete);
+ return;
+}
+
+void plic_init()
+{
+ if (!plic_base)
+ {
+ return;
+ }
+ /* PLIC takes up 64 MB space */
+ plic_base = (size_t)rt_ioremap((void *)plic_base, 64 * 1024 * 1024);
+
+ plic_set_threshold(0);
+
+ /*set the same priority for all the irqs*/
+ for (int i = 1; i < CONFIG_IRQ_NR; i++)
+ {
+ plic_set_priority(i, 1);
+ }
+
+ /*disable all interrupts*/
+ for (int i = 1; i < CONFIG_IRQ_NR; i++)
+ {
+ plic_irq_disable(i);
+ }
+
+ set_csr(sie, read_csr(sie) | MIP_SEIP);
+
+ return;
+}
+
+extern struct rt_irq_desc irq_desc[MAX_HANDLERS];
+#ifdef BOARD_UR_DP1000
+int find_first_bit(rt_uint32_t *addr, int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ if (*addr & (1 << i))
+ return i;
+ }
+ return -1;
+}
+
+static rt_bool_t is_irqs_pending(rt_uint32_t ie[])
+{
+
+ int hartid = __raw_hartid();
+ int nr_irqs = CONFIG_IRQ_NR;
+ int nr_irq_groups = (nr_irqs + 31) / 32;
+ rt_bool_t is_pending = RT_FALSE;
+ void *pending_base = (void *)PLIC_PENDING(0);
+ void *enable_base = (void *)PLIC_ENABLE(hartid);
+ int i, j;
+
+ for (i = 0; i < nr_irq_groups; i++)
+ ie[i] = readl(enable_base + i * sizeof(rt_uint32_t));
+
+ for (i = 0; i < nr_irq_groups; i++)
+ {
+ rt_uint32_t pending_irqs = readl(pending_base + i * sizeof(rt_uint32_t)) & ie[i];
+ if (pending_irqs)
+ {
+ int nbit = find_first_bit(&pending_irqs, 32);
+ for (j = 0; j < nr_irq_groups; j++)
+ writel((i == j) ? (1 << nbit) : 0, enable_base + j * sizeof(rt_uint32_t));
+
+ is_pending = RT_TRUE;
+ break;
+ }
+ }
+
+ return is_pending;
+}
+
+static void restore_irqs_enable(rt_uint32_t ie[])
+{
+ int hartid = __raw_hartid();
+ int nr_irqs = CONFIG_IRQ_NR;
+ int nr_irq_groups = (nr_irqs + 31) / 32;
+ void *enable_base = (void *)PLIC_ENABLE(hartid);
+ int i;
+
+ for (i = 0; i < nr_irq_groups; i++)
+ writel(ie[i], enable_base + i * sizeof(rt_uint32_t));
+
+ return;
+}
+#endif
+/*
+ * Handling an interrupt is a two-step process: first you claim the interrupt
+ * by reading the claim register, then you complete the interrupt by writing
+ * that source ID back to the same claim register. This automatically enables
+ * and disables the interrupt, so there's nothing else to do.
+ */
+void plic_handle_irq(void)
+{
+ rt_uint32_t plic_irq;
+#ifdef BOARD_UR_DP1000
+ /* TODO: if not only one interrupt, we need to continue to check the interrupt source */
+ unsigned int ie[32] = {0};
+ plic_irq = is_irqs_pending(ie) ? plic_claim() : 0;
+ restore_irqs_enable(ie);
+ if (plic_irq > CONFIG_IRQ_NR)
+ {
+ /*spurious interrupt, return directly*/
+ rt_kprintf("spurious interrupt, irq = %d\n", plic_irq);
+ return;
+ }
+ plic_complete(plic_irq);
+
+ irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
+
+#else
+ plic_irq = plic_claim();
+ plic_complete(plic_irq);
+ if (plic_irq > CONFIG_IRQ_NR)
+ {
+ /*spurious interrupt, return directly*/
+ rt_kprintf("spurious interrupt, irq = %d\n", plic_irq);
+ return;
+ }
+
+ irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param);
+#endif
+ return;
+} \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/plic.h b/bsp/ultrarisc/arch/ur-cp100/plic.h
new file mode 100644
index 0000000000..050a24d7bb
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/plic.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-05-20 bigmagic first version
+ * 2021-10-20 bernard fix s-mode issue
+ * 2025-01-26 ZhangJing Porting to ultrarisc cp100
+ */
+
+#ifndef __PLIC_H__
+#define __PLIC_H__
+
+#include <rtconfig.h>
+#include <rthw.h>
+
+#define PLIC_PRIORITY_BASE 0x0
+#define PLIC_PENDING_BASE 0x1000
+#define PLIC_ENABLE_BASE 0x2000
+#define PLIC_CONTEXT_BASE 0x200000
+
+extern size_t plic_base;
+
+#define PLIC_BASE (plic_base)
+
+#define PLIC_PRIORITY_OFFSET (0x0)
+#define PLIC_PENDING_OFFSET (0x1000)
+
+#define PLIC_ENABLE_STRIDE 0x80
+#define PLIC_CONTEXT_STRIDE 0x1000
+
+#define RISCV_S_MODE
+
+#ifndef RISCV_S_MODE
+ /*using context 0*/
+ #define PLIC_MENABLE_OFFSET (0x2000)
+ #define PLIC_MTHRESHOLD_OFFSET (0x200000)
+ #define PLIC_MCLAIM_OFFSET (0x200004)
+ #define PLIC_MCOMPLETE_OFFSET (0x200004)
+
+ #define PLIC_ENABLE(hart) (PLIC_BASE + PLIC_MENABLE_OFFSET + (hart * 3) * PLIC_ENABLE_STRIDE)
+ #define PLIC_THRESHOLD(hart) (PLIC_BASE + PLIC_MTHRESHOLD_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+ #define PLIC_CLAIM(hart) (PLIC_BASE + PLIC_MCLAIM_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+ #define PLIC_COMPLETE(hart) (PLIC_BASE + PLIC_MCOMPLETE_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+
+#else
+ /*using context 1*/
+ #define PLIC_SENABLE_OFFSET (0x2000 + PLIC_ENABLE_STRIDE)
+ #define PLIC_STHRESHOLD_OFFSET (0x200000 + PLIC_CONTEXT_STRIDE)
+ #define PLIC_SCLAIM_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE)
+ #define PLIC_SCOMPLETE_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE)
+
+ #define PLIC_ENABLE(hart) (PLIC_BASE + PLIC_SENABLE_OFFSET + (hart * 3) * PLIC_ENABLE_STRIDE)
+ #define PLIC_THRESHOLD(hart) (PLIC_BASE + PLIC_STHRESHOLD_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+ #define PLIC_CLAIM(hart) (PLIC_BASE + PLIC_SCLAIM_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+ #define PLIC_COMPLETE(hart) (PLIC_BASE + PLIC_SCOMPLETE_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE)
+#endif
+
+#define PLIC_PRIORITY(id) (PLIC_BASE + PLIC_PRIORITY_OFFSET + (id) * 4)
+#define PLIC_PENDING(id) (PLIC_BASE + PLIC_PENDING_OFFSET + ((id) / 32))
+
+#define WORD_CNT_BYTE (1024 / 8)
+
+#define CONFIG_IRQ_NR (32)
+#define CONFIG_IRQ_WORD (CONFIG_IRQ_NR / 32)
+
+void plic_set_priority(int irq, int priority);
+void plic_irq_enable(int irq);
+void plic_irq_disable(int irq);
+void plic_set_threshold(int mthreshold);
+rt_uint32_t plic_claim(void);
+void plic_complete(int irq);
+
+void plic_set_thresh(rt_uint32_t val);
+void plic_set_ie(rt_uint32_t word_index, rt_uint32_t val);
+void plic_init();
+void plic_handle_irq(void);
+
+#endif \ No newline at end of file
diff --git a/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h b/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h
new file mode 100644
index 0000000000..1048d4bb40
--- /dev/null
+++ b/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-01-30 lizhirui first version
+ * 2023-10-12 Shell Add permission control API
+ * 2025-01-22 ZhangJing Add pte default attribute for ur-cp100
+ */
+
+#ifndef __RISCV_MMU_H__
+#define __RISCV_MMU_H__
+
+#include <rtthread.h>
+#include <rthw.h>
+#include "riscv.h"
+
+#undef PAGE_SIZE
+
+#define PAGE_OFFSET_SHIFT 0
+#define PAGE_OFFSET_BIT 12
+#define PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+#define PAGE_OFFSET_MASK __MASK(PAGE_OFFSET_BIT)
+#define VPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define VPN0_BIT 9
+#define VPN1_SHIFT (VPN0_SHIFT + VPN0_BIT)
+#define VPN1_BIT 9
+#define VPN2_SHIFT (VPN1_SHIFT + VPN1_BIT)
+#define VPN2_BIT 9
+
+#define PPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT)
+#define PPN0_BIT 9
+#define PPN1_SHIFT (PPN0_SHIFT + PPN0_BIT)
+#define PPN1_BIT 9
+#define PPN2_SHIFT (PPN1_SHIFT + PPN1_BIT)
+#define PPN2_BIT 26
+#define PPN_BITS (PPN0_BIT + PPN1_BIT + PPN2_BIT)
+
+#define L1_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT + VPN1_BIT)
+#define L2_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT)
+#define L3_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT)
+
+#define ARCH_ADDRESS_WIDTH_BITS 64
+
+#define PHYSICAL_ADDRESS_WIDTH_BITS 56
+
+#define PAGE_ATTR_BASE (PTE_A | PTE_D)
+#define PAGE_ATTR_NEXT_LEVEL (0)
+#define PAGE_ATTR_RWX (PTE_X | PTE_W | PTE_R)
+#define PAGE_ATTR_READONLY (PTE_R)
+#define PAGE_ATTR_READEXECUTE (PTE_X | PTE_R)
+
+#define PAGE_ATTR_USER (PTE_U)
+#define PAGE_ATTR_SYSTEM (0)
+
+#define PAGE_DEFAULT_ATTR_LEAF (PAGE_ATTR_RWX | PAGE_ATTR_USER | PTE_V | PTE_G | PAGE_ATTR_BASE )
+#define PAGE_DEFAULT_ATTR_NEXT (PAGE_ATTR_NEXT_LEVEL | PTE_V | PTE_G)
+
+#define PAGE_IS_LEAF(pte) __MASKVALUE(pte, PAGE_ATTR_RWX)
+
+#define PTE_USED(pte) __MASKVALUE(pte, PTE_V)
+
+/**
+ * encoding of SATP (Supervisor Address Translation and Protection register)
+ */
+#define SATP_MODE_OFFSET 60
+#define SATP_MODE_BARE 0
+#define SATP_MODE_SV39 8
+#define SATP_MODE_SV48 9
+#define SATP_MODE_SV57 10
+#define SATP_MODE_SV64 11
+
+#define ARCH_VADDR_WIDTH 39
+#define SATP_MODE SATP_MODE_SV39
+
+#define MMU_MAP_K_DEVICE (PTE_G | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_K_RWCB (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_K_RW (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_U_RWCB (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_U_RWCB_XN (PTE_U | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_U_RW (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE)
+#define MMU_MAP_EARLY (PAGE_ATTR_RWX | PTE_G | PTE_V | PAGE_ATTR_BASE)
+
+#define PTE_XWR_MASK 0xe
+
+#define ARCH_PAGE_SIZE PAGE_SIZE
+#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
+#define ARCH_PAGE_SHIFT PAGE_OFFSET_BIT
+#define ARCH_INDEX_WIDTH 9
+#define ARCH_INDEX_SIZE (1ul << ARCH_INDEX_WIDTH)
+#define ARCH_INDEX_MASK (ARCH_INDEX_SIZE - 1)
+
+#define DRAM_SIZE (0x400000000) /* 16GB */
+#define MMIO_SIZE (0x80000000)
+#define MAP_COUNT ((DRAM_SIZE + MMIO_SIZE) >> VPN2_SHIFT)
+
+#define ARCH_MAP_FAILED ((void *)0x8000000000000000)
+
+void mmu_set_pagetable(rt_ubase_t addr);
+void mmu_enable_user_page_access(void);
+void mmu_disable_user_page_access(void);
+
+#define RT_HW_MMU_PROT_READ 1
+#define RT_HW_MMU_PROT_WRITE 2
+#define RT_HW_MMU_PROT_EXECUTE 4
+#define RT_HW_MMU_PROT_KERNEL 8
+#define RT_HW_MMU_PROT_USER 16
+#define RT_HW_MMU_PROT_CACHE 32
+
+void rt_hw_asid_init(void);
+struct rt_aspace;
+void rt_hw_asid_switch_pgtbl(struct rt_aspace *aspace, rt_ubase_t pgtbl);
+
+/**
+ * @brief Remove permission from attribution
+ *
+ * @param attr architecture specified mmu attribution
+ * @param prot protect that will be removed
+ * @return size_t returned attribution
+ */
+rt_inline size_t rt_hw_mmu_attr_rm_perm(size_t attr, rt_base_t prot)
+{
+ switch (prot)
+ {
+ /* remove write permission for user */
+ case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
+ attr &= ~PTE_W;
+ break;
+ /* remove write permission for kernel */
+ case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
+ attr &= ~PTE_W;
+ break;
+ default:
+ RT_ASSERT(0);
+ }
+ return attr;
+}
+
+/**
+ * @brief Add permission from attribution
+ *
+ * @param attr architecture specified mmu attribution
+ * @param prot protect that will be added
+ * @return size_t returned attribution
+ */
+rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot)
+{
+ switch (prot)
+ {
+ /* add write permission for user */
+ case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
+ attr |= (PTE_R | PTE_W | PTE_U);
+ break;
+ default:
+ RT_ASSERT(0);
+ }
+ return attr;
+}
+
+/**
+ * @brief Test permission from attribution
+ *
+ * @param attr architecture specified mmu attribution
+ * @param prot protect that will be test
+ * @return rt_bool_t RT_TRUE if the prot is allowed, otherwise RT_FALSE
+ */
+rt_inline rt_bool_t rt_hw_mmu_attr_test_perm(size_t attr, rt_base_t prot)
+{
+ rt_bool_t rc = 0;
+ switch (prot & ~RT_HW_MMU_PROT_USER)
+ {
+ /* test write permission for user */
+ case RT_HW_MMU_PROT_WRITE:
+ rc = ((attr & PTE_W) && (attr & PTE_R));
+ break;
+ case RT_HW_MMU_PROT_READ:
+ rc = !!(attr & PTE_R);
+ break;
+ case RT_HW_MMU_PROT_EXECUTE:
+ rc = !!(attr & PTE_X);
+ break;
+ default:
+ RT_ASSERT(0);
+ }
+
+ if (rc && (prot & RT_HW_MMU_PROT_USER))
+ {
+ rc = !!(attr & PTE_U);
+ }
+ return rc;
+}
+
+#endif \ No newline at end of file