diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 97684e4a80b0..136e8ce26a4b 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -5696,3 +5696,18 @@ zbus: - "area: llext" tests: - llext + +OpenRISC Arch: + status: maintained + maintainers: + - jhol + files: + - arch/openrisc/ + - boards/qemu/or1k/ + - drivers/timer/*openrisc* + - include/zephyr/arch/openrisc/ + - soc/qemu/or1k/ + labels: + - "area: OpenRISC" + tests: + - arch.openrisc diff --git a/arch/Kconfig b/arch/Kconfig index 94e9a540a08e..e0b73b1a0ed0 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -66,6 +66,16 @@ config MIPS help MIPS architecture +config OPENRISC + bool + select ARCH_IS_SET + select ATOMIC_OPERATIONS_BUILTIN + select BIG_ENDIAN + select USE_SWITCH + select USE_SWITCH_SUPPORTED + help + OpenRISC architecture + config SPARC bool select ARCH_IS_SET @@ -227,7 +237,7 @@ config SRAM_BASE_ADDRESS /chosen/zephyr,sram in devicetree. The user should generally avoid changing it via menuconfig or in configuration files. -if ARC || ARM || ARM64 || NIOS2 || X86 || RISCV +if ARC || ARM || ARM64 || NIOS2 || X86 || RISCV || OPENRISC # Workaround for not being able to have commas in macro arguments DT_CHOSEN_Z_FLASH := zephyr,flash @@ -250,7 +260,7 @@ config FLASH_BASE_ADDRESS normally set by the board's defconfig file and the user should generally avoid modifying it via the menu configuration. -endif # ARM || ARM64 || ARC || NIOS2 || X86 || RISCV +endif # ARM || ARM64 || ARC || NIOS2 || X86 || RISCV || OPENRISC if ARCH_HAS_TRUSTED_EXECUTION diff --git a/arch/archs.yml b/arch/archs.yml index e07d10ffe80b..ffb2cf1dcfb5 100644 --- a/arch/archs.yml +++ b/arch/archs.yml @@ -9,6 +9,8 @@ archs: path: mips - name: nios2 path: nios2 + - name: openrisc + path: openrisc - name: posix path: posix - name: riscv diff --git a/arch/openrisc/CMakeLists.txt b/arch/openrisc/CMakeLists.txt new file mode 100644 index 000000000000..76483141d1d5 --- /dev/null +++ b/arch/openrisc/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT "elf32-or1k") + +add_subdirectory(core) +zephyr_include_directories(include) diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig new file mode 100644 index 000000000000..48a9a4e2b1d3 --- /dev/null +++ b/arch/openrisc/Kconfig @@ -0,0 +1,26 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +menu "OpenRISC Options" + depends on OPENRISC + +config ARCH + string + default "openrisc" + +config GEN_ISR_TABLES + default y + +config GEN_IRQ_VECTOR_TABLE + default n + +config GEN_SW_ISR_TABLE + default y + +config NUM_IRQS + int + +endmenu diff --git a/arch/openrisc/core/CMakeLists.txt b/arch/openrisc/core/CMakeLists.txt new file mode 100644 index 000000000000..a9c17b6e8ed4 --- /dev/null +++ b/arch/openrisc/core/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() + +zephyr_library_sources( + cpu_idle.c + exception.S + fatal.c + irq_manage.c + irq_offload.c + prep_c.c + reboot.c + switch.S + thread.c +) + +zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) diff --git a/arch/openrisc/core/asm_macros.inc b/arch/openrisc/core/asm_macros.inc new file mode 100644 index 000000000000..2cb0b3c20f43 --- /dev/null +++ b/arch/openrisc/core/asm_macros.inc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * Convenience macros for assembly code + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Convenience macros for assembly code. */ + + +/* + * Helper macro which stores the value of a register to a the address contained + * in a pointer register plus an immediate offset. + */ + +.macro op_store_reg reg, off, ptr_reg + l.sw \off(\ptr_reg), \reg +.endm + + +/* + * Helper macro which loads a value to a register from an address contained in + * a pointer register plus an immediate offset. + */ + +.macro op_load_reg reg, off, ptr_reg + l.lwz \reg, \off(\ptr_reg) +.endm diff --git a/arch/openrisc/core/cpu_idle.c b/arch/openrisc/core/cpu_idle.c new file mode 100644 index 000000000000..5d17e33e799c --- /dev/null +++ b/arch/openrisc/core/cpu_idle.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include + +static ALWAYS_INLINE void openrisc_idle(unsigned int key) +{ + sys_trace_idle(); + + /* unlock interrupts */ + irq_unlock(key); + + /* wait for interrupt */ + if (openrisc_read_spr(SPR_UPR) & SPR_UPR_PMP) { + openrisc_write_spr(SPR_PMR, openrisc_read_spr(SPR_PMR) | SPR_PMR_DME); + } +} + +#ifndef CONFIG_ARCH_HAS_CUSTOM_CPU_IDLE +void arch_cpu_idle(void) +{ + openrisc_idle(1); +} +#endif + +#ifndef CONFIG_ARCH_HAS_CUSTOM_CPU_ATOMIC_IDLE +void arch_cpu_atomic_idle(unsigned int key) +{ + openrisc_idle(key); +} +#endif diff --git a/arch/openrisc/core/exception.S b/arch/openrisc/core/exception.S new file mode 100644 index 000000000000..4999561cd600 --- /dev/null +++ b/arch/openrisc/core/exception.S @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "asm_macros.inc" + +#define ESF_O(FIELD) __struct_arch_esf_##FIELD##_OFFSET + + +/* imports */ +GTEXT(z_openrisc_fault) + +GTEXT(z_check_stack_sentinel) +GTEXT(z_get_next_switch_handle) +GTEXT(z_openrisc_handle_irqs) +GTEXT(z_openrisc_switch) +GTEXT(z_openrisc_timer_isr) + +#if defined(CONFIG_SOC_RESET_HOOK) +GTEXT(soc_reset_hook) +#endif + +/* exports */ +GTEXT(__reset) +GTEXT(__start) + +GTEXT(z_openrisc_thread_start) + + +/* + * Zeros a continuous series of registers starting at first amd ending at last. + */ + +.altmacro +.macro zero_regs first=0, last=31 + l.movhi r\first, 0 +.if \last-\first + zero_regs %first+1, \last +.endif +.endm + + +/* + * Calls a given function, and sets the return address to return to another + * location. + */ + +.macro chain_call proc1, proc2 + l.movhi r9, hi(\proc2) +#ifdef __OR1K_NODELAY__ + l.ori r9, r9, lo(\proc2) + l.j \proc1 +#else + l.j \proc1 + l.ori r9, r9, lo(\proc2) +#endif +.endm + + +/* + * Calls a function specified by a register, and sets the return address to + * return to another location. + */ + +.macro chain_call_reg proc1_reg, proc2 + l.movhi r9, hi(\proc2) +#ifdef __OR1K_NODELAY__ + l.ori r9, r9, lo(\proc2) + l.jr \proc1_reg +#else + l.jr \proc1_reg + l.ori r9, r9, lo(\proc2) +#endif +.endm + + +/* + * Helper macro which loads or stores all caller-saved registers to the stack. + */ + +.macro do_caller_saved op + \op r3, ESF_O(r3), r1 + \op r4, ESF_O(r4), r1 + \op r5, ESF_O(r5), r1 + \op r6, ESF_O(r6), r1 + \op r7, ESF_O(r7), r1 + \op r8, ESF_O(r8), r1 + \op r11, ESF_O(r11), r1 + \op r12, ESF_O(r12), r1 + \op r13, ESF_O(r13), r1 + \op r15, ESF_O(r15), r1 + \op r17, ESF_O(r17), r1 + \op r19, ESF_O(r19), r1 + \op r21, ESF_O(r21), r1 + \op r23, ESF_O(r23), r1 + \op r25, ESF_O(r25), r1 + \op r27, ESF_O(r27), r1 + \op r29, ESF_O(r29), r1 + \op r31, ESF_O(r31), r1 +.endm + + +/* + * Stores all caller-saved registers to the stack. + */ + +.macro store_caller_saved + do_caller_saved op_store_reg +.endm + + +/* + * Loads all caller-saved registers from the stack. + */ + +.macro load_caller_saved + do_caller_saved op_load_reg +.endm + + +/* + * Stores the values of the ESR and EPCR registers into the est_t structure + * pointed at by the r1 stack pointer. + * + * Modifies: r15 + */ + +.macro store_esr_epcr + /* Save ESR */ + l.mfspr r15, r0, SPR_ESR_BASE + l.sw ESF_O(esr)(r1), r15 + + /* Save EPCR */ + l.mfspr r15, r0, SPR_EPCR_BASE + l.sw ESF_O(epcr)(r1), r15 +.endm + + +/* + * Loads the values of the ESR and EPCR registers from the est_t structure + * pointed at by the r1 stack pointer. + * + * Modifies: r15 + */ + +.macro load_esr_epcr + /* Load ESR */ + l.lwz r15, ESF_O(esr)(r1) + l.mtspr r0, r15, SPR_ESR_BASE + + /* Load EPCR */ + l.lwz r15, ESF_O(epcr)(r1) + l.mtspr r0, r15, SPR_EPCR_BASE +.endm + + +/* + * Stores the values of the MAC registers into the est_t structure pointed at + * by the r1 stack pointer. + * + * Modifies: r15 + */ + +.macro store_mac + l.mfspr r15, r0, SPR_MACLO + l.sw ESF_O(mac_lo)(r1), r15 + l.mfspr r15, r0, SPR_MACHI + l.sw ESF_O(mac_hi)(r1), r15 +.endm + + +/* + * Loads the values of the MAC registers from the est_t structure pointed at + * by the r1 stack pointer. + * + * Modifies: r15 + */ + +.macro load_mac + l.lwz r15, ESF_O(mac_lo)(r1) + l.mtspr r0, r15, SPR_MACLO + l.lwz r15, ESF_O(mac_hi)(r1) + l.mtspr r0, r15, SPR_MACHI +.endm + + +/* + * Declares a instruction exception label for a given address. + */ + +.macro exception_label num, label + .global _\label + .org ((\num) * 0x100) +_\label\(): + +.endm + + +/* + * Saves r9 on the current stack. + */ + +.macro push_r9 + l.addi r1, r1, -4 + l.sw 0(r1), r9 +.endm + + +/* + * Restores r9 from the current stack. + */ + +.macro pop_r9 + l.lwz r9, 0(r1) + l.addi r1, r1, 4 +.endm + + +/* + * Increments or decrements the _cpu->nested counter. + * + * Modifies: value_reg + */ + +.macro update_nested_count cpu_ptr_reg, value_reg, increment + l.lwz \value_reg, ___cpu_t_nested_OFFSET(\cpu_ptr_reg) + l.addi \value_reg, \value_reg, \increment + l.sw ___cpu_t_nested_OFFSET(\cpu_ptr_reg), \value_reg +.endm + + +/* + * Gets the current CPU structure. + * Loads the IRQ stack pointer, and updates the nested IRQ counter. + * + * Modifies: dst + */ + +.macro get_current_cpu dst + l.movhi \dst, hi(_kernel + ___kernel_t_cpus_OFFSET) + l.ori \dst, \dst, lo(_kernel + ___kernel_t_cpus_OFFSET) +.endm + + +/* + * Loads the IRQ stack pointer, and updates the nested IRQ counter. + * + * Modifies: r15, r17 + */ + +.macro setup_irq_stack + /* Get the cpu_t pointer */ + get_current_cpu r15 + + /* Increment the nested IRQ counter */ + update_nested_count r15, r17, 1 + + /* Skip if we're already in an interrupt, and save the stack pointer */ + l.sfgtui r17, 1 +#ifdef __OR1K_NODELAY__ + l.ori r17, r1, 0 + l.bf 1f +#else + l.bf 1f + l.ori r17, r1, 0 +#endif + + /* Switch to interrupt stack */ + l.lwz r1, ___cpu_t_irq_stack_OFFSET(r15) + + /* Save the stack pointer on the IRQ stack */ + l.addi r1, r1, -4 + l.sw 0(r1), r17 + +1: +.endm + + +/* + * Common head code required by all exception handler. + */ + +.macro exception_handler_head + /* Allocate esf_t on the stack */ + l.addi r1, r1, lo(-__struct_arch_esf_SIZEOF) + + /* Store caller-saved, exception and MAC registers */ + store_caller_saved + store_esr_epcr + store_mac +.endm + + +/* + * Common head code required by all ISRs. + */ + +.macro isr_head + exception_handler_head + + setup_irq_stack + + /* Save r9 on the stack */ + push_r9 +.endm + + +/* + * Common error handler functionality. + */ + +.macro error_handler_tail num + /* Call z_openrisc_fault with the esf and reason arguments */ + l.ori r3, r1, 0 +#ifdef __OR1K_NODELAY__ + l.ori r4, r0, \num + l.jal z_openrisc_fault +#else + l.jal z_openrisc_fault + l.ori r4, r0, \num +#endif + + /* Halt */ + l.j . +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +.endm + + +/* + * Implements system initialization on reset. + */ + +.macro exception_reset +SECTION_SUBSEC_FUNC(exceptions, _reset_and__start, __reset) +SECTION_SUBSEC_FUNC(exceptions, _reset_and__start, __start) +exception_label 0x1, reset + /* + * Initialize Supervision Register: + * Supervisor mode on, all interrupts off, caches off + */ + l.ori r14, r0, SPR_SR_SM + l.mtspr r0, r14, SPR_SR + + /* Zero all registers */ + zero_regs 1, 31 + +#if defined(CONFIG_SOC_RESET_HOOK) + l.jal soc_reset_hook +#ifndef __OR1K_NODELAY__ + l.nop +#endif +#endif + +#ifdef CONFIG_INIT_STACKS + /* Pre-populate all bytes in z_interrupt_stacks with 0xAA */ + l.movhi r14, hi(z_interrupt_stacks) + l.ori r14, r14, lo(z_interrupt_stacks) + l.addi r16, r14, __z_interrupt_all_stacks_SIZEOF + + l.movhi r16, 0xAAAA + l.ori r16, r16, 0xAAAA + +aa_loop: + l.sw 0(r14), r16 + l.addi r14, r14, 4 + l.sfltu r14, r16 + l.bf aa_loop +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +#endif /* CONFIG_INIT_STACKS */ + + /* Setup stack pointer. */ + l.movhi r1, hi(__stack) + l.ori r1, r1, lo(__stack) + + /* Set frame pointer */ + l.ori r2, r1, 0 + + /* Jump into C domain. */ + l.j z_prep_c +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +.endm + + +/* + * Handles exception errors + */ + +.macro exception_error num, label +exception_label \num, \label + exception_handler_head + error_handler_tail \num +.endm + + +/* + * Handles Tick Timer Exception. + * + * Saves register state, then implements tick-timer handling functionality + * then hands off to _isr_tail to implemented shared tail functionality. + */ + +.macro exception_tick_timer +exception_label 0x5, tick_timer + isr_head + + /* Handle the tick timer and jump to _isr_tail on return. */ + chain_call z_openrisc_timer_isr, _isr_tail +.endm + + +/* + * Handles External Interrupt Exception. + * + * Saves register state, then implements interrupt handling functionality + * then hands off to _isr_tail to implemented shared tail functionality. + */ + +.macro exception_external_interrupt +exception_label 0x8, external_interrupt + isr_head + + /* Call to z_openrisc_handle_irqs and return to _isr_tail. */ + chain_call z_openrisc_handle_irqs, _isr_tail +.endm + + +/* + * Handles syscalls + */ + +.macro exception_syscall +exception_label 0xC, syscall + exception_handler_head + +#ifdef CONFIG_IRQ_OFFLOAD + /* Determine what to do. Operation code is in r11 */ + l.sfeqi r11, OR_SYSCALL_IRQ_OFFLOAD + l.bf do_irq_offload +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +#endif + + error_handler_tail 0xC + +#ifdef CONFIG_IRQ_OFFLOAD +do_irq_offload: + setup_irq_stack + + /* Save r9 on the stack */ + push_r9 + + /* + * Save r9, invoke the offload handler and jump to _isr_tail on + * return. + */ + l.ori r15, r3, 0 + l.ori r3, r4, 0 + chain_call_reg r15, _isr_tail + +#endif +.endm + + +SECTION_FUNC(exceptions, _exceptions) + +/* Reset */ +exception_reset + +/* Bus Error */ +exception_error 0x2, bus_error + +/* Data Page Fault */ +exception_error 0x3, data_page_fault + +/* Instruction Page Fault */ +exception_error 0x4, instruction_page_fault + +/* Tick Timer */ +exception_tick_timer + +/* Alignment Exception */ +exception_error 0x6, alignment_exception + +/* Illegal Instruction */ +exception_error 0x7, illegal_instruction + +/* External Interrupt */ +exception_external_interrupt + +/* Data TLB Miss */ +exception_error 0x9, dtlb_miss + +/* Instruction TLB Miss */ +exception_error 0xA, itlb_miss + +/* Range Exception */ +exception_error 0xB, range_exception + +/* System Call */ +exception_syscall + +/* Floating Point Exception */ +exception_error 0xD, floating_point_exception + +/* Trap */ +exception_error 0xE, trap_exception + + +/* + * Common interrupt handler tail routine. + * + * This routing implements common interrupt handler tail behaviour, shared + * between the tick timer and external exceptions and exits out of exception + * context when complete. + */ + +SECTION_FUNC(exceptions, _isr_tail) + /* Get the cpu_t pointer */ + get_current_cpu r15 + + /* Decrement the nested IRQ count */ + update_nested_count r15, r17, -1 + + /* If the nested count is back to zero, restore the thread stack */ + l.sfnei r17, 0 + l.bf retain_irq_stack +#ifndef __OR1K_NODELAY__ + l.nop +#endif + + /* Restore r9 */ + pop_r9 + + /* Restore stack pointer */ + l.lwz r1, 0(r1) + +retain_irq_stack: + /* Save temporary registers */ +#if defined(CONFIG_MULTITHREADING) + l.addi r1, r1, -8 + l.sw 0(r1), r9 + l.sw 4(r1), r14 +#elif defined(CONFIG_STACK_SENTINEL) + l.addi r1, r1, -4 + l.sw 0(r1), r9 +#endif + +#ifdef CONFIG_STACK_SENTINEL + l.jal z_check_stack_sentinel +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +#endif + +check_reschedule: + /* + * Load the address of the current k_thread from the current cpu_t for use by + * z_openrisc_switch + */ + get_current_cpu r15 + l.lwz r14, ___cpu_t_current_OFFSET(r15) + +#ifdef CONFIG_MULTITHREADING + /* Call z_get_next_switch_handle(NULL) */ +#ifdef __OR1K_NODELAY__ + l.ori r3, r0, 0 + l.jal z_get_next_switch_handle +#else + l.jal z_get_next_switch_handle + l.ori r3, r0, 0 +#endif + + /* If the return handle was NULL, exit the ISR without rescheduling */ + l.sfeqi r11, 0 + l.bf no_reschedule +#ifndef __OR1K_NODELAY__ + l.nop +#endif + +reschedule: + /* + * If the handle was not NULL, call + * z_openrisc_context_switch(handle, prev_thread). + * where esf is currently pointed to by the stack pointer. + */ + l.ori r3, r11, 0 +#ifdef __OR1K_NODELAY__ + l.ori r4, r14, 0 + l.jal z_openrisc_switch +#else + l.jal z_openrisc_switch + l.ori r4, r14, 0 +#endif + +no_reschedule: + +#endif + + /* Restore temporary registers */ +#if defined(CONFIG_MULTITHREADING) + l.lwz r9, 0(r1) + l.lwz r14, 4(r1) + l.addi r1, r1, 8 +#elif defined(CONFIG_STACK_SENTINEL) + l.lwz r9, 0(r1) + l.addi r1, r1, 4 +#endif + +SECTION_FUNC(exceptions, z_openrisc_thread_start) + /* Reload caller-saved, exception and MAC registers */ + load_caller_saved + load_mac + load_esr_epcr + + /* Restore stack pointer */ + l.addi r1, r1, lo(__struct_arch_esf_SIZEOF) + + /* Return from exception */ + l.rfe diff --git a/arch/openrisc/core/fatal.c b/arch/openrisc/core/fatal.c new file mode 100644 index 000000000000..5b8921384d36 --- /dev/null +++ b/arch/openrisc/core/fatal.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +FUNC_NORETURN void z_openrisc_fatal_error(unsigned int reason, + const struct arch_esf *esf) +{ +#ifdef CONFIG_EXCEPTION_DEBUG + if (esf != NULL) { + LOG_ERR("epcr: 0x%08x esr: 0x%08x", esf->epcr, esf->esr); + LOG_ERR(" r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x", + esf->r3, esf->r4, esf->r5, esf->r6); + LOG_ERR(" r7: 0x%08x r8: 0x%08x", + esf->r7, esf->r8); + LOG_ERR(" r11: 0x%08x r12: 0x%08x", + esf->r11, esf->r12); + LOG_ERR(" r13: 0x%08x r15: 0x%08x r17: 0x%08x r19: 0x%08x", + esf->r13, esf->r15, esf->r17, esf->r19); + LOG_ERR(" r21: 0x%08x r23: 0x%08x r25: 0x%08x r27: 0x%08x", + esf->r21, esf->r23, esf->r25, esf->r27); + LOG_ERR(" r29: 0x%08x r31: 0x%08x", + esf->r29, esf->r31); + } +#endif /* CONFIG_EXCEPTION_DEBUG */ + z_fatal_error(reason, esf); + CODE_UNREACHABLE; +} + +static char *reason_str(unsigned int reason) +{ + switch (reason) { + case 0x2: + return "Bus Error"; + case 0x3: + return "Data Page Fault"; + case 0x4: + return "Instruction Page Fault"; + case 0x5: + return "Tick Timer"; + case 0x6: + return "Alignment Exception"; + case 0x7: + return "Illegal Instruction"; + case 0x8: + return "External Interrupt"; + case 0x9: + return "D-TLB Miss"; + case 0xA: + return "I-TLB Miss"; + case 0xB: + return "Range Exception"; + case 0xC: + return "Syscall"; + case 0xD: + return "Floating Point Exception"; + case 0xE: + return "Trap"; + default: + return "unknown"; + } +} + +void z_openrisc_fault(struct arch_esf *esf, unsigned int reason) +{ + LOG_ERR(""); + LOG_ERR(" reason: %d, %s", reason, reason_str(reason)); + + z_openrisc_fatal_error(K_ERR_CPU_EXCEPTION, esf); +} diff --git a/arch/openrisc/core/irq_manage.c b/arch/openrisc/core/irq_manage.c new file mode 100644 index 000000000000..71ba1c6522e0 --- /dev/null +++ b/arch/openrisc/core/irq_manage.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + + +FUNC_NORETURN void z_irq_spurious(const void *unused) +{ + ARG_UNUSED(unused); + + LOG_ERR("Spurious interrupt detected!"); + + z_openrisc_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); +} + +void arch_irq_enable(unsigned int irq) +{ + const unsigned int key = irq_lock(); + + openrisc_write_spr(SPR_PICMR, openrisc_read_spr(SPR_PICMR) | BIT(irq)); + irq_unlock(key); +} + +void arch_irq_disable(unsigned int irq) +{ + const unsigned int key = irq_lock(); + + openrisc_write_spr(SPR_PICMR, openrisc_read_spr(SPR_PICMR) & ~BIT(irq)); + irq_unlock(key); +}; + +int arch_irq_is_enabled(unsigned int irq) +{ + return (openrisc_read_spr(SPR_PICMR) & BIT(irq)) != 0; +} + +static ALWAYS_INLINE void enter_irq(unsigned int irq) +{ + if (IS_ENABLED(CONFIG_TRACING_ISR)) { + sys_trace_isr_enter(); + } + + const struct _isr_table_entry *const ite = _sw_isr_table + irq; + + ite->isr(ite->arg); + + if (IS_ENABLED(CONFIG_TRACING_ISR)) { + sys_trace_isr_exit(); + } +} + +void z_openrisc_enter_irq(unsigned int irq) +{ + enter_irq(irq); +} + +void z_openrisc_handle_irqs(void) +{ + uint32_t picsr; + + /* Interatively process every interrupt flag */ + while ((picsr = openrisc_read_spr(SPR_PICSR))) { + enter_irq(find_lsb_set(picsr) - 1); + } +} + +#ifdef CONFIG_DYNAMIC_INTERRUPTS +int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, uint32_t flags) +{ + ARG_UNUSED(flags); + ARG_UNUSED(priority); + + z_isr_install(irq, routine, parameter); + return irq; +} +#endif /* CONFIG_DYNAMIC_INTERRUPTS */ diff --git a/arch/openrisc/core/irq_offload.c b/arch/openrisc/core/irq_offload.c new file mode 100644 index 000000000000..d98aceee4482 --- /dev/null +++ b/arch/openrisc/core/irq_offload.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) +{ + arch_syscall_invoke2((uintptr_t)routine, (uintptr_t)parameter, OR_SYSCALL_IRQ_OFFLOAD); +} + +void arch_irq_offload_init(void) +{ +} diff --git a/arch/openrisc/core/offsets/offsets.c b/arch/openrisc/core/offsets/offsets.c new file mode 100644 index 000000000000..342c3b107511 --- /dev/null +++ b/arch/openrisc/core/offsets/offsets.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief OpenRISC kernel structure member offset definition file + * + * This module is responsible for the generation of the absolute symbols whose + * value represents the member offsets for various OpenRISC kernel structures. + */ + +#include +#include +#include + +GEN_OFFSET_SYM(_callee_saved_t, r1); +GEN_OFFSET_SYM(_callee_saved_t, r2); +GEN_OFFSET_SYM(_callee_saved_t, r9); +GEN_OFFSET_SYM(_callee_saved_t, r10); +GEN_OFFSET_SYM(_callee_saved_t, r14); +GEN_OFFSET_SYM(_callee_saved_t, r16); +GEN_OFFSET_SYM(_callee_saved_t, r18); +GEN_OFFSET_SYM(_callee_saved_t, r20); +GEN_OFFSET_SYM(_callee_saved_t, r22); +GEN_OFFSET_SYM(_callee_saved_t, r24); +GEN_OFFSET_SYM(_callee_saved_t, r26); +GEN_OFFSET_SYM(_callee_saved_t, r28); +GEN_OFFSET_SYM(_callee_saved_t, r30); + +GEN_ABSOLUTE_SYM(_callee_saved_t_SIZEOF, sizeof(_callee_saved_t)); + +GEN_OFFSET_STRUCT(arch_esf, r3); +GEN_OFFSET_STRUCT(arch_esf, r4); +GEN_OFFSET_STRUCT(arch_esf, r5); +GEN_OFFSET_STRUCT(arch_esf, r6); +GEN_OFFSET_STRUCT(arch_esf, r7); +GEN_OFFSET_STRUCT(arch_esf, r8); +GEN_OFFSET_STRUCT(arch_esf, r11); +GEN_OFFSET_STRUCT(arch_esf, r12); +GEN_OFFSET_STRUCT(arch_esf, r13); +GEN_OFFSET_STRUCT(arch_esf, r15); +GEN_OFFSET_STRUCT(arch_esf, r17); +GEN_OFFSET_STRUCT(arch_esf, r19); +GEN_OFFSET_STRUCT(arch_esf, r21); +GEN_OFFSET_STRUCT(arch_esf, r23); +GEN_OFFSET_STRUCT(arch_esf, r25); +GEN_OFFSET_STRUCT(arch_esf, r27); +GEN_OFFSET_STRUCT(arch_esf, r29); +GEN_OFFSET_STRUCT(arch_esf, r31); +GEN_OFFSET_STRUCT(arch_esf, mac_lo); +GEN_OFFSET_STRUCT(arch_esf, mac_hi); +GEN_OFFSET_STRUCT(arch_esf, epcr); +GEN_OFFSET_STRUCT(arch_esf, esr); + +GEN_ABSOLUTE_SYM(__struct_arch_esf_SIZEOF, sizeof(struct arch_esf)); + +GEN_ABS_SYM_END diff --git a/arch/openrisc/core/prep_c.c b/arch/openrisc/core/prep_c.c new file mode 100644 index 000000000000..4bf9a2c4ada8 --- /dev/null +++ b/arch/openrisc/core/prep_c.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Full C support initialization + */ + +#include +#include +#include + +/** + * + * @brief Prepare to and run C code + * + * This routine prepares for the execution of and runs C code. + * + * @return N/A + */ + +void z_prep_c(void) +{ +#if defined(CONFIG_SOC_PREP_HOOK) + soc_prep_hook(); +#endif + z_bss_zero(); + z_data_copy(); + +#if CONFIG_ARCH_CACHE + arch_cache_init(); +#endif + z_cstart(); + CODE_UNREACHABLE; +} diff --git a/arch/openrisc/core/reboot.c b/arch/openrisc/core/reboot.c new file mode 100644 index 000000000000..af4d287ddb7d --- /dev/null +++ b/arch/openrisc/core/reboot.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief OpenRISC reboot interface + */ + +#include +#include +#include + +/** + * @brief Reset the system + * + * This is stub function to avoid build error with CONFIG_REBOOT=y + * OpenRISC specification does not have a common interface for system reset. + * Each OpenRISC SoC that has reset feature should implement own reset function. + */ + +void __weak sys_arch_reboot(int type) +{ + ARG_UNUSED(type); + + __asm__("l.nop 13"); +} diff --git a/arch/openrisc/core/switch.S b/arch/openrisc/core/switch.S new file mode 100644 index 000000000000..796efd3caba7 --- /dev/null +++ b/arch/openrisc/core/switch.S @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "asm_macros.inc" + +#define THREAD_O(FIELD) _thread_offset_to_##FIELD + +.macro do_callee_saved op, reg + \op r2, THREAD_O(r2), \reg + \op r9, THREAD_O(r9), \reg + \op r10, THREAD_O(r10), \reg + \op r14, THREAD_O(r14), \reg + \op r16, THREAD_O(r16), \reg + \op r18, THREAD_O(r18), \reg + \op r20, THREAD_O(r20), \reg + \op r22, THREAD_O(r22), \reg + \op r24, THREAD_O(r24), \reg + \op r26, THREAD_O(r26), \reg + \op r28, THREAD_O(r28), \reg + \op r30, THREAD_O(r30), \reg +.endm + +.macro store_callee_saved reg + do_callee_saved op_store_reg, \reg +.endm + +.macro load_callee_saved reg + do_callee_saved op_load_reg, \reg +.endm + +GTEXT(z_openrisc_switch) + +/* void z_openrisc_switch(k_thread_t *switch_to, k_thread_t *switch_from) */ +SECTION_FUNC(TEXT, z_openrisc_switch) + + /* Save the old thread's callee-saved registers */ + store_callee_saved r4 + + /* Save the old thread's stack pointer */ + l.sw _thread_offset_to_r1(r4), r1 + + /* Set thread->switch_handle = thread to mark completion */ + l.sw ___thread_t_switch_handle_OFFSET(r4), r4 + + /* Get the new thread's stack pointer */ + l.lwz r1, _thread_offset_to_r1(r3) + +#if CONFIG_INSTRUMENT_THREAD_SWITCHING + /* Save r3 to r14, then restore it after use */ +#ifdef __OR1K_NODELAY__ + l.ori r14, r3, 0 + l.jal z_thread_mark_switched_in +#else + l.jal z_thread_mark_switched_in + l.ori r14, r3, 0 +#endif + l.ori r3, r14, 0 +#endif + + /* Restore the new thread's callee-saved registers */ + load_callee_saved r3 + + /* Return to arch_switch() or _irq_wrapper() */ + l.jr r9 +#ifndef __OR1K_NODELAY__ + l.nop +#endif diff --git a/arch/openrisc/core/thread.c b/arch/openrisc/core/thread.c new file mode 100644 index 000000000000..3b495380963f --- /dev/null +++ b/arch/openrisc/core/thread.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +void z_thread_entry(k_thread_entry_t thread, + void *arg1, + void *arg2, + void *arg3); + +void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, + char *stack_ptr, k_thread_entry_t entry, + void *p1, void *p2, void *p3) +{ + extern void z_openrisc_thread_start(void); + + /* Initial stack frame for thread */ + struct arch_esf *const stack_init = (struct arch_esf *)Z_STACK_PTR_ALIGN( + Z_STACK_PTR_TO_FRAME(struct arch_esf, stack_ptr)); + + /* Setup the initial stack frame */ + stack_init->r3 = (uint32_t)entry; + stack_init->r4 = (uint32_t)p1; + stack_init->r5 = (uint32_t)p2; + stack_init->r6 = (uint32_t)p3; + + stack_init->epcr = (uint32_t)z_thread_entry; + + stack_init->esr = SPR_SR_SM | SPR_SR_IEE | SPR_SR_TEE +#ifdef CONFIG_DCACHE + | SPR_SR_DCE +#endif +#ifdef CONFIG_ICACHE + | SPR_SR_ICE +#endif + ; + + thread->callee_saved.r1 = (uint32_t)stack_init; + + /* where to go when returning from z_openrisc_switch() */ + thread->callee_saved.r9 = (uint32_t)z_openrisc_thread_start; + + /* our switch handle is the thread pointer itself */ + thread->switch_handle = thread; +} diff --git a/arch/openrisc/include/kernel_arch_data.h b/arch/openrisc/include/kernel_arch_data.h new file mode 100644 index 000000000000..a755fb772916 --- /dev/null +++ b/arch/openrisc/include/kernel_arch_data.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private kernel definitions + * + * This file contains private kernel structures definitions and various + * other definitions for the OpenRISC processor architecture. + */ + +#ifndef ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_DATA_H_ +#define ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_DATA_H_ + +#include +#include +#include + +#ifndef _ASMLANGUAGE +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_DATA_H_ */ diff --git a/arch/openrisc/include/kernel_arch_func.h b/arch/openrisc/include/kernel_arch_func.h new file mode 100644 index 000000000000..c84e49328824 --- /dev/null +++ b/arch/openrisc/include/kernel_arch_func.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private kernel definitions + * + * This file contains private kernel function/macro definitions and various + * other definitions for the OpenRISC processor architecture. + */ + +#ifndef ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_FUNC_H_ +#define ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_FUNC_H_ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE +static ALWAYS_INLINE void arch_kernel_init(void) +{ +#ifdef CONFIG_SOC_PER_CORE_INIT_HOOK + soc_per_core_init_hook(); +#endif /* CONFIG_SOC_PER_CORE_INIT_HOOK */ +} + +static ALWAYS_INLINE void +arch_switch(void *switch_to, void **switched_from) +{ + extern void z_openrisc_switch(struct k_thread *new, struct k_thread *old); + struct k_thread *new = switch_to; + struct k_thread *old = CONTAINER_OF(switched_from, struct k_thread, + switch_handle); + z_openrisc_switch(new, old); +} + +FUNC_NORETURN void z_openrisc_fatal_error(unsigned int reason, + const struct arch_esf *esf); + +static inline bool arch_is_in_isr(void) +{ + return _current_cpu->nested != 0U; +} + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_ARCH_OPENRISC_INCLUDE_KERNEL_ARCH_FUNC_H_ */ diff --git a/arch/openrisc/include/offsets_short_arch.h b/arch/openrisc/include/offsets_short_arch.h new file mode 100644 index 000000000000..b1cfd00f4031 --- /dev/null +++ b/arch/openrisc/include/offsets_short_arch.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_OPENRISC_INCLUDE_OFFSETS_SHORT_ARCH_H_ +#define ZEPHYR_ARCH_OPENRISC_INCLUDE_OFFSETS_SHORT_ARCH_H_ + +#include + +#define _thread_offset_to_r1 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r1_OFFSET) + +#define _thread_offset_to_r2 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r2_OFFSET) + +#define _thread_offset_to_r9 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r9_OFFSET) + +#define _thread_offset_to_r10 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r10_OFFSET) + +#define _thread_offset_to_r14 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r14_OFFSET) + +#define _thread_offset_to_r16 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r16_OFFSET) + +#define _thread_offset_to_r18 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r18_OFFSET) + +#define _thread_offset_to_r20 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r20_OFFSET) + +#define _thread_offset_to_r22 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r22_OFFSET) + +#define _thread_offset_to_r24 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r24_OFFSET) + +#define _thread_offset_to_r26 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r26_OFFSET) + +#define _thread_offset_to_r28 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r28_OFFSET) + +#define _thread_offset_to_r30 \ + (___thread_t_callee_saved_OFFSET + ___callee_saved_t_r30_OFFSET) + +#endif /* ZEPHYR_ARCH_OPENRISC_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ diff --git a/arch/openrisc/include/openrisc/openriscregs.h b/arch/openrisc/include/openrisc/openriscregs.h new file mode 100644 index 000000000000..c83a8090e759 --- /dev/null +++ b/arch/openrisc/include/openrisc/openriscregs.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * Macros for OpenRISC SPR manipulations + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_OPENRISCREGS_H_ +#define _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_OPENRISCREGS_H_ + +#include + +#define openrisc_write_spr(spr, val) \ +({ \ + __asm__ __volatile__ ("l.mtspr r0,%0,%1" \ + : \ + : "r" (val), "K" (spr)); \ +}) + +#define openrisc_read_spr(spr) \ +({ \ + uint32_t val; \ + __asm__ __volatile__ ("l.mfspr %0,r0,%1" \ + : "=r" (val) \ + : "K" (spr)); \ + val; \ +}) + +#endif /* _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_OPENRISCREGS_H_ */ diff --git a/arch/openrisc/include/openrisc/spr_defs.h b/arch/openrisc/include/openrisc/spr_defs.h new file mode 100644 index 000000000000..662aaf76d445 --- /dev/null +++ b/arch/openrisc/include/openrisc/spr_defs.h @@ -0,0 +1,667 @@ +/* + * SPR Definitions + * + * Copyright (C) 2000 Damjan Lampret + * Copyright (C) 2003 Matjaz Breskvar + * Copyright (C) 2008, 2010 Embecosm Limited + * Copyright (C) 2010-2011 Jonas Bonn + * Copyright (c) 2025 NVIDIA Corporation + * + * This file is part of OpenRISC 1000 Architectural Simulator. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_SPR_DEFS_H_ +#define _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_SPR_DEFS_H_ + +/* Definition of special-purpose registers (SPRs). */ +#define MAX_GRPS (32) +#define MAX_SPRS_PER_GRP_BITS (11) +#define MAX_SPRS_PER_GRP (1 << MAX_SPRS_PER_GRP_BITS) +#define MAX_SPRS (0x10000) + +/* Base addresses for the groups */ +#define SPRGROUP_SYS (0 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_DMMU (1 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_IMMU (2 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_DC (3 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_IC (4 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_MAC (5 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_D (6 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PC (7 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PM (8 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PIC (9 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_TT (10 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_FP (11 << MAX_SPRS_PER_GRP_BITS) + +/* System control and status group */ +#define SPR_VR (SPRGROUP_SYS + 0) +#define SPR_UPR (SPRGROUP_SYS + 1) +#define SPR_CPUCFGR (SPRGROUP_SYS + 2) +#define SPR_DMMUCFGR (SPRGROUP_SYS + 3) +#define SPR_IMMUCFGR (SPRGROUP_SYS + 4) +#define SPR_DCCFGR (SPRGROUP_SYS + 5) +#define SPR_ICCFGR (SPRGROUP_SYS + 6) +#define SPR_DCFGR (SPRGROUP_SYS + 7) +#define SPR_PCCFGR (SPRGROUP_SYS + 8) +#define SPR_VR2 (SPRGROUP_SYS + 9) +#define SPR_AVR (SPRGROUP_SYS + 10) +#define SPR_EVBAR (SPRGROUP_SYS + 11) +#define SPR_AECR (SPRGROUP_SYS + 12) +#define SPR_AESR (SPRGROUP_SYS + 13) +#define SPR_NPC (SPRGROUP_SYS + 16) +#define SPR_SR (SPRGROUP_SYS + 17) +#define SPR_PPC (SPRGROUP_SYS + 18) +#define SPR_FPCSR (SPRGROUP_SYS + 20) +#define SPR_ISR_BASE (SPRGROUP_SYS + 21) +#define SPR_ISR_LAST (SRPGROUP_SYS + 28) +#define SPR_EPCR_BASE (SPRGROUP_SYS + 32) +#define SPR_EPCR_LAST (SPRGROUP_SYS + 47) +#define SPR_EEAR_BASE (SPRGROUP_SYS + 48) +#define SPR_EEAR_LAST (SPRGROUP_SYS + 63) +#define SPR_ESR_BASE (SPRGROUP_SYS + 64) +#define SPR_ESR_LAST (SPRGROUP_SYS + 79) +#define SPR_COREID (SPRGROUP_SYS + 128) +#define SPR_NUMCORES (SPRGROUP_SYS + 129) +#define SPR_GPR_BASE (SPRGROUP_SYS + 1024) + +/* Data MMU group */ +#define SPR_DMMUCR (SPRGROUP_DMMU + 0) +#define SPR_DMMUPR (SPRGROUP_DMMU + 1) +#define SPR_DTLBEIR (SPRGROUP_DMMU + 2) +#define SPR_DTLBMR_BASE(WAY) (SPRGROUP_DMMU + 0x200 + (WAY) * 0x100) +#define SPR_DTLBMR_LAST(WAY) (SPRGROUP_DMMU + 0x27f + (WAY) * 0x100) +#define SPR_DTLBTR_BASE(WAY) (SPRGROUP_DMMU + 0x280 + (WAY) * 0x100) +#define SPR_DTLBTR_LAST(WAY) (SPRGROUP_DMMU + 0x2ff + (WAY) * 0x100) + +/* Instruction MMU group */ +#define SPR_IMMUCR (SPRGROUP_IMMU + 0) +#define SPR_IMMUPR (SPRGROUP_IMMU + 1) +#define SPR_ITLBEIR (SPRGROUP_IMMU + 2) +#define SPR_ITLBMR_BASE(WAY) (SPRGROUP_IMMU + 0x200 + (WAY) * 0x100) +#define SPR_ITLBMR_LAST(WAY) (SPRGROUP_IMMU + 0x27f + (WAY) * 0x100) +#define SPR_ITLBTR_BASE(WAY) (SPRGROUP_IMMU + 0x280 + (WAY) * 0x100) +#define SPR_ITLBTR_LAST(WAY) (SPRGROUP_IMMU + 0x2ff + (WAY) * 0x100) + +/* Data cache group */ +#define SPR_DCCR (SPRGROUP_DC + 0) +#define SPR_DCBPR (SPRGROUP_DC + 1) +#define SPR_DCBFR (SPRGROUP_DC + 2) +#define SPR_DCBIR (SPRGROUP_DC + 3) +#define SPR_DCBWR (SPRGROUP_DC + 4) +#define SPR_DCBLR (SPRGROUP_DC + 5) +#define SPR_DCR_BASE(WAY) (SPRGROUP_DC + 0x200 + (WAY) * 0x200) +#define SPR_DCR_LAST(WAY) (SPRGROUP_DC + 0x3ff + (WAY) * 0x200) + +/* Instruction cache group */ +#define SPR_ICCR (SPRGROUP_IC + 0) +#define SPR_ICBPR (SPRGROUP_IC + 1) +#define SPR_ICBIR (SPRGROUP_IC + 2) +#define SPR_ICBLR (SPRGROUP_IC + 3) +#define SPR_ICR_BASE(WAY) (SPRGROUP_IC + 0x200 + (WAY) * 0x200) +#define SPR_ICR_LAST(WAY) (SPRGROUP_IC + 0x3ff + (WAY) * 0x200) + +/* MAC group */ +#define SPR_MACLO (SPRGROUP_MAC + 1) +#define SPR_MACHI (SPRGROUP_MAC + 2) + +/* Debug group */ +#define SPR_DVR(N) (SPRGROUP_D + (N)) +#define SPR_DCR(N) (SPRGROUP_D + 8 + (N)) +#define SPR_DMR1 (SPRGROUP_D + 16) +#define SPR_DMR2 (SPRGROUP_D + 17) +#define SPR_DWCR0 (SPRGROUP_D + 18) +#define SPR_DWCR1 (SPRGROUP_D + 19) +#define SPR_DSR (SPRGROUP_D + 20) +#define SPR_DRR (SPRGROUP_D + 21) + +/* Performance counters group */ +#define SPR_PCCR(N) (SPRGROUP_PC + (N)) +#define SPR_PCMR(N) (SPRGROUP_PC + 8 + (N)) + +/* Power management group */ +#define SPR_PMR (SPRGROUP_PM + 0) + +/* PIC group */ +#define SPR_PICMR (SPRGROUP_PIC + 0) +#define SPR_PICPR (SPRGROUP_PIC + 1) +#define SPR_PICSR (SPRGROUP_PIC + 2) + +/* Tick Timer group */ +#define SPR_TTMR (SPRGROUP_TT + 0) +#define SPR_TTCR (SPRGROUP_TT + 1) + +/* + * Bit definitions for the Version Register + */ + +#define SPR_VR_VER 0xff000000 /* Processor version */ +#define SPR_VR_CFG 0x00ff0000 /* Processor configuration */ +#define SPR_VR_RES 0x0000ffc0 /* Reserved */ +#define SPR_VR_REV 0x0000003f /* Processor revision */ +#define SPR_VR_UVRP 0x00000040 /* Updated Version Registers Present */ + +#define SPR_VR_VER_OFF 24 +#define SPR_VR_CFG_OFF 16 +#define SPR_VR_REV_OFF 0 + +/* + * Bit definitions for the Version Register 2 + */ + +#define SPR_VR2_CPUID 0xff000000 /* Processor ID */ +#define SPR_VR2_VER 0x00ffffff /* Processor version */ + +/* + * Bit definitions for the Unit Present Register + */ + +#define SPR_UPR_UP 0x00000001 /* UPR present */ +#define SPR_UPR_DCP 0x00000002 /* Data cache present */ +#define SPR_UPR_ICP 0x00000004 /* Instruction cache present */ +#define SPR_UPR_DMP 0x00000008 /* Data MMU present */ +#define SPR_UPR_IMP 0x00000010 /* Instruction MMU present */ +#define SPR_UPR_MP 0x00000020 /* MAC present */ +#define SPR_UPR_DUP 0x00000040 /* Debug unit present */ +#define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */ +#define SPR_UPR_PMP 0x00000100 /* Power management present */ +#define SPR_UPR_PICP 0x00000200 /* PIC present */ +#define SPR_UPR_TTP 0x00000400 /* Tick timer present */ +#define SPR_UPR_RES 0x00fe0000 /* Reserved */ +#define SPR_UPR_CUP 0xff000000 /* Context units present */ + +/* + * JPB: Bit definitions for the CPU configuration register + */ + +#define SPR_CPUCFGR_NSGF 0x0000000f /* Number of shadow GPR files */ +#define SPR_CPUCFGR_CGF 0x00000010 /* Custom GPR file */ +#define SPR_CPUCFGR_OB32S 0x00000020 /* ORBIS32 supported */ +#define SPR_CPUCFGR_OB64S 0x00000040 /* ORBIS64 supported */ +#define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */ +#define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */ +#define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */ +#define SPR_CPUCFGR_ND 0x00000400 /* No delay slots */ +#define SPR_CPUCFGR_AVRP 0x00000800 /* Architecture Version Register (AVR) Present */ +#define SPR_CPUCFGR_EVBARP 0x00001000 /* Exception Vector Base Address Register Present */ +#define SPR_CPUCFGR_ISRP 0x00002000 /* Implementation-Specific Registers (ISR0-7) Present */ +#define SPR_CPUCFGR_AECSRP 0x00004000 /* Arithmetic Exception Control/Status Registers + * (ARCR/AESR) Present + */ +#define SPR_CPUCFGR_RES 0xffff8000 /* Reserved */ + +/* + * JPB: Bit definitions for the Debug configuration register and other + * constants. + */ + +#define SPR_DCFGR_NDP 0x00000007 /* Number of matchpoints mask */ +#define SPR_DCFGR_NDP1 0x00000000 /* One matchpoint supported */ +#define SPR_DCFGR_NDP2 0x00000001 /* Two matchpoints supported */ +#define SPR_DCFGR_NDP3 0x00000002 /* Three matchpoints supported */ +#define SPR_DCFGR_NDP4 0x00000003 /* Four matchpoints supported */ +#define SPR_DCFGR_NDP5 0x00000004 /* Five matchpoints supported */ +#define SPR_DCFGR_NDP6 0x00000005 /* Six matchpoints supported */ +#define SPR_DCFGR_NDP7 0x00000006 /* Seven matchpoints supported */ +#define SPR_DCFGR_NDP8 0x00000007 /* Eight matchpoints supported */ +#define SPR_DCFGR_WPCI 0x00000008 /* Watchpoint counters implemented */ + +#define MATCHPOINTS_TO_NDP(n) (1 == n ? SPR_DCFGR_NDP1 : \ + 2 == n ? SPR_DCFGR_NDP2 : \ + 3 == n ? SPR_DCFGR_NDP3 : \ + 4 == n ? SPR_DCFGR_NDP4 : \ + 5 == n ? SPR_DCFGR_NDP5 : \ + 6 == n ? SPR_DCFGR_NDP6 : \ + 7 == n ? SPR_DCFGR_NDP7 : SPR_DCFGR_NDP8) +#define MAX_MATCHPOINTS 8 +#define MAX_WATCHPOINTS (MAX_MATCHPOINTS + 2) + +/* + * Bit definitions for Version Register 2 + */ + +#define SPR_VR2_CPUID 0xff000000 /* CPU Identification number */ +#define SPR_VR2_VER 0x00ffffff /* Version */ + +/* + * Bit definitions for Architecture Version Register + */ + +#define SPR_AVR_RES 0x000000ff /* Reserved */ +#define SPR_AVR_REV 0x0000ff00 /* Architecture Revision Number */ +#define SPR_AVR_MIN 0x00ff0000 /* Minor Architecture Version Number */ +#define SPR_AVR_MAJ 0xff000000 /* Major Architecture Version Number */ + +/* + * Bit definitions for Exception Vector Base Address Register + */ + +#define SPR_EVBAR_RES 0x00001fff /* Reserved */ +#define SPR_EVBAR_EVBA 0xffffe000 /* Exception Vector Base Address */ + +/* + * Bit definitions for the Arithmetic Exception Control Register + */ + +#define SPR_AECR_CYADDE 0x00000001 /* unsigned overflow in add */ +#define SPR_AECR_OVADDE 0x00000002 /* signed overflow in add */ +#define SPR_AECR_CYMULE 0x00000004 /* unsigned overflow in mul */ +#define SPR_AECR_OVMULE 0x00000008 /* signed overflow in mul */ +#define SPR_AECR_DBZE 0x00000010 /* divide by zero */ +#define SPR_AECR_CYMACADDE 0x00000020 /* unsigned overflow in mac add */ +#define SPR_AECR_OVMACADDE 0x00000040 /* signed overflow in mac add */ + +/* + * Bit definitions for the Arithmetic Exception Status Register + */ + +#define SPR_AESR_CYADDE 0x00000001 /* unsigned overflow in add */ +#define SPR_AESR_OVADDE 0x00000002 /* signed overflow in add */ +#define SPR_AESR_CYMULE 0x00000004 /* unsigned overflow in mul */ +#define SPR_AESR_OVMULE 0x00000008 /* signed overflow in mul */ +#define SPR_AESR_DBZE 0x00000010 /* divide by zero */ +#define SPR_AESR_CYMACADDE 0x00000020 /* unsigned overflow in mac add */ +#define SPR_AESR_OVMACADDE 0x00000040 /* signed overflow in mac add */ + +/* + * Bit definitions for the Supervision Register + */ + +#define SPR_SR_SM 0x00000001 /* Supervisor Mode */ +#define SPR_SR_TEE 0x00000002 /* Tick timer Exception Enable */ +#define SPR_SR_IEE 0x00000004 /* Interrupt Exception Enable */ +#define SPR_SR_DCE 0x00000008 /* Data Cache Enable */ +#define SPR_SR_ICE 0x00000010 /* Instruction Cache Enable */ +#define SPR_SR_DME 0x00000020 /* Data MMU Enable */ +#define SPR_SR_IME 0x00000040 /* Instruction MMU Enable */ +#define SPR_SR_LEE 0x00000080 /* Little Endian Enable */ +#define SPR_SR_CE 0x00000100 /* CID Enable */ +#define SPR_SR_F 0x00000200 /* Condition Flag */ +#define SPR_SR_CY 0x00000400 /* Carry flag */ +#define SPR_SR_OV 0x00000800 /* Overflow flag */ +#define SPR_SR_OVE 0x00001000 /* Overflow flag Exception */ +#define SPR_SR_DSX 0x00002000 /* Delay Slot Exception */ +#define SPR_SR_EPH 0x00004000 /* Exception Prefix High */ +#define SPR_SR_FO 0x00008000 /* Fixed one */ +#define SPR_SR_SUMRA 0x00010000 /* Supervisor SPR read access */ +#define SPR_SR_RES 0x0ffe0000 /* Reserved */ +#define SPR_SR_CID 0xf0000000 /* Context ID */ + +/* + * Bit definitions for the Data MMU Control Register + */ + +#define SPR_DMMUCR_P2S 0x0000003e /* Level 2 Page Size */ +#define SPR_DMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ +#define SPR_DMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ +#define SPR_DMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ + +/* + * Bit definitions for the Instruction MMU Control Register + */ + +#define SPR_IMMUCR_P2S 0x0000003e /* Level 2 Page Size */ +#define SPR_IMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ +#define SPR_IMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ +#define SPR_IMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ + +/* + * Bit definitions for the Data TLB Match Register + */ + +#define SPR_DTLBMR_V 0x00000001 /* Valid */ +#define SPR_DTLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ +#define SPR_DTLBMR_CID 0x0000003c /* Context ID */ +#define SPR_DTLBMR_LRU 0x000000c0 /* Least Recently Used */ +#define SPR_DTLBMR_VPN 0xffffe000 /* Virtual Page Number */ + +/* + * Bit definitions for the Data TLB Translate Register + */ + +#define SPR_DTLBTR_CC 0x00000001 /* Cache Coherency */ +#define SPR_DTLBTR_CI 0x00000002 /* Cache Inhibit */ +#define SPR_DTLBTR_WBC 0x00000004 /* Write-Back Cache */ +#define SPR_DTLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ +#define SPR_DTLBTR_A 0x00000010 /* Accessed */ +#define SPR_DTLBTR_D 0x00000020 /* Dirty */ +#define SPR_DTLBTR_URE 0x00000040 /* User Read Enable */ +#define SPR_DTLBTR_UWE 0x00000080 /* User Write Enable */ +#define SPR_DTLBTR_SRE 0x00000100 /* Supervisor Read Enable */ +#define SPR_DTLBTR_SWE 0x00000200 /* Supervisor Write Enable */ +#define SPR_DTLBTR_PPN 0xffffe000 /* Physical Page Number */ + +/* + * Bit definitions for the Instruction TLB Match Register + */ + +#define SPR_ITLBMR_V 0x00000001 /* Valid */ +#define SPR_ITLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ +#define SPR_ITLBMR_CID 0x0000003c /* Context ID */ +#define SPR_ITLBMR_LRU 0x000000c0 /* Least Recently Used */ +#define SPR_ITLBMR_VPN 0xffffe000 /* Virtual Page Number */ + +/* + * Bit definitions for the Instruction TLB Translate Register + */ + +#define SPR_ITLBTR_CC 0x00000001 /* Cache Coherency */ +#define SPR_ITLBTR_CI 0x00000002 /* Cache Inhibit */ +#define SPR_ITLBTR_WBC 0x00000004 /* Write-Back Cache */ +#define SPR_ITLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ +#define SPR_ITLBTR_A 0x00000010 /* Accessed */ +#define SPR_ITLBTR_D 0x00000020 /* Dirty */ +#define SPR_ITLBTR_SXE 0x00000040 /* User Read Enable */ +#define SPR_ITLBTR_UXE 0x00000080 /* User Write Enable */ +#define SPR_ITLBTR_PPN 0xfffff000 /* Physical Page Number */ + +/* + * Bit definitions for Data Cache Control register + */ + +#define SPR_DCCR_EW 0x000000ff /* Enable ways */ + +/* + * Bit definitions for Insn Cache Control register + */ + +#define SPR_ICCR_EW 0x000000ff /* Enable ways */ + +/* + * Bit definitions for Data Cache Configuration Register + */ + +#define SPR_DCCFGR_NCW 0x00000007 +#define SPR_DCCFGR_NCS 0x00000078 +#define SPR_DCCFGR_CBS 0x00000080 +#define SPR_DCCFGR_CWS 0x00000100 +#define SPR_DCCFGR_CCRI 0x00000200 +#define SPR_DCCFGR_CBIRI 0x00000400 +#define SPR_DCCFGR_CBPRI 0x00000800 +#define SPR_DCCFGR_CBLRI 0x00001000 +#define SPR_DCCFGR_CBFRI 0x00002000 +#define SPR_DCCFGR_CBWBRI 0x00004000 + +#define SPR_DCCFGR_NCW_OFF 0 +#define SPR_DCCFGR_NCS_OFF 3 +#define SPR_DCCFGR_CBS_OFF 7 + +/* + * Bit definitions for Instruction Cache Configuration Register + */ + +#define SPR_ICCFGR_NCW 0x00000007 +#define SPR_ICCFGR_NCS 0x00000078 +#define SPR_ICCFGR_CBS 0x00000080 +#define SPR_ICCFGR_CCRI 0x00000200 +#define SPR_ICCFGR_CBIRI 0x00000400 +#define SPR_ICCFGR_CBPRI 0x00000800 +#define SPR_ICCFGR_CBLRI 0x00001000 + +#define SPR_ICCFGR_NCW_OFF 0 +#define SPR_ICCFGR_NCS_OFF 3 +#define SPR_ICCFGR_CBS_OFF 7 + +/* + * Bit definitions for Data MMU Configuration Register + */ + +#define SPR_DMMUCFGR_NTW 0x00000003 +#define SPR_DMMUCFGR_NTS 0x0000001C +#define SPR_DMMUCFGR_NAE 0x000000E0 +#define SPR_DMMUCFGR_CRI 0x00000100 +#define SPR_DMMUCFGR_PRI 0x00000200 +#define SPR_DMMUCFGR_TEIRI 0x00000400 +#define SPR_DMMUCFGR_HTR 0x00000800 + +#define SPR_DMMUCFGR_NTW_OFF 0 +#define SPR_DMMUCFGR_NTS_OFF 2 + +/* + * Bit definitions for Instruction MMU Configuration Register + */ + +#define SPR_IMMUCFGR_NTW 0x00000003 +#define SPR_IMMUCFGR_NTS 0x0000001C +#define SPR_IMMUCFGR_NAE 0x000000E0 +#define SPR_IMMUCFGR_CRI 0x00000100 +#define SPR_IMMUCFGR_PRI 0x00000200 +#define SPR_IMMUCFGR_TEIRI 0x00000400 +#define SPR_IMMUCFGR_HTR 0x00000800 + +#define SPR_IMMUCFGR_NTW_OFF 0 +#define SPR_IMMUCFGR_NTS_OFF 2 + +/* + * Bit definitions for Debug Control registers + */ + +#define SPR_DCR_DP 0x00000001 /* DVR/DCR present */ +#define SPR_DCR_CC 0x0000000e /* Compare condition */ +#define SPR_DCR_SC 0x00000010 /* Signed compare */ +#define SPR_DCR_CT 0x000000e0 /* Compare to */ + +/* Bit results with SPR_DCR_CC mask */ +#define SPR_DCR_CC_MASKED 0x00000000 +#define SPR_DCR_CC_EQUAL 0x00000002 +#define SPR_DCR_CC_LESS 0x00000004 +#define SPR_DCR_CC_LESSE 0x00000006 +#define SPR_DCR_CC_GREAT 0x00000008 +#define SPR_DCR_CC_GREATE 0x0000000a +#define SPR_DCR_CC_NEQUAL 0x0000000c + +/* Bit results with SPR_DCR_CT mask */ +#define SPR_DCR_CT_DISABLED 0x00000000 +#define SPR_DCR_CT_IFEA 0x00000020 +#define SPR_DCR_CT_LEA 0x00000040 +#define SPR_DCR_CT_SEA 0x00000060 +#define SPR_DCR_CT_LD 0x00000080 +#define SPR_DCR_CT_SD 0x000000a0 +#define SPR_DCR_CT_LSEA 0x000000c0 +#define SPR_DCR_CT_LSD 0x000000e0 + +/* + * Bit definitions for Debug Mode 1 register + */ + +#define SPR_DMR1_CW 0x000fffff /* Chain register pair data */ +#define SPR_DMR1_CW0_AND 0x00000001 +#define SPR_DMR1_CW0_OR 0x00000002 +#define SPR_DMR1_CW0 (SPR_DMR1_CW0_AND | SPR_DMR1_CW0_OR) +#define SPR_DMR1_CW1_AND 0x00000004 +#define SPR_DMR1_CW1_OR 0x00000008 +#define SPR_DMR1_CW1 (SPR_DMR1_CW1_AND | SPR_DMR1_CW1_OR) +#define SPR_DMR1_CW2_AND 0x00000010 +#define SPR_DMR1_CW2_OR 0x00000020 +#define SPR_DMR1_CW2 (SPR_DMR1_CW2_AND | SPR_DMR1_CW2_OR) +#define SPR_DMR1_CW3_AND 0x00000040 +#define SPR_DMR1_CW3_OR 0x00000080 +#define SPR_DMR1_CW3 (SPR_DMR1_CW3_AND | SPR_DMR1_CW3_OR) +#define SPR_DMR1_CW4_AND 0x00000100 +#define SPR_DMR1_CW4_OR 0x00000200 +#define SPR_DMR1_CW4 (SPR_DMR1_CW4_AND | SPR_DMR1_CW4_OR) +#define SPR_DMR1_CW5_AND 0x00000400 +#define SPR_DMR1_CW5_OR 0x00000800 +#define SPR_DMR1_CW5 (SPR_DMR1_CW5_AND | SPR_DMR1_CW5_OR) +#define SPR_DMR1_CW6_AND 0x00001000 +#define SPR_DMR1_CW6_OR 0x00002000 +#define SPR_DMR1_CW6 (SPR_DMR1_CW6_AND | SPR_DMR1_CW6_OR) +#define SPR_DMR1_CW7_AND 0x00004000 +#define SPR_DMR1_CW7_OR 0x00008000 +#define SPR_DMR1_CW7 (SPR_DMR1_CW7_AND | SPR_DMR1_CW7_OR) +#define SPR_DMR1_CW8_AND 0x00010000 +#define SPR_DMR1_CW8_OR 0x00020000 +#define SPR_DMR1_CW8 (SPR_DMR1_CW8_AND | SPR_DMR1_CW8_OR) +#define SPR_DMR1_CW9_AND 0x00040000 +#define SPR_DMR1_CW9_OR 0x00080000 +#define SPR_DMR1_CW9 (SPR_DMR1_CW9_AND | SPR_DMR1_CW9_OR) +#define SPR_DMR1_RES1 0x00300000 /* Reserved */ +#define SPR_DMR1_ST 0x00400000 /* Single-step trace*/ +#define SPR_DMR1_BT 0x00800000 /* Branch trace */ +#define SPR_DMR1_RES2 0xff000000 /* Reserved */ + +/* + * Bit definitions for Debug Mode 2 register. AWTC and WGB corrected by JPB + */ + +#define SPR_DMR2_WCE0 0x00000001 /* Watchpoint counter 0 enable */ +#define SPR_DMR2_WCE1 0x00000002 /* Watchpoint counter 0 enable */ +#define SPR_DMR2_AWTC 0x00000ffc /* Assign watchpoints to counters */ +#define SPR_DMR2_AWTC_OFF 2 /* Bit offset to AWTC field */ +#define SPR_DMR2_WGB 0x003ff000 /* Watchpoints generating breakpoint */ +#define SPR_DMR2_WGB_OFF 12 /* Bit offset to WGB field */ +#define SPR_DMR2_WBS 0xffc00000 /* JPB: Watchpoint status */ +#define SPR_DMR2_WBS_OFF 22 /* Bit offset to WBS field */ + +/* + * Bit definitions for Debug watchpoint counter registers + */ + +#define SPR_DWCR_COUNT 0x0000ffff /* Count */ +#define SPR_DWCR_MATCH 0xffff0000 /* Match */ +#define SPR_DWCR_MATCH_OFF 16 /* Match bit offset */ + +/* + * Bit definitions for Debug stop register + */ + +#define SPR_DSR_RSTE 0x00000001 /* Reset exception */ +#define SPR_DSR_BUSEE 0x00000002 /* Bus error exception */ +#define SPR_DSR_DPFE 0x00000004 /* Data Page Fault exception */ +#define SPR_DSR_IPFE 0x00000008 /* Insn Page Fault exception */ +#define SPR_DSR_TTE 0x00000010 /* Tick Timer exception */ +#define SPR_DSR_AE 0x00000020 /* Alignment exception */ +#define SPR_DSR_IIE 0x00000040 /* Illegal Instruction exception */ +#define SPR_DSR_IE 0x00000080 /* Interrupt exception */ +#define SPR_DSR_DME 0x00000100 /* DTLB miss exception */ +#define SPR_DSR_IME 0x00000200 /* ITLB miss exception */ +#define SPR_DSR_RE 0x00000400 /* Range exception */ +#define SPR_DSR_SCE 0x00000800 /* System call exception */ +#define SPR_DSR_FPE 0x00001000 /* Floating Point Exception */ +#define SPR_DSR_TE 0x00002000 /* Trap exception */ + +/* + * Bit definitions for Debug reason register + */ + +#define SPR_DRR_RSTE 0x00000001 /* Reset exception */ +#define SPR_DRR_BUSEE 0x00000002 /* Bus error exception */ +#define SPR_DRR_DPFE 0x00000004 /* Data Page Fault exception */ +#define SPR_DRR_IPFE 0x00000008 /* Insn Page Fault exception */ +#define SPR_DRR_TTE 0x00000010 /* Tick Timer exception */ +#define SPR_DRR_AE 0x00000020 /* Alignment exception */ +#define SPR_DRR_IIE 0x00000040 /* Illegal Instruction exception */ +#define SPR_DRR_IE 0x00000080 /* Interrupt exception */ +#define SPR_DRR_DME 0x00000100 /* DTLB miss exception */ +#define SPR_DRR_IME 0x00000200 /* ITLB miss exception */ +#define SPR_DRR_RE 0x00000400 /* Range exception */ +#define SPR_DRR_SCE 0x00000800 /* System call exception */ +#define SPR_DRR_FPE 0x00001000 /* Floating Point Exception */ +#define SPR_DRR_TE 0x00002000 /* Trap exception */ + +/* + * Bit definitions for Performance counters mode registers + */ + +#define SPR_PCMR_CP 0x00000001 /* Counter present */ +#define SPR_PCMR_UMRA 0x00000002 /* User mode read access */ +#define SPR_PCMR_CISM 0x00000004 /* Count in supervisor mode */ +#define SPR_PCMR_CIUM 0x00000008 /* Count in user mode */ +#define SPR_PCMR_LA 0x00000010 /* Load access event */ +#define SPR_PCMR_SA 0x00000020 /* Store access event */ +#define SPR_PCMR_IF 0x00000040 /* Instruction fetch event*/ +#define SPR_PCMR_DCM 0x00000080 /* Data cache miss event */ +#define SPR_PCMR_ICM 0x00000100 /* Insn cache miss event */ +#define SPR_PCMR_IFS 0x00000200 /* Insn fetch stall event */ +#define SPR_PCMR_LSUS 0x00000400 /* LSU stall event */ +#define SPR_PCMR_BS 0x00000800 /* Branch stall event */ +#define SPR_PCMR_DTLBM 0x00001000 /* DTLB miss event */ +#define SPR_PCMR_ITLBM 0x00002000 /* ITLB miss event */ +#define SPR_PCMR_DDS 0x00004000 /* Data dependency stall event */ +#define SPR_PCMR_WPE 0x03ff8000 /* Watchpoint events */ + +/* + * Bit definitions for the Power management register + */ + +#define SPR_PMR_SDF 0x0000000f /* Slow down factor */ +#define SPR_PMR_DME 0x00000010 /* Doze mode enable */ +#define SPR_PMR_SME 0x00000020 /* Sleep mode enable */ +#define SPR_PMR_DCGE 0x00000040 /* Dynamic clock gating enable */ +#define SPR_PMR_SUME 0x00000080 /* Suspend mode enable */ + +/* + * Bit definitions for PICMR + */ + +#define SPR_PICMR_IUM 0xfffffffc /* Interrupt unmask */ + +/* + * Bit definitions for PICPR + */ + +#define SPR_PICPR_IPRIO 0xfffffffc /* Interrupt priority */ + +/* + * Bit definitions for PICSR + */ + +#define SPR_PICSR_IS 0xffffffff /* Interrupt status */ + +/* + * Bit definitions for Tick Timer Control Register + */ + +#define SPR_TTCR_CNT 0xffffffff /* Count, time period */ +#define SPR_TTMR_TP 0x0fffffff /* Time period */ +#define SPR_TTMR_IP 0x10000000 /* Interrupt Pending */ +#define SPR_TTMR_IE 0x20000000 /* Interrupt Enable */ +#define SPR_TTMR_DI 0x00000000 /* Disabled */ +#define SPR_TTMR_RT 0x40000000 /* Restart tick */ +#define SPR_TTMR_SR 0x80000000 /* Single run */ +#define SPR_TTMR_CR 0xc0000000 /* Continuous run */ +#define SPR_TTMR_M 0xc0000000 /* Tick mode */ + +/* + * Bit definitions for the FP Control Status Register + */ + +#define SPR_FPCSR_FPEE 0x00000001 /* Floating Point Exception Enable */ +#define SPR_FPCSR_RM 0x00000006 /* Rounding Mode */ +#define SPR_FPCSR_OVF 0x00000008 /* Overflow Flag */ +#define SPR_FPCSR_UNF 0x00000010 /* Underflow Flag */ +#define SPR_FPCSR_SNF 0x00000020 /* SNAN Flag */ +#define SPR_FPCSR_QNF 0x00000040 /* QNAN Flag */ +#define SPR_FPCSR_ZF 0x00000080 /* Zero Flag */ +#define SPR_FPCSR_IXF 0x00000100 /* Inexact Flag */ +#define SPR_FPCSR_IVF 0x00000200 /* Invalid Flag */ +#define SPR_FPCSR_INF 0x00000400 /* Infinity Flag */ +#define SPR_FPCSR_DZF 0x00000800 /* Divide By Zero Flag */ +#define SPR_FPCSR_ALLF (SPR_FPCSR_OVF | SPR_FPCSR_UNF | SPR_FPCSR_SNF | \ + SPR_FPCSR_QNF | SPR_FPCSR_ZF | SPR_FPCSR_IXF | \ + SPR_FPCSR_IVF | SPR_FPCSR_INF | SPR_FPCSR_DZF) + +#define FPCSR_RM_RN (0<<1) +#define FPCSR_RM_RZ (1<<1) +#define FPCSR_RM_RIP (2<<1) +#define FPCSR_RM_RIN (3<<1) + +/* + * l.nop constants + */ + +#define NOP_NOP 0x0000 /* Normal nop instruction */ +#define NOP_EXIT 0x0001 /* End of simulation */ +#define NOP_REPORT 0x0002 /* Simple report */ +#define NOP_PUTC 0x0004 /* JPB: Simputc instruction */ +#define NOP_CNT_RESET 0x0005 /* Reset statistics counters */ +#define NOP_GET_TICKS 0x0006 /* JPB: Get # ticks running */ +#define NOP_GET_PS 0x0007 /* JPB: Get picosecs/cycle */ +#define NOP_TRACE_ON 0x0008 /* Turn on tracing */ +#define NOP_TRACE_OFF 0x0009 /* Turn off tracing */ +#define NOP_RANDOM 0x000a /* Return 4 random bytes */ +#define NOP_OR1KSIM 0x000b /* Return non-zero if this is Or1ksim */ +#define NOP_EXIT_SILENT 0x000c /* End of simulation, quiet version */ + +#endif /* _ZEPHYR_ARCH_OPENRISC_INCLUDE_OPENRISC_SPR_DEFS_H_ */ diff --git a/boards/qemu/or1k/Kconfig b/boards/qemu/or1k/Kconfig new file mode 100644 index 000000000000..07fc74f2c63b --- /dev/null +++ b/boards/qemu/or1k/Kconfig @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Joel Holdsworth +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_QEMU_OR1K + select QEMU_TARGET diff --git a/boards/qemu/or1k/Kconfig.defconfig b/boards/qemu/or1k/Kconfig.defconfig new file mode 100644 index 000000000000..d8c3c0dd95d0 --- /dev/null +++ b/boards/qemu/or1k/Kconfig.defconfig @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +if BOARD_QEMU_OR1K + +config BUILD_OUTPUT_BIN + default n + +config QEMU_ICOUNT_SHIFT + default 6 if QEMU_ICOUNT + +endif # BOARD_QEMU_OR1K diff --git a/boards/qemu/or1k/Kconfig.qemu_or1k b/boards/qemu/or1k/Kconfig.qemu_or1k new file mode 100644 index 000000000000..90e87a8525b4 --- /dev/null +++ b/boards/qemu/or1k/Kconfig.qemu_or1k @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_QEMU_OR1K + select SOC_QEMU_OR1K diff --git a/boards/qemu/or1k/board.cmake b/boards/qemu/or1k/board.cmake new file mode 100644 index 000000000000..04457c4f9f21 --- /dev/null +++ b/boards/qemu/or1k/board.cmake @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(SUPPORTED_EMU_PLATFORMS qemu) + +set(QEMU_binary_suffix or1k) +set(QEMU_CPU_TYPE_${ARCH} or1k) + +set(QEMU_FLAGS_${ARCH} + -machine or1k-sim + -nographic +) + +board_set_debugger_ifnset(qemu) diff --git a/boards/qemu/or1k/board.yml b/boards/qemu/or1k/board.yml new file mode 100644 index 000000000000..01a6e4d4fd06 --- /dev/null +++ b/boards/qemu/or1k/board.yml @@ -0,0 +1,6 @@ +board: + name: qemu_or1k + full_name: QEMU Emulation for OpenRISC 1000 + vendor: qemu + socs: + - name: qemu_or1k diff --git a/boards/qemu/or1k/doc/index.rst b/boards/qemu/or1k/doc/index.rst new file mode 100644 index 000000000000..41026cdcb4ad --- /dev/null +++ b/boards/qemu/or1k/doc/index.rst @@ -0,0 +1,92 @@ +.. _qemu_or1k: + +OpenRISC 1000 Emulation (QEMU) +############################## + +Overview +******** + +This board configuration will use QEMU to emulate the OpenRISC 1000 platform. + +This configuration provides support for an or1k CPU core and these devices: + +* OpenRISC Interrupt Controller +* OpenRISC Tick Timer +* NS16550 UART + + +.. note:: + This board configuration makes no claims about its suitability for use + with an actual OpenRISC 1000 hardware system, or any other hardware system. + +Hardware +******** + +Supported Features +================== + +The following hardware features are supported: + ++--------------------------------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++================================+============+======================+ +| OpenRISC Interrupt Controller | on-chip | interrupt controller | ++--------------------------------+------------+----------------------+ +| OpenRISC Tick Timer | on-chip | system clock | ++--------------------------------+------------+----------------------+ +| NS16550 UART | FPGA | serial port | ++--------------------------------+------------+----------------------+ + +The kernel currently does not support other hardware features on this platform. + +Devices +======== +System Clock +------------ + +Qemu Tick Timer timer uses a clock frequency of 20 MHz, +see hw/openrisc/cputimer.c in Qemu source tree for details. + +Serial Port +----------- + +This board configuration uses a single serial communication channel +with UART3. + +Programming and Debugging +************************* + +Use this configuration to run basic Zephyr applications and kernel tests in the QEMU +emulated environment, for example, with the :zephyr:code-sample:`synchronization` sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: qemu_or1k + :goals: run + +This will build an image with the synchronization sample app, boot it using +QEMU, and display the following console output: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-3843-g5a1358a9ef *** + thread_a: Hello World from cpu 0 on qemu_or1k! + thread_b: Hello World from cpu 0 on qemu_or1k! + thread_a: Hello World from cpu 0 on qemu_or1k! + thread_b: Hello World from cpu 0 on qemu_or1k! + thread_a: Hello World from cpu 0 on qemu_or1k! + thread_b: Hello World from cpu 0 on qemu_or1k! + thread_a: Hello World from cpu 0 on qemu_or1k! + thread_b: Hello World from cpu 0 on qemu_or1k! + thread_a: Hello World from cpu 0 on qemu_or1k! + thread_b: Hello World from cpu 0 on qemu_or1k! + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + + +References +********** + +https://www.qemu.org/ diff --git a/boards/qemu/or1k/qemu_or1k.dts b/boards/qemu/or1k/qemu_or1k.dts new file mode 100644 index 000000000000..8e30fb56c00c --- /dev/null +++ b/boards/qemu/or1k/qemu_or1k.dts @@ -0,0 +1,57 @@ +/* + * 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "skeleton.dtsi" + +/ { + model = "Qemu OpenRISC 1000"; + compatible = "opencores,or1ksim"; + interrupt-parent = <&pic>; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart3; + zephyr,shell-uart = &uart3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "opencores,or1200-rtlsvn481"; + reg = <0>; + clock-frequency = <20000000>; + + pic: interrupt-controller { + #interrupt-cells = <1>; + compatible = "opencores,or1k-pic-level"; + interrupt-controller; + }; + }; + }; + + + sram0: memory@0 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x00000000 0x08000000>; + }; + + uart3: serial@90000300 { + compatible = "ns16550"; + reg = <0x90000300 0x100>; + reg-shift = <0>; + interrupts = <2>; + /* no matter for emulated port */ + clock-frequency = <20000000>; + current-speed = <115200>; + status = "okay"; + }; +}; diff --git a/boards/qemu/or1k/qemu_or1k.yaml b/boards/qemu/or1k/qemu_or1k.yaml new file mode 100644 index 000000000000..f9d120449d79 --- /dev/null +++ b/boards/qemu/or1k/qemu_or1k.yaml @@ -0,0 +1,16 @@ +identifier: qemu_or1k +name: QEMU emulation for OpenRISC 1000 +type: qemu +simulation: + - name: qemu +arch: openrisc +toolchain: + - zephyr + - cross-compile +ram: 128 +testing: + default: true + ignore_tags: + - net + - bluetooth +vendor: qemu diff --git a/boards/qemu/or1k/qemu_or1k_defconfig b/boards/qemu/or1k/qemu_or1k_defconfig new file mode 100644 index 000000000000..7e06442efb73 --- /dev/null +++ b/boards/qemu/or1k/qemu_or1k_defconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_OPENRISC_TICK_TIMER=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_STACK_SENTINEL=y diff --git a/cmake/emu/qemu.cmake b/cmake/emu/qemu.cmake index 11dead318fbb..34063324f2b0 100644 --- a/cmake/emu/qemu.cmake +++ b/cmake/emu/qemu.cmake @@ -8,6 +8,8 @@ elseif("${ARCH}" STREQUAL "mips") else() set_ifndef(QEMU_binary_suffix mipsel) endif() +elseif("${ARCH}" STREQUAL "openrisc") + set_ifndef(QEMU_binary_suffix or1k) elseif(DEFINED QEMU_ARCH) set_ifndef(QEMU_binary_suffix ${QEMU_ARCH}) else() diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 9a6b2697e988..bfd6c97f5da7 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -31,6 +31,7 @@ zephyr_library_sources_ifdef(CONFIG_NATIVE_POSIX_TIMER native_posix_timer.c) zephyr_library_sources_ifdef(CONFIG_NPCX_ITIM_TIMER npcx_itim_timer.c) zephyr_library_sources_ifdef(CONFIG_NRF_GRTC_TIMER nrf_grtc_timer.c) zephyr_library_sources_ifdef(CONFIG_NRF_RTC_TIMER nrf_rtc_timer.c) +zephyr_library_sources_ifdef(CONFIG_OPENRISC_TICK_TIMER openrisc_tick_timer.c) zephyr_library_sources_ifdef(CONFIG_RCAR_CMT_TIMER rcar_cmt_timer.c) zephyr_library_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c) zephyr_library_sources_ifdef(CONFIG_RV32M1_LPTMR_TIMER rv32m1_lptmr_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 839dec71fa26..09f30a019651 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -89,6 +89,7 @@ source "drivers/timer/Kconfig.npcx_itim" source "drivers/timer/Kconfig.nrf_rtc" source "drivers/timer/Kconfig.nrf_grtc" source "drivers/timer/Kconfig.nrf_xrtc" +source "drivers/timer/Kconfig.openrisc_tick" source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" source "drivers/timer/Kconfig.rv32m1_lptmr" diff --git a/drivers/timer/Kconfig.openrisc_tick b/drivers/timer/Kconfig.openrisc_tick new file mode 100644 index 000000000000..d9e8c91e2351 --- /dev/null +++ b/drivers/timer/Kconfig.openrisc_tick @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config OPENRISC_TICK_TIMER + bool "OpenRISC Tick Timer" + depends on OPENRISC + select TICKLESS_CAPABLE + help + This module implements a kernel device driver for the OpenRISC Tick timer. diff --git a/drivers/timer/openrisc_tick_timer.c b/drivers/timer/openrisc_tick_timer.c new file mode 100644 index 000000000000..5e9687850d15 --- /dev/null +++ b/drivers/timer/openrisc_tick_timer.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAX_CYC SPR_TTMR_TP + +static struct k_spinlock lock; +static uint32_t last_count; +static uint64_t last_ticks; +static uint32_t last_elapsed; +static uint32_t cyc_per_tick; + +static ALWAYS_INLINE void set_compare(uint32_t time) +{ + openrisc_write_spr(SPR_TTMR, SPR_TTMR_IE | SPR_TTMR_CR | time); +} + +static ALWAYS_INLINE void clear_compare(void) +{ + openrisc_write_spr(SPR_TTMR, SPR_TTMR_CR); +} + +static ALWAYS_INLINE uint32_t get_count(void) +{ + return openrisc_read_spr(SPR_TTCR); +} + +void z_openrisc_timer_isr(void) +{ + if (IS_ENABLED(CONFIG_TRACING_ISR)) { + sys_trace_isr_enter(); + } + + const k_spinlock_key_t key = k_spin_lock(&lock); + + const uint32_t current_count = get_count(); + const uint32_t delta_count = current_count - last_count; + const uint32_t delta_ticks = delta_count / cyc_per_tick; + + last_count += delta_ticks * cyc_per_tick; + last_ticks += delta_ticks; + last_elapsed = 0; + + if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + clear_compare(); + } else { + set_compare((last_count + cyc_per_tick) & MAX_CYC); + } + + k_spin_unlock(&lock, key); + sys_clock_announce(delta_ticks); + + if (IS_ENABLED(CONFIG_TRACING_ISR)) { + sys_trace_isr_exit(); + } +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ +#if defined(CONFIG_TICKLESS_KERNEL) + if (ticks == K_TICKS_FOREVER) { + if (idle) { + return; + } + + ticks = INT32_MAX; + } + + /* + * Clamp the max period length to a number of cycles that can fit + * in half the range of a cycle_diff_t for native width divisions + * to be usable elsewhere. The half range gives us extra room to cope + * with the unavoidable IRQ servicing latency. + */ + ticks = CLAMP(ticks, 0, MAX_CYC / 2 / cyc_per_tick); + + const uint32_t compare = + ((last_ticks + last_elapsed + (uint32_t)ticks) * cyc_per_tick) & MAX_CYC; + const k_spinlock_key_t key = k_spin_lock(&lock); + + set_compare(compare); + k_spin_unlock(&lock, key); + +#else /* CONFIG_TICKLESS_KERNEL */ + ARG_UNUSED(ticks); + ARG_UNUSED(idle); +#endif +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + const k_spinlock_key_t key = k_spin_lock(&lock); + + const uint32_t current_count = get_count(); + const uint32_t delta_count = current_count - last_count; + const uint32_t delta_ticks = delta_count / cyc_per_tick; + + last_elapsed = delta_ticks; + k_spin_unlock(&lock, key); + return delta_ticks; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return get_count(); +} + +static int sys_clock_driver_init(void) +{ + cyc_per_tick = (uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() / + (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC); + + last_ticks = get_count() / cyc_per_tick; + last_count = last_ticks * cyc_per_tick; + last_elapsed = 0; + + set_compare((last_count + cyc_per_tick) & MAX_CYC); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, + CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/bindings/interrupt-controller/openrisc,or1k-pic-level.yaml b/dts/bindings/interrupt-controller/openrisc,or1k-pic-level.yaml new file mode 100644 index 000000000000..50bb86a3eca3 --- /dev/null +++ b/dts/bindings/interrupt-controller/openrisc,or1k-pic-level.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: OpenRISC CPU interrupt controller + +compatible: "opencores,or1k-pic-level" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 1 + +interrupt-cells: + - irq diff --git a/include/zephyr/arch/arch_inlines.h b/include/zephyr/arch/arch_inlines.h index 0f32159e2f1b..86b306a01d16 100644 --- a/include/zephyr/arch/arch_inlines.h +++ b/include/zephyr/arch/arch_inlines.h @@ -28,6 +28,8 @@ #include #elif defined(CONFIG_MIPS) #include +#elif defined(CONFIG_OPENRISC) +#include #elif defined(CONFIG_ARCH_POSIX) #include #elif defined(CONFIG_SPARC) diff --git a/include/zephyr/arch/cpu.h b/include/zephyr/arch/cpu.h index 1e107512fa2a..5f52f8dc9224 100644 --- a/include/zephyr/arch/cpu.h +++ b/include/zephyr/arch/cpu.h @@ -27,6 +27,8 @@ #include #elif defined(CONFIG_MIPS) #include +#elif defined(CONFIG_OPENRISC) +#include #elif defined(CONFIG_ARCH_POSIX) #include #elif defined(CONFIG_SPARC) diff --git a/include/zephyr/arch/openrisc/arch.h b/include/zephyr/arch/openrisc/arch.h new file mode 100644 index 000000000000..3a6012a68c9c --- /dev/null +++ b/include/zephyr/arch/openrisc/arch.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_H_ +#define ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_H_ + +#include + +#include +#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) +#include +#include +#include +#include +#include + +#include + +#include + +#define ARCH_STACK_PTR_ALIGN 8 + +#define SPR_SR_IRQ_MASK (SPR_SR_IEE | SPR_SR_TEE) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Configure a static interrupt. + * + * All arguments must be computable by the compiler at build time. + * + * @param irq_p IRQ line number + * @param priority_p Interrupt priority + * @param isr_p Interrupt service routine + * @param isr_param_p ISR parameter + * @param flags_p IRQ options + * + * @return The vector assigned to this interrupt + */ + +#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ + { \ + Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \ + } + +static ALWAYS_INLINE unsigned int arch_irq_lock(void) +{ + const uint32_t sr = openrisc_read_spr(SPR_SR); + + openrisc_write_spr(SPR_SR, sr & ~SPR_SR_IRQ_MASK); + return (sr & SPR_SR_IRQ_MASK) ? 1 : 0; +} + +static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) +{ + const uint32_t sr = openrisc_read_spr(SPR_SR); + + openrisc_write_spr(SPR_SR, key ? (sr | SPR_SR_IRQ_MASK) : (sr & ~SPR_SR_IRQ_MASK)); +} + +static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) +{ + return key != 0; +} + +static ALWAYS_INLINE void arch_nop(void) +{ + __asm__ volatile ("l.nop"); +} + +extern uint32_t sys_clock_cycle_get_32(void); + +static inline uint32_t arch_k_cycle_get_32(void) +{ + return sys_clock_cycle_get_32(); +} + +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_H_ */ diff --git a/include/zephyr/arch/openrisc/arch_inlines.h b/include/zephyr/arch/openrisc/arch_inlines.h new file mode 100644 index 000000000000..127541582a4e --- /dev/null +++ b/include/zephyr/arch/openrisc/arch_inlines.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_INLINES_H +#define ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_INLINES_H + +#include + +static ALWAYS_INLINE unsigned int arch_num_cpus(void) +{ + return CONFIG_MP_MAX_NUM_CPUS; +} + +#endif /* ZEPHYR_INCLUDE_ARCH_OPENRISC_ARCH_INLINES_H */ diff --git a/include/zephyr/arch/openrisc/exception.h b/include/zephyr/arch/openrisc/exception.h new file mode 100644 index 000000000000..508b948f9645 --- /dev/null +++ b/include/zephyr/arch/openrisc/exception.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_OPENRISC_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_OPENRISC_EXCEPTION_H_ + +#ifndef _ASMLANGUAGE +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct arch_esf { + uint32_t r3; /* Function argument */ + uint32_t r4; /* Function argument */ + uint32_t r5; /* Function argument */ + uint32_t r6; /* Function argument */ + uint32_t r7; /* Function argument */ + uint32_t r8; /* Function argument */ + + uint32_t r11; /* Return value (low) */ + uint32_t r12; /* Return value (high) */ + + uint32_t r13; /* Caller-saved general purpose */ + uint32_t r15; /* Caller-saved general purpose */ + uint32_t r17; /* Caller-saved general purpose */ + uint32_t r19; /* Caller-saved general purpose */ + uint32_t r21; /* Caller-saved general purpose */ + uint32_t r23; /* Caller-saved general purpose */ + uint32_t r25; /* Caller-saved general purpose */ + uint32_t r27; /* Caller-saved general purpose */ + uint32_t r29; /* Caller-saved general purpose */ + uint32_t r31; /* Caller-saved general purpose */ + + uint32_t mac_lo; + uint32_t mac_hi; + + uint32_t epcr; + uint32_t esr; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_OPENRISC_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/openrisc/linker.ld b/include/zephyr/arch/openrisc/linker.ld new file mode 100644 index 000000000000..279ea6009a02 --- /dev/null +++ b/include/zephyr/arch/openrisc/linker.ld @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * based on include/arch/mips/linker.ld + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file for the OpenRISC platform + */ + +#include +#include +#include + +#define ROMABLE_REGION RAM +#define RAMABLE_REGION RAM + +#define _EXCEPTION_SECTION_NAME exceptions + +MEMORY +{ + RAM (rwx) : ORIGIN = CONFIG_SRAM_BASE_ADDRESS, LENGTH = KB(CONFIG_SRAM_SIZE) + /* Used by and documented in include/linker/intlist.ld */ + IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K +} + +REGION_ALIAS("REGION_TEXT", RAM); +REGION_ALIAS("REGION_RODATA", RAM); +REGION_ALIAS("REGION_DATA_VMA", RAM); +REGION_ALIAS("REGION_DATA_LMA", RAM); +REGION_ALIAS("REGION_BSS", RAM); + +ENTRY(CONFIG_KERNEL_ENTRY) + +PROVIDE (__memory_base = CONFIG_SRAM_BASE_ADDRESS); +PROVIDE (__memory_size = CONFIG_SRAM_SIZE * 1024); +PROVIDE (__stack = CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE - 1) * 1024); + +SECTIONS +{ + +#include + + SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) + { + KEEP(*(.exceptions)) + KEEP(*(.exceptions.*)) + } GROUP_LINK_IN(ROMABLE_REGION) + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + . = ALIGN(4); + + *(.text) + *(".text.*") + } GROUP_LINK_IN(REGION_TEXT) + + __rodata_region_start = .; +#include +/* Located in generated directory. This file is populated by calling + * zephyr_linker_sources(ROM_SECTIONS ...). Useful for grouping iterable RO structs. + */ +#include +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + . = ALIGN(4); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_LINK_IN(REGION_RODATA) + +#include + __rodata_region_end = .; + + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + . = ALIGN(8); + _image_ram_start = .; + __data_ram_start = .; + + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.sdata) + *(.sdata.*) + . = ALIGN(8); + SORT(CONSTRUCTORS) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_DATA_LINK_IN(REGION_DATA_VMA, REGION_DATA_LMA) + +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + __data_ram_end = .; + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes + */ + . = ALIGN(4); + __bss_start = .; + *(.dynbss) + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(.scommon) + COMMON_SYMBOLS + /* + * As memory is cleared in words only, it is simpler to ensure the BSS + * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. + */ + __bss_end = ALIGN(4); + } GROUP_LINK_IN(REGION_BSS) + + SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) + { + /* + * This section is used for non-initialized objects that + * will not be cleared during the boot process. + */ + *(.noinit) + *(.noinit.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + } GROUP_LINK_IN(REGION_BSS) + +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#include + + GROUP_END(RAMABLE_REGION) + +#include + + .mdebug.abi32 : { + KEEP(*(.mdebug.abi32)) + } + + SECTION_PROLOGUE(.gnu.attributes, 0,) + { + KEEP(*(.gnu.attributes)) + } + + /DISCARD/ : { + *(.pdr) + *(.reginfo) + } +} diff --git a/include/zephyr/arch/openrisc/syscall.h b/include/zephyr/arch/openrisc/syscall.h new file mode 100644 index 000000000000..1b7b0ca543e3 --- /dev/null +++ b/include/zephyr/arch/openrisc/syscall.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief OpenRISC specific syscall header + * + * This header contains the OpenRISC specific syscall interface. It is + * included by the syscall interface architecture-abstraction header + * (include/arch/syscall.h) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_OPENRISC_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_OPENRISC_SYSCALL_H_ + +/* + * Privileged mode system calls + */ +#define OR_SYSCALL_RUNTIME_EXCEPT 0 +#define OR_SYSCALL_IRQ_OFFLOAD 1 + +#ifndef _ASMLANGUAGE + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Syscall invocation macros. OpenRISC-specific machine constraints used to + * ensure args land in the proper registers. + */ +static inline uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r4 __asm__ ("r4") = arg2; + register unsigned long r5 __asm__ ("r5") = arg3; + register unsigned long r6 __asm__ ("r6") = arg4; + register unsigned long r7 __asm__ ("r7") = arg5; + register unsigned long r8 __asm__ ("r8") = arg6; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3), "r" (r4), "r" (r5), "r" (r6), "r" (r7), + "r" (r8) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, + uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r4 __asm__ ("r4") = arg2; + register unsigned long r5 __asm__ ("r5") = arg3; + register unsigned long r6 __asm__ ("r6") = arg4; + register unsigned long r7 __asm__ ("r7") = arg5; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3), "r" (r4), "r" (r5), "r" (r6), "r" (r7) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r4 __asm__ ("r4") = arg2; + register unsigned long r5 __asm__ ("r5") = arg3; + register unsigned long r6 __asm__ ("r6") = arg4; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3), "r" (r4), "r" (r5), "r" (r6) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, + uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r4 __asm__ ("r4") = arg2; + register unsigned long r5 __asm__ ("r5") = arg3; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3), "r" (r4), "r" (r5) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r4 __asm__ ("r4") = arg2; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3), "r" (r4) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke1(uintptr_t arg1, uintptr_t call_id) +{ + register unsigned long r3 __asm__ ("r3") = arg1; + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : "r" (r3) + : "memory"); + return r11; +} + +static inline uintptr_t arch_syscall_invoke0(uintptr_t call_id) +{ + register unsigned long r11 __asm__ ("r11") = call_id; + + __asm__ volatile ("l.sys 0" + : "+r" (r11) + : + : "memory"); + return r11; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* ZEPHYR_INCLUDE_ARCH_OPENRISC_SYSCALL_H_ */ diff --git a/include/zephyr/arch/openrisc/thread.h b/include/zephyr/arch/openrisc/thread.h new file mode 100644 index 000000000000..3ed99f6a96c3 --- /dev/null +++ b/include/zephyr/arch/openrisc/thread.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * based on include/arch/mips/thread.h + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Per-arch thread definition + * + * This file contains definitions for + * + * struct _thread_arch + * struct _callee_saved + * + * necessary to instantiate instances of struct k_thread. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_OPENRISC_THREAD_H_ +#define ZEPHYR_INCLUDE_ARCH_OPENRISC_THREAD_H_ + +#ifndef _ASMLANGUAGE +#include + +/* + * The following structure defines the list of registers that need to be + * saved/restored when a cooperative context switch occurs. + */ +struct _callee_saved { + uint32_t r1; /* Stack pointer */ + uint32_t r2; /* Frame Pointer */ + uint32_t r9; /* Return Address */ + + uint32_t r10; + uint32_t r14; + uint32_t r16; + uint32_t r18; + uint32_t r20; + uint32_t r22; + uint32_t r24; + uint32_t r26; + uint32_t r28; + uint32_t r30; +}; +typedef struct _callee_saved _callee_saved_t; + +struct _thread_arch { +}; + +typedef struct _thread_arch _thread_arch_t; + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_OPENRISC_THREAD_H_ */ diff --git a/include/zephyr/linker/linker-tool-gcc.h b/include/zephyr/linker/linker-tool-gcc.h index 32319a41543a..e84889b66688 100644 --- a/include/zephyr/linker/linker-tool-gcc.h +++ b/include/zephyr/linker/linker-tool-gcc.h @@ -59,6 +59,8 @@ /* Not needed */ #elif defined(CONFIG_SPARC) OUTPUT_FORMAT("elf32-sparc") +#elif defined(CONFIG_OPENRISC) + OUTPUT_FORMAT("elf32-or1k") #else #error Arch not supported. #endif diff --git a/include/zephyr/linker/utils.h b/include/zephyr/linker/utils.h index 5b92f5b48dd1..24f56adaaa87 100644 --- a/include/zephyr/linker/utils.h +++ b/include/zephyr/linker/utils.h @@ -36,7 +36,8 @@ static inline bool linker_is_in_rodata(const void *addr) #if defined(CONFIG_ARM) || defined(CONFIG_ARC) || defined(CONFIG_X86) || \ defined(CONFIG_ARM64) || defined(CONFIG_NIOS2) || \ defined(CONFIG_RISCV) || defined(CONFIG_SPARC) || \ - defined(CONFIG_MIPS) || defined(CONFIG_XTENSA) + defined(CONFIG_MIPS) || defined(CONFIG_XTENSA) || \ + defined(CONFIG_OPENRISC) extern char __rodata_region_start[]; extern char __rodata_region_end[]; #define RO_START __rodata_region_start diff --git a/include/zephyr/toolchain/common.h b/include/zephyr/toolchain/common.h index c84328365fd3..afdcfd4302b7 100644 --- a/include/zephyr/toolchain/common.h +++ b/include/zephyr/toolchain/common.h @@ -87,7 +87,8 @@ #define PERFOPT_ALIGN .align 4 #elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || \ - defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) + defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) || \ + defined(CONFIG_OPENRISC) #define PERFOPT_ALIGN .balign 4 #elif defined(CONFIG_ARCH_POSIX) diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index e003cd2c26f7..30f4346569fe 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -370,7 +370,7 @@ do { \ #if defined(CONFIG_ARM) || defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) \ || defined(CONFIG_XTENSA) || defined(CONFIG_ARM64) \ - || defined(CONFIG_MIPS) + || defined(CONFIG_MIPS) || defined(CONFIG_OPENRISC) #define GTEXT(sym) .global sym; .type sym, %function #define GDATA(sym) .global sym; .type sym, %object #define WTEXT(sym) .weak sym; .type sym, %function @@ -552,7 +552,8 @@ do { \ "\n\t.type\t" #name ",@object") #elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || \ - defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) + defined(CONFIG_XTENSA) || defined(CONFIG_MIPS) || \ + defined(CONFIG_OPENRISC) /* No special prefixes necessary for constants in this arch AFAICT */ #define GEN_ABSOLUTE_SYM(name, value) \ diff --git a/kernel/Kconfig b/kernel/Kconfig index 9c92dc542c0e..252a3bc10e1d 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -157,7 +157,7 @@ config SCHED_CPU_MASK_PIN_ONLY config MAIN_STACK_SIZE int "Size of stack for initialization and main thread" default 2048 if COVERAGE_GCOV - default 512 if ZTEST && !(RISCV || X86 || ARM || ARC || NIOS2) + default 512 if ZTEST && !(RISCV || X86 || ARM || ARC || NIOS2 || OPENRISC) default 1024 help When the initialization is complete, the thread executing it then diff --git a/scripts/logging/dictionary/dictionary_parser/log_database.py b/scripts/logging/dictionary/dictionary_parser/log_database.py index 83e34e4abebb..654752409f6e 100644 --- a/scripts/logging/dictionary/dictionary_parser/log_database.py +++ b/scripts/logging/dictionary/dictionary_parser/log_database.py @@ -46,6 +46,9 @@ # for explanation. "extra_string_section": ['datas'], }, + "openrisc" : { + "kconfig": "CONFIG_OPENRISC", + }, "posix" : { "kconfig": "CONFIG_ARCH_POSIX", }, diff --git a/scripts/pylib/twister/twisterlib/platform.py b/scripts/pylib/twister/twisterlib/platform.py index f960610ae141..4fc56a4696b0 100644 --- a/scripts/pylib/twister/twisterlib/platform.py +++ b/scripts/pylib/twister/twisterlib/platform.py @@ -160,6 +160,7 @@ def load(self, board, target, aliases, data, variant_data): "arm64": ["zephyr", "cross-compile"], "mips": ["zephyr"], "nios2": ["zephyr"], + "openrisc": ["zephyr"], "riscv": ["zephyr", "cross-compile"], "posix": ["host", "llvm"], "sparc": ["zephyr"], diff --git a/scripts/schemas/twister/platform-schema.yaml b/scripts/schemas/twister/platform-schema.yaml index 945163ae3273..29351f9636ba 100644 --- a/scripts/schemas/twister/platform-schema.yaml +++ b/scripts/schemas/twister/platform-schema.yaml @@ -62,6 +62,7 @@ schema;platform-schema: "arm64", "mips", "nios2", + "openrisc", "posix", "riscv", "sparc", diff --git a/soc/qemu/or1k/CMakeLists.txt b/soc/qemu/or1k/CMakeLists.txt new file mode 100644 index 000000000000..f70db9b413d5 --- /dev/null +++ b/soc/qemu/or1k/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_compile_options( + ${TOOLCHAIN_C_FLAGS} +) + +zephyr_ld_options( + ${TOOLCHAIN_LD_FLAGS} +) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/openrisc/linker.ld CACHE INTERNAL "") diff --git a/soc/qemu/or1k/Kconfig b/soc/qemu/or1k/Kconfig new file mode 100644 index 000000000000..bd490337d8cf --- /dev/null +++ b/soc/qemu/or1k/Kconfig @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_QEMU_OR1K + select OPENRISC diff --git a/soc/qemu/or1k/Kconfig.defconfig b/soc/qemu/or1k/Kconfig.defconfig new file mode 100644 index 000000000000..691f478c6037 --- /dev/null +++ b/soc/qemu/or1k/Kconfig.defconfig @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_QEMU_OR1K + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 20000000 + +config NUM_IRQS + default 32 + +endif # SOC_QEMU_OR1K diff --git a/soc/qemu/or1k/Kconfig.soc b/soc/qemu/or1k/Kconfig.soc new file mode 100644 index 000000000000..7ccfa139a41f --- /dev/null +++ b/soc/qemu/or1k/Kconfig.soc @@ -0,0 +1,11 @@ +# +# Copyright (c) 2025 NVIDIA Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_QEMU_OR1K + bool + +config SOC + default "qemu_or1k" if SOC_QEMU_OR1K diff --git a/soc/qemu/or1k/soc.h b/soc/qemu/or1k/soc.h new file mode 100644 index 000000000000..11ff9603cb84 --- /dev/null +++ b/soc/qemu/or1k/soc.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2025 NVIDIA Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __QEMU_OR1K_SOC_H__ +#define __QEMU_OR1K_SOC_H__ + +#endif /* __QEMU_OR1K_SOC_H__ */ diff --git a/soc/qemu/or1k/soc.yml b/soc/qemu/or1k/soc.yml new file mode 100644 index 000000000000..bf17bb55f96e --- /dev/null +++ b/soc/qemu/or1k/soc.yml @@ -0,0 +1,2 @@ +socs: + - name: qemu_or1k diff --git a/subsys/debug/thread_info.c b/subsys/debug/thread_info.c index 742cbd594850..3953680c447e 100644 --- a/subsys/debug/thread_info.c +++ b/subsys/debug/thread_info.c @@ -74,6 +74,9 @@ const size_t _kernel_thread_info_offsets[] = { #elif defined(CONFIG_MIPS) [THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread, callee_saved.sp), +#elif defined(CONFIG_OPENRISC) + [THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread, + callee_saved.r1), #elif defined(CONFIG_NIOS2) [THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread, callee_saved.sp), diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h index 71dfda7c1931..ac42c7f1359d 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -154,6 +154,8 @@ extern "C" { #define PROCESSOR_NAME "xtensa" #elif defined(CONFIG_SPARC) #define PROCESSOR_NAME "sparc" +#elif defined(CONFIG_OPENRISC) +#define PROCESSOR_NAME "openrisc" #endif #ifndef PROCESSOR_NAME diff --git a/subsys/testsuite/Kconfig b/subsys/testsuite/Kconfig index dd1aff5b6251..37e9e03ed14d 100644 --- a/subsys/testsuite/Kconfig +++ b/subsys/testsuite/Kconfig @@ -18,6 +18,7 @@ config TEST_EXTRA_STACK_SIZE int "Test function extra thread stack size" default 2048 if COVERAGE_GCOV default 768 if XTENSA + default 128 if OPENRISC default 0 depends on TEST help diff --git a/subsys/testsuite/include/zephyr/interrupt_util.h b/subsys/testsuite/include/zephyr/interrupt_util.h index a3653618d970..eadf327913fc 100644 --- a/subsys/testsuite/include/zephyr/interrupt_util.h +++ b/subsys/testsuite/include/zephyr/interrupt_util.h @@ -204,6 +204,14 @@ static inline void trigger_irq(int irq) z_mips_enter_irq(irq); } +#elif defined(CONFIG_OPENRISC) +extern void z_openrisc_enter_irq(int); + +static inline void trigger_irq(int irq) +{ + z_openrisc_enter_irq(irq); +} + #elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_VIM) extern void z_vim_arm_enter_irq(int); diff --git a/subsys/testsuite/include/zephyr/test_asm_inline_gcc.h b/subsys/testsuite/include/zephyr/test_asm_inline_gcc.h index aba64c450c8c..b1b782a3429c 100644 --- a/subsys/testsuite/include/zephyr/test_asm_inline_gcc.h +++ b/subsys/testsuite/include/zephyr/test_asm_inline_gcc.h @@ -48,6 +48,8 @@ static inline void timestamp_serialize(void) #define timestamp_serialize() #elif defined(CONFIG_MIPS) #define timestamp_serialize() +#elif defined(CONFIG_OPENRISC) +#define timestamp_serialize() #else #error implementation of timestamp_serialize() not provided for your CPU target #endif diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index 699c7bdc642b..685062810be0 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -56,6 +56,7 @@ */ #elif defined(CONFIG_SPARC) #elif defined(CONFIG_MIPS) +#elif defined(CONFIG_OPENRISC) #elif defined(CONFIG_ARCH_POSIX) #if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) #define TICK_IRQ TIMER_TICK_IRQ diff --git a/tests/kernel/fatal/exception/src/main.c b/tests/kernel/fatal/exception/src/main.c index 6eb97068b6ce..2587b3dd4b4b 100644 --- a/tests/kernel/fatal/exception/src/main.c +++ b/tests/kernel/fatal/exception/src/main.c @@ -123,6 +123,8 @@ void entry_cpu_exception_extend(void *p1, void *p2, void *p3) */ #elif defined(CONFIG_ARC) __asm__ volatile ("swi"); +#elif defined(CONFIG_OPENRISC) + __asm__ volatile ("l.trap 0"); #else /* used to create a divide by zero error on X86 and MIPS */ volatile int error; diff --git a/tests/kernel/fatal/no-multithreading/testcase.yaml b/tests/kernel/fatal/no-multithreading/testcase.yaml index ef0b24a79f5f..a86d1921b365 100644 --- a/tests/kernel/fatal/no-multithreading/testcase.yaml +++ b/tests/kernel/fatal/no-multithreading/testcase.yaml @@ -4,6 +4,7 @@ common: - qemu_arc/qemu_arc_em - qemu_arc/qemu_arc_hs - qemu_arc/qemu_arc_hs6x + - qemu_or1k - qemu_riscv32 - qemu_riscv32e - qemu_riscv64 diff --git a/tests/kernel/mem_slab/mslab_api/testcase.yaml b/tests/kernel/mem_slab/mslab_api/testcase.yaml index 40021091d012..3f6dd8561527 100644 --- a/tests/kernel/mem_slab/mslab_api/testcase.yaml +++ b/tests/kernel/mem_slab/mslab_api/testcase.yaml @@ -23,6 +23,7 @@ tests: - qemu_riscv32e - qemu_riscv64 - qemu_leon3 + - qemu_or1k integration_platforms: - qemu_cortex_m3 - qemu_arc/qemu_arc_hs diff --git a/tests/kernel/threads/no-multithreading/testcase.yaml b/tests/kernel/threads/no-multithreading/testcase.yaml index ae0556c54c63..01a27d684ffc 100644 --- a/tests/kernel/threads/no-multithreading/testcase.yaml +++ b/tests/kernel/threads/no-multithreading/testcase.yaml @@ -19,6 +19,7 @@ tests: - qemu_arc/qemu_arc_em - qemu_arc/qemu_arc_hs - qemu_arc/qemu_arc_hs6x + - qemu_or1k - qemu_riscv32 - qemu_riscv32e - qemu_riscv64 diff --git a/tests/kernel/timer/timer_api/testcase.yaml b/tests/kernel/timer/timer_api/testcase.yaml index 454403837a03..622f5461a359 100644 --- a/tests/kernel/timer/timer_api/testcase.yaml +++ b/tests/kernel/timer/timer_api/testcase.yaml @@ -20,6 +20,7 @@ tests: - qemu_arc/qemu_arc_hs - qemu_arc/qemu_arc_hs6x - qemu_leon3 + - qemu_or1k integration_platforms: - qemu_cortex_m3 - nsim/nsim_em diff --git a/tests/lib/mpsc_pbuf/testcase.yaml b/tests/lib/mpsc_pbuf/testcase.yaml index 50d9722e4264..e3860e647574 100644 --- a/tests/lib/mpsc_pbuf/testcase.yaml +++ b/tests/lib/mpsc_pbuf/testcase.yaml @@ -10,6 +10,7 @@ tests: - qemu_cortex_r5 - qemu_leon3 - qemu_nios2 + - qemu_or1k - qemu_riscv32 - qemu_riscv64 - qemu_x86 diff --git a/tests/lib/multi_heap/testcase.yaml b/tests/lib/multi_heap/testcase.yaml index f327881614f1..cf5c3a9d0daf 100644 --- a/tests/lib/multi_heap/testcase.yaml +++ b/tests/lib/multi_heap/testcase.yaml @@ -23,6 +23,7 @@ tests: - qemu_riscv32e - qemu_riscv64 - qemu_leon3 + - qemu_or1k integration_platforms: - qemu_cortex_m3 extra_configs: diff --git a/west.yml b/west.yml index 1c55e5f1e6bf..ab51bd55a008 100644 --- a/west.yml +++ b/west.yml @@ -23,6 +23,8 @@ manifest: url-base: https://github.com/zephyrproject-rtos - name: babblesim url-base: https://github.com/BabbleSim + - name: picolibc + url-base: https://github.com/picolibc group-filter: [-babblesim, -optional] @@ -335,8 +337,9 @@ manifest: groups: - debug - name: picolibc + remote: picolibc path: modules/lib/picolibc - revision: 82d62ed1ac55b4e34a12d0390aced2dc9af13fc9 + revision: 4380f9ae363db5ea4b88c9f339d3faaf1a6b4030 - name: segger revision: cf56b1d9c80f81a26e2ac5727c9cf177116a4692 path: modules/debug/segger