URL
https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk
Subversion Repositories riscv_vhdl
[/] [riscv_vhdl/] [trunk/] [examples/] [zephyr/] [v1.6.0-riscv64-base.diff] - Rev 5
Compare with Previous | Blame | View Log
diff --git a/arch/Kconfig b/arch/Kconfig index c574947..200f486 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -37,6 +37,10 @@ config NIOS2 bool "Nios II Gen 2 architecture" select ATOMIC_OPERATIONS_C +config RISCV64 + bool "RISC-V 64-bits architecture" + select ATOMIC_OPERATIONS_C + endchoice # diff --git a/arch/riscv64/Kbuild b/arch/riscv64/Kbuild new file mode 100644 index 0000000..1573726 --- /dev/null +++ b/arch/riscv64/Kbuild @@ -0,0 +1,6 @@ +subdir-ccflags-y +=-I$(srctree)/include/drivers +subdir-ccflags-y +=-I$(srctree)/drivers +subdir-asflags-y += $(subdir-ccflags-y) + +obj-y += soc/$(SOC_PATH)/ +obj-y += core/ diff --git a/arch/riscv64/Kconfig b/arch/riscv64/Kconfig new file mode 100644 index 0000000..e551376 --- /dev/null +++ b/arch/riscv64/Kconfig @@ -0,0 +1,76 @@ +# ARC EM4 options + +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +choice + prompt "RISC-V SoC Selection" + depends on RISCV64 + + source "arch/riscv64/soc/*/Kconfig.soc" +endchoice + + +menu "RISC-V Options" + depends on RISCV64 + +config ARCH + default "riscv64" + +config ARCH_DEFCONFIG + string + default "arch/riscv64/defconfig" + +config NUM_IRQS + int + prompt "Upper limit of interrupt numbers/IDs used" + range 1 256 + help + Interrupts available will be 1 to NUM_IRQS-1. + Interrupt pin 0 is hardcoded as unused. + +config RISCV_SYSTIMER + bool "Include System Timer" + default y + +config UART_RISCV_GNSS + bool "Include UART" + default y + +config CONSOLE + bool "Include Console" + default y + +config SRAM_SIZE + int "SRAM Size in kB" + default 256 + help + This option specifies the size of the SRAM in kB. It is normally set + by the platform's defconfig file and the user should generally avoid + modifying it via the menu configuration. + +config SRAM_BASE_ADDRESS + hex "SRAM Base Address" + default 0x10000000 + help + This option specifies the base address of the SRAM on the platform. It + is normally set by the platform's defconfig file and the user should + generally avoid modifying it via the menu configuration. + + +source "arch/riscv64/soc/*/Kconfig" + +endmenu diff --git a/arch/riscv64/Makefile b/arch/riscv64/Makefile new file mode 100644 index 0000000..107faa8 --- /dev/null +++ b/arch/riscv64/Makefile @@ -0,0 +1,12 @@ +cflags-y += $(call cc-option,-ffunction-sections,) $(call cc-option,-fdata-sections,) +cflags-$(CONFIG_LTO) = $(call cc-option,-flto,) + +soc_ld_include := -I$(srctree)/arch/$(ARCH)/soc/$(SOC_PATH) +arch_cflags += $(soc_ld_include) +EXTRA_LINKER_CMD_OPT += $(soc_ld_include) + +include $(srctree)/arch/$(ARCH)/soc/$(SOC_PATH)/Makefile + +KBUILD_CFLAGS += $(cflags-y) +KBUILD_CFLAGS += -Wno-unused-function +KBUILD_CXXFLAGS += $(cflags-y) diff --git a/arch/riscv64/_howto_build_riscv b/arch/riscv64/_howto_build_riscv new file mode 100644 index 0000000..f82fc8a --- /dev/null +++ b/arch/riscv64/_howto_build_riscv @@ -0,0 +1,4 @@ +cd samples/shell +export ZEPHYR_BASE=/home/teeshina/svn/20170117_zephyr16/zephyr +make ARCH=riscv64 CROSS_COMPILE=/home/teeshina/riscv/gnu-toolchain-rv64ima/bin/riscv64-unknown-elf- BOARD=riscv_gnss 2>&1 | tee _err.log +elf2raw64 outdir/riscv_gnss/zephyr.elf -h -f 262144 -l 8 -o fwimage.hex diff --git a/arch/riscv64/core/Makefile b/arch/riscv64/core/Makefile new file mode 100644 index 0000000..638187f --- /dev/null +++ b/arch/riscv64/core/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -I$(srctree)/kernel/nanokernel/include +ccflags-y +=-I$(srctree)/arch/$(ARCH)/include +ccflags-y += -I$(srctree)/kernel/microkernel/include + +obj-y += cpu_idle.o fatal.o gptimers.o \ + irq_manage.o swap.o new_thread.o memaccess.o diff --git a/arch/riscv64/core/cpu_idle.c b/arch/riscv64/core/cpu_idle.c new file mode 100644 index 0000000..5f13ec9 --- /dev/null +++ b/arch/riscv64/core/cpu_idle.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief CPU power management + * + * CPU power management routines. + */ + +#include <toolchain.h> +#include <sections.h> +#include <arch/cpu.h> + +/* + * @brief Put the CPU in low-power mode + * + * This function always exits with interrupts unlocked. + * + * void nanCpuIdle(void) + */ + +void nano_cpu_idle(void) { + _arch_irq_unlock(0); +} +/* + * @brief Put the CPU in low-power mode, entered with IRQs locked + * + * This function exits with interrupts restored to <key>. + * + * void nano_cpu_atomic_idle(unsigned int key) + */ +void nano_cpu_atomic_idle(unsigned int key) { + _arch_irq_unlock(key); +} + +void sys_arch_reboot(int type) { + ARG_UNUSED(type); + //DO_REBOOT(); +} diff --git a/arch/riscv64/core/fatal.c b/arch/riscv64/core/fatal.c new file mode 100644 index 0000000..967e09a --- /dev/null +++ b/arch/riscv64/core/fatal.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Nanokernel fatal error handler + * + * This module provides the _NanoFatalErrorHandler() routine. + */ + +#include <toolchain.h> +#include <sections.h> + +#include <nanokernel.h> +#include <misc/printk.h> + +const NANO_ESF _default_esf = { + 0xdeaddead, /* placeholder */ +}; + + +/** + * + * @brief Nanokernel fatal error handler + * + * This routine is called when a fatal error condition is detected by either + * hardware or software. + * + * The caller is expected to always provide a usable ESF. In the event that the + * fatal error does not have a hardware generated ESF, the caller should either + * create its own or use a pointer to the global default ESF <_default_esf>. + * + * @param reason the reason that the handler was called + * @param pEsf pointer to the exception stack frame + * + * @return This function does not return. + */ +FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason, + const NANO_ESF *pEsf) +{ + +#ifdef CONFIG_PRINTK + printk("***** Unhandled interrupt vector %d occurred! \n", -1); +#endif + while (1) {} +} \ No newline at end of file diff --git a/arch/riscv64/core/gptimers.c b/arch/riscv64/core/gptimers.c new file mode 100644 index 0000000..8e5c856 --- /dev/null +++ b/arch/riscv64/core/gptimers.c @@ -0,0 +1,7 @@ +#include <stdint.h> + +// +uint32_t _do_read_cpu_timestamp32(void) { + return 500;//READ32(); +} + diff --git a/arch/riscv64/core/irq_manage.c b/arch/riscv64/core/irq_manage.c new file mode 100644 index 0000000..fb889ac --- /dev/null +++ b/arch/riscv64/core/irq_manage.c @@ -0,0 +1,113 @@ +#include <nanokernel.h> +#include <kernel_structs.h> +#include <misc/__assert.h> +#include <board.h> +#include <sw_isr_table.h> +#include <irq.h> +#include <memaccess.h> + +_IsrTableEntry_t isr_demux_table[CONFIG_NUM_IRQS]; + +void run_isr_handler(int idx, void *arg) { + if (isr_demux_table[idx].isr == 0) { + return; + } + _kernel.nested++; + ((NANO_EOI_GET_FUNC)isr_demux_table[idx].isr)(isr_demux_table[idx].arg); + _kernel.nested--; +} + +unsigned int _arch_irq_lock(void) { + unsigned int ret = READ32(&__IRQCTRL->irq_lock); + WRITE32(&__IRQCTRL->irq_lock, 1); + return ret; +} + +void _arch_irq_unlock(unsigned int key) { + WRITE32(&__IRQCTRL->irq_lock, key); +} + +unsigned int _arch_irq_lock_state() { + return READ32(&__IRQCTRL->irq_lock); +} + +/** + * + * @brief Enable an interrupt line + * + * Clear possible pending interrupts on the line, and enable the interrupt + * line. After this call, the CPU will receive interrupts for the specified + * <irq>. + * + * @return N/A + */ +void _arch_irq_enable(unsigned int irq) +{ + /* before enabling interrupts, ensure that interrupt is cleared */ + uint32_t bit = READ32(&__IRQCTRL->irq_mask); + bit &= ~(1u << irq); + WRITE32(&__IRQCTRL->irq_clear, 1u << irq); + WRITE32(&__IRQCTRL->irq_mask, bit); +} + +/** + * + * @brief Disable an interrupt line + * + * Disable an interrupt line. After this call, the CPU will stop receiving + * interrupts for the specified <irq>. + * + * @return N/A + */ +void _arch_irq_disable(unsigned int irq) +{ + uint32_t bit = READ32(&__IRQCTRL->irq_mask); + bit |= (1u << irq); + WRITE32(&__IRQCTRL->irq_mask, bit); +} + +/* + * @internal + * + * @brief Replace an interrupt handler by another + * + * An interrupt's ISR can be replaced at runtime. + * + * @return N/A + */ + +void _irq_handler_set( + unsigned int irq, + void (*new)(void *arg), + void *arg +) +{ + int key = irq_lock(); + + __ASSERT(irq < CONFIG_NUM_IRQS, "IRQ number too high"); + isr_demux_table[irq].arg = arg; + isr_demux_table[irq].isr = new; + + irq_unlock(key); +} + +/* + * @brief Connect an ISR to an interrupt line + * + * @a isr is connected to interrupt line @a irq, a number greater than or equal + * 16. No prior ISR can have been connected on @a irq interrupt line since the + * system booted. + * + * This routine will hang if another ISR was connected for interrupt line @a irq + * and ASSERT_ON is enabled; if ASSERT_ON is disabled, it will fail silently. + * + * @return the interrupt line number + */ +int _arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(void *arg), void *parameter, + uint32_t flags) +{ + ARG_UNUSED(flags); + _irq_handler_set(irq, routine, parameter); + return irq; +} diff --git a/arch/riscv64/core/memaccess.c b/arch/riscv64/core/memaccess.c new file mode 100644 index 0000000..52a46bb --- /dev/null +++ b/arch/riscv64/core/memaccess.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, GNSS Sensor Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> + +uint16_t READ16(volatile uint16_t *addr) +{ + return *addr; +} + +uint32_t READ32(volatile uint32_t *addr) +{ + return *addr; +} + +uint64_t READ64(volatile uint64_t *addr) +{ + return *addr; +} + +void WRITE32(volatile uint32_t *addr, uint32_t val) +{ + *addr = val; +} + +void WRITE64(volatile uint64_t *addr, uint64_t val) +{ + *addr = val; +} diff --git a/arch/riscv64/core/new_thread.c b/arch/riscv64/core/new_thread.c new file mode 100644 index 0000000..a8492f7 --- /dev/null +++ b/arch/riscv64/core/new_thread.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010-2015 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Nanokernel thread support primitives + * + * This module provides core nanokernel fiber related primitives for the IA-32 + * processor architecture. + */ + + +#include <kernel.h> +#include <nano_internal.h> +#include <kernel_structs.h> +#include <wait_q.h> +#include <string.h> +#include <misc/printk.h> +#include "swap_macros.h" + +#ifdef _WIN32 +extern int LIBH_create_thread(char *pStackMem, + unsigned stackSize, + int priority, + unsigned options); +#endif + +#if defined(CONFIG_THREAD_MONITOR) +/* + * Add a thread to the kernel's list of active threads. + */ +static ALWAYS_INLINE void thread_monitor_init(struct k_thread *thread) +{ + unsigned int key; + + key = irq_lock(); + thread->next_thread = _kernel.threads; + _kernel.threads = thread; + irq_unlock(key); +} +#else +#define thread_monitor_init(thread) \ + do {/* do nothing */ \ + } while ((0)) +#endif /* CONFIG_THREAD_MONITOR */ + + +struct init_stack_frame { + /* top of the stack / most recently pushed */ + + /* Used by _thread_entry_wrapper. pulls these off the stack and + * into argument registers before calling _thread_entry() + */ + _thread_entry_t entry_point; + void *arg1; + void *arg2; + void *arg3; + + /* least recently pushed */ +}; + + +/** + * + * @brief Create a new kernel execution thread + * + * This function is utilized to create execution threads for both fiber + * threads and kernel tasks. + */ +extern void _new_thread(char *pStack, size_t stackSize, + void (*pEntry)(void *, void *, void *), + void *p1, void *p2, void *p3, + int prio, unsigned options) +{ + + + _ASSERT_VALID_PRIO(priority, thread_func); + + struct k_thread *thread; + unsigned long *pInitialCtx; + +#ifdef CONFIG_INIT_STACKS + memset(pStack, 0xaa, stackSize); +#endif + + /* Initialize various struct k_thread members */ + thread = (struct k_thread *)pStack; + pInitialCtx = + (unsigned long *)(pStack + stackSize); + + + _init_thread_base(&thread->base, prio, K_PRESTART, options); + + /* static threads overwrite it afterwards with real value */ + thread->init_data = NULL; + thread->fn_abort = NULL; + +#ifdef CONFIG_THREAD_CUSTOM_DATA + /* Initialize custom data field (value is opaque to kernel) */ + thread->custom_data = NULL; +#endif + thread->callee_saved.key = 0; + thread->callee_saved.preemptive = 0; + /* Leave the rest of thread->callee_saved junk */ + + thread_monitor_init(thread); + + + //printk("\nInitial context SP = 0x%x\n", (unsigned long)pStack); + thread->callee_saved.r[COOP_REG_RA/sizeof(uint64_t)] = (uint64_t)_thread_entry; + thread->callee_saved.r[COOP_REG_MEPC/sizeof(uint64_t)] = (uint64_t)_thread_entry; + thread->callee_saved.r[COOP_REG_A0/sizeof(uint64_t)] = (uint64_t)pEntry; + thread->callee_saved.r[COOP_REG_A1/sizeof(uint64_t)] = (uint64_t)p1; + thread->callee_saved.r[COOP_REG_A2/sizeof(uint64_t)] = (uint64_t)p2; + thread->callee_saved.r[COOP_REG_A3/sizeof(uint64_t)] = (uint64_t)p3; + thread->callee_saved.r[COOP_REG_SP/sizeof(uint64_t)] = + (uint64_t)(pStack + stackSize); +#ifdef _WIN32 + LIBH_create_thread(pStack, (unsigned int)stackSize, prio, options); +#endif +} diff --git a/arch/riscv64/core/offsets/offsets.c b/arch/riscv64/core/offsets/offsets.c new file mode 100644 index 0000000..c1cd125 --- /dev/null +++ b/arch/riscv64/core/offsets/offsets.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief RISC-V nano 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 RISC-V nanokernel + * structures. + * + * All of the absolute symbols defined by this module will be present in the + * final microkernel or nanokernel ELF image (due to the linker's reference to + * the _OffsetAbsSyms symbol). + * + * INTERNAL + * It is NOT necessary to define the offset for every member of a structure. + * Typically, only those members that are accessed by assembly language routines + * are defined; however, it doesn't hurt to define all fields for the sake of + * completeness. + */ + +#include <gen_offset.h> + diff --git a/arch/riscv64/core/swap.S b/arch/riscv64/core/swap.S new file mode 100644 index 0000000..8ead287 --- /dev/null +++ b/arch/riscv64/core/swap.S @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014-2015 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _ASMLANGUAGE + +#include "swap_macros.h" + +/** + * + * @brief Initiate a cooperative context switch + * + * The _Swap() routine is invoked by various nanokernel services to effect + * a cooperative context switch. Prior to invoking _Swap(), the caller + * disables interrupts via nanoCpuIntLock() and the return 'key' is passed as a + * parameter to _Swap(). The key is in fact the value stored in the register + * operand of a CLRI instruction. + * + * It stores the intlock key parameter into current->intlock_key. + + * Given that _Swap() is called to effect a cooperative context switch, + * the caller-saved integer registers are saved on the stack by the function + * call preamble to _Swap(). This creates a custom stack frame that will be + * popped when returning from _Swap(), but is not suitable for handling a return + * from an exception. Thus, the fact that the thread is pending because of a + * cooperative call to _Swap() has to be recorded via the _CAUSE_COOP code in + * the relinquish_cause of the thread's tTCS. The _IrqExit()/_FirqExit() code + * will take care of doing the right thing to restore the thread status. + * + * When _Swap() is invoked, we know the decision to perform a context switch or + * not has already been taken and a context switch must happen. + * + * @return may contain a return value setup by a call to fiberRtnValueSet() + * + * C function prototype: + * + * unsigned int _Swap (unsigned int key); + * + */ + +.section ".text" +.globl __start +__start: + jal _Cstart; + +.section ".text" +.globl _Swap +_Swap: + _save_context(tp) + la s0, _kernel + ld s1,_kernel_offset_to_current(s0) # s1 = _kernel.current + addi s2,s1,_thread_offset_to_callee_saved # s2 = &next_thread->callee_saved + sd a0,_callee_saved_offset_to_key(s2) # _kernel.current->callee_saved.key = fl + + ## Populate default return value + lw a1,_k_neg_eagain + sd a1, _callee_saved_offset_to_retval(s2) + + ## This thread was switched preemptively + li a1,0 + sd a1,_callee_saved_offset_to_preemptive(s2) + + jal _get_next_ready_thread + mv s1,a0 + sd s1,_kernel_offset_to_current(s0) # _kernel.current = _get_next_ready_thread() + addi tp,s1,_thread_offset_to_callee_saved # tp = &next_thread->callee_saved + + ld a0,_callee_saved_offset_to_key(tp) # a0 = callee_saved.key + jal _arch_irq_unlock # _arch_irq_unlock(callee_saved.key) + + _restore_context(tp) + ld t4,_callee_saved_offset_to_preemptive(tp) + bnez t4,__swap_preemptive +__swap_cooperative: + ret +__swap_preemptive: + ld t4,COOP_REG_MEPC(tp) + jalr t4 + +## +# _IsrWrapper(int idx, void *) +# a0 store IRQ index, +# a1 equals NULL +# +.globl _IsrWrapper +_IsrWrapper: + addi sp,sp,-32 + sd ra,0(sp) + sd s0,8(sp) + sd s1,16(sp) + sd s2,24(sp) + + # Grab a reference to _kernel in r10 so we can determine the + # current irq stack pointer + # + la a1,_kernel + + # Stash a copy of thread's sp in r12 so that we can put it on the IRQ + # stack + # + mv a2,sp + + # Switch to interrupt stack + ld sp,_kernel_offset_to_irq_stack(a1) + + # Store thread stack pointer onto IRQ stack + addi sp,sp,-8 + sd a2,0(sp) + + call run_isr_handler + + ld sp,0(sp) + + # Check reschedule condition + jal _get_next_ready_thread + beqz a0,_IsrExit_ending # _get_next_ready_thread() == 0 goto ending + + ## Do not reschedule coop threads (threads that have negative prio) + ld s1, _thread_offset_to_prio(a0) + blt s1,zero,_IsrExit_ending + + ## Do not reschedule if scheduler is locked + ld s1, _thread_offset_to_sched_locked(a0) + bne s1,zero,_IsrExit_ending + + ## Call into the kernel to see if a scheduling decision is necessary + mv s1,a0 # s1 = next_thread + jal _is_next_thread_current + bne a0,zero,_IsrExit_ending + + ## Flag current thread that it was switched preemptively + la s0, _kernel + ld s0,_kernel_offset_to_current(s0) # s0 = _kernel.current + addi s2,s0,_thread_offset_to_callee_saved # s2 = &next_thread->callee_saved + li a0,1 + sd a0,_callee_saved_offset_to_preemptive(s2) + + # Store IRQ key + jal _arch_irq_lock_state # a0 = _arch_irq_lock_state() + sd a0,_callee_saved_offset_to_key(s2) + + ## + # Switch to the new thread. + # + addi tp,s1,_thread_offset_to_callee_saved # tp = &next_thread->callee_saved + + ld a0,_callee_saved_offset_to_key(tp) # a0 = callee_saved.key + jal _arch_irq_unlock # _arch_irq_unlock(callee_saved.key) + + ld t4,_callee_saved_offset_to_preemptive(tp) + bnez t4,_IsrExit_ending + + ## Next thread was switched cooperative so,set MEPC to ra + ld a0,COOP_REG_RA(tp) + sd a0,COOP_REG_MEPC(tp) + + +_IsrExit_ending: + ld s2,24(sp) + ld s1,16(sp) + ld s0,8(sp) + ld ra,0(sp) + addi sp,sp,32 + ret diff --git a/arch/riscv64/core/swap_macros.h b/arch/riscv64/core/swap_macros.h new file mode 100644 index 0000000..f520918 --- /dev/null +++ b/arch/riscv64/core/swap_macros.h @@ -0,0 +1,159 @@ +/* swap_macros.h - helper macros for context switch */ + +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SWAP_MACROS__H_ +#define _SWAP_MACROS__H_ + +#define tNANO_FIBER_OFFSET 0 +#define tNANO_TASK_OFFSET 8 +#define tNANO_CURRENT_OFFSET 16 + +#define _kernel_offset_to_irq_stack 8 +#define _kernel_offset_to_current 16 + +#define _timeout_sizeof 48 +#define _thread_offset_to_prio 24 +#define _thread_offset_to_sched_locked 32 +#define _thread_offset_to_callee_saved 96 //_thread_base_sizeof+caller_saved + +#define _callee_saved_offset_to_key 256 //(32*sizeof(uint64_t)) +#define _callee_saved_offset_to_retval 264 //(33*sizeof(uint64_t)) +#define _callee_saved_offset_to_preemptive 272 //(34*sizeof(uint64_t)) + +#define TCS_LINK_OFFSET 0 +#define TCS_FLAGS_OFFSET 8 +#define TCS_INTLOCK_OFFSET 16 +#define TCS_COOP_REGS_OFFSET 24 + +/** + * Saved by callee function registers: + * s0..s11, sp, tp + */ + +/** Return address */ +#define COOP_REG_RA 0//(0*sizeof(uint64_t)) +/** Saved registers */ +#define COOP_REG_S0 8//(1*sizeof(uint64_t)) +#define COOP_REG_S1 16//(2*sizeof(uint64_t)) +#define COOP_REG_S2 24//(3*sizeof(uint64_t)) +#define COOP_REG_S3 32//(4*sizeof(uint64_t)) +#define COOP_REG_S4 40//(5*sizeof(uint64_t)) +#define COOP_REG_S5 48//(6*sizeof(uint64_t)) +#define COOP_REG_S6 56//(7*sizeof(uint64_t)) +#define COOP_REG_S7 64//(8*sizeof(uint64_t)) +#define COOP_REG_S8 72//(9*sizeof(uint64_t)) +#define COOP_REG_S9 80//(10*sizeof(uint64_t)) +#define COOP_REG_S10 88//(11*sizeof(uint64_t)) +#define COOP_REG_S11 96//(12*sizeof(uint64_t)) +/** Stack pointer */ +#define COOP_REG_SP 104//(13*sizeof(uint64_t)) +/** Thread pointer */ +#define COOP_REG_TP 112//(14*sizeof(uint64_t)) +#define COOP_REG_MEPC COOP_REG_TP//(14*sizeof(uint64_t)) +/** Return values */ +#define COOP_REG_V0 120//(15*sizeof(uint64_t)) +#define COOP_REG_V1 128//(16*sizeof(uint64_t)) +/** Function Arguments */ +#define COOP_REG_A0 136//(17*sizeof(uint64_t)) +#define COOP_REG_A1 144//(18*sizeof(uint64_t)) +#define COOP_REG_A2 152//(19*sizeof(uint64_t)) +#define COOP_REG_A3 160//(20*sizeof(uint64_t)) +#define COOP_REG_A4 168//(21*sizeof(uint64_t)) +#define COOP_REG_A5 176//(22*sizeof(uint64_t)) +#define COOP_REG_A6 184//(23*sizeof(uint64_t)) +#define COOP_REG_A7 192//(24*sizeof(uint64_t)) +/** Temporary registers */ +#define COOP_REG_T0 200//(25*sizeof(uint64_t)) +#define COOP_REG_T1 208//(26*sizeof(uint64_t)) +#define COOP_REG_T2 216//(27*sizeof(uint64_t)) +#define COOP_REG_T3 224//(28*sizeof(uint64_t)) +#define COOP_REG_T4 232//(29*sizeof(uint64_t)) +/** Global pointer */ +#define COOP_REG_GP 240//(30*sizeof(uint64_t)) + +#define COOP_REGS_TOTAL 32 +#define COOP_STACKFRAME_SIZE (COOP_REGS_TOTAL*sizeof(uint64_t)) + + +#define _save_context(TO) \ + sd ra, COOP_REG_RA(TO); \ + sd s0, COOP_REG_S0(TO); \ + sd s1, COOP_REG_S1(TO); \ + sd s2, COOP_REG_S2(TO); \ + sd s3, COOP_REG_S3(TO); \ + sd s4, COOP_REG_S4(TO); \ + sd s5, COOP_REG_S5(TO); \ + sd s6, COOP_REG_S6(TO); \ + sd s7, COOP_REG_S7(TO); \ + sd s8, COOP_REG_S8(TO); \ + sd s9, COOP_REG_S9(TO); \ + sd s10, COOP_REG_S10(TO); \ + sd s11, COOP_REG_S11(TO); \ + sd sp, COOP_REG_SP(TO); \ + sd x16, COOP_REG_V0(TO); \ + sd x17, COOP_REG_V1(TO); \ + sd a0, COOP_REG_A0(TO); \ + sd a1, COOP_REG_A1(TO); \ + sd a2, COOP_REG_A2(TO); \ + sd a3, COOP_REG_A3(TO); \ + sd a4, COOP_REG_A4(TO); \ + sd a5, COOP_REG_A5(TO); \ + sd a6, COOP_REG_A6(TO); \ + sd a7, COOP_REG_A7(TO); \ + sd t0, COOP_REG_T0(TO); \ + sd t1, COOP_REG_T1(TO); \ + sd t2, COOP_REG_T2(TO); \ + sd t3, COOP_REG_T3(TO); \ + sd t4, COOP_REG_T4(TO); \ + sd gp, COOP_REG_GP(TO); + + +#define _restore_context(FROM) \ + ld ra, COOP_REG_RA(FROM); \ + ld s0, COOP_REG_S0(FROM); \ + ld s1, COOP_REG_S1(FROM); \ + ld s2, COOP_REG_S2(FROM); \ + ld s3, COOP_REG_S3(FROM); \ + ld s4, COOP_REG_S4(FROM); \ + ld s5, COOP_REG_S5(FROM); \ + ld s6, COOP_REG_S6(FROM); \ + ld s7, COOP_REG_S7(FROM); \ + ld s8, COOP_REG_S8(FROM); \ + ld s9, COOP_REG_S9(FROM); \ + ld s10, COOP_REG_S10(FROM); \ + ld s11, COOP_REG_S11(FROM); \ + ld sp, COOP_REG_SP(FROM); \ + ld x16, COOP_REG_V0(FROM); \ + ld x17, COOP_REG_V1(FROM); \ + ld a0, COOP_REG_A0(FROM); \ + ld a1, COOP_REG_A1(FROM); \ + ld a2, COOP_REG_A2(FROM); \ + ld a3, COOP_REG_A3(FROM); \ + ld a4, COOP_REG_A4(FROM); \ + ld a5, COOP_REG_A5(FROM); \ + ld a6, COOP_REG_A6(FROM); \ + ld a7, COOP_REG_A7(FROM); \ + ld t0, COOP_REG_T0(FROM); \ + ld t1, COOP_REG_T1(FROM); \ + ld t2, COOP_REG_T2(FROM); \ + ld t3, COOP_REG_T3(FROM); \ + ld t4, COOP_REG_T4(FROM); \ + ld gp, COOP_REG_GP(FROM); + + +#endif /* _SWAP_MACROS__H_ */ diff --git a/arch/riscv64/defconfig b/arch/riscv64/defconfig new file mode 100644 index 0000000..e69de29 diff --git a/arch/riscv64/include/kernel_arch_data.h b/arch/riscv64/include/kernel_arch_data.h new file mode 100644 index 0000000..ef8242b --- /dev/null +++ b/arch/riscv64/include/kernel_arch_data.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Gnss Sensor Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __KERNEL_ARCH__DATA_H__ +#define __KERNEL_ARCH__DATA_H__ + +#include <stdint.h> +#include <toolchain.h> +#include <sections.h> +#include <arch/cpu.h> + +#ifndef _ASMLANGUAGE +#include <kernel.h> +#include <nano_internal.h> +#include <stdint.h> +#include <misc/util.h> +#include <misc/dlist.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct _caller_saved { + /* + * Nothing here, the exception code puts all the caller-saved + * registers onto the stack. + */ + int empty_; +}; + +typedef struct _caller_saved _caller_saved_t; + +struct _callee_saved { + uint64_t r[32]; + /* IRQ status before irq_lock() and call to _Swap() */ + uint64_t key; + + /* Return value of _Swap() */ + uint64_t retval; + + /* I actually do not understand where preemptive tasks switch occurs, + * so use this flag stores the latest method of switch 0=coop; 1=preemp. + * It allows properly switch cooperative/preemtive threads independently + * of its priority + */ + uint64_t preemptive; +}; + +typedef struct _callee_saved _callee_saved_t; + +struct _thread_arch { + /* nothing for now */ + unsigned int empty_; +}; + +typedef struct _thread_arch _thread_arch_t; + +struct _kernel_arch { + /* nothing for now */ + int empty_; +}; + +typedef struct _kernel_arch _kernel_arch_t; + + +#ifdef __cplusplus +} +#endif + +#endif /* __KERNEL_ARCH__DATA_H__ */ diff --git a/arch/riscv64/include/kernel_arch_func.h b/arch/riscv64/include/kernel_arch_func.h new file mode 100644 index 0000000..55046ab --- /dev/null +++ b/arch/riscv64/include/kernel_arch_func.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Gnss Sensor Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Private kernel definitions + * + * This file contains private kernel function/macro definitions and various + * other definitions for the Nios II processor architecture. + * + * This file is also included by assembly language files which must #define + * _ASMLANGUAGE before including this header file. Note that kernel + * assembly source files obtains structure offset values via "absolute + * symbols" in the offsets.o module. + */ + +#ifndef _kernel_arch_func__h_ +#define _kernel_arch_func__h_ + +#include <stdint.h> +#include <toolchain.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE + +void nano_cpu_idle(void); +void nano_cpu_atomic_idle(unsigned int key); + +extern char _interrupt_stack[]; + +static ALWAYS_INLINE void nanoArchInit(void) +{ + _kernel.irq_stack = _interrupt_stack + CONFIG_ISR_STACK_SIZE; +} + +static ALWAYS_INLINE void +_set_thread_return_value(struct k_thread *thread, unsigned int value) +{ + thread->callee_saved.retval = value; +} + +static inline void _IntLibInit(void) +{ + /* No special initialization of the interrupt subsystem required */ +} + +FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason, + const NANO_ESF * esf); + +#define _is_in_isr() (_kernel.nested != 0) + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* _kernel_arch_func__h_ */ diff --git a/arch/riscv64/include/kernel_event_logger_arch.h b/arch/riscv64/include/kernel_event_logger_arch.h new file mode 100644 index 0000000..b6b8e67 --- /dev/null +++ b/arch/riscv64/include/kernel_event_logger_arch.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Kernel event logger support for ARM + */ + +#ifndef __KERNEL_EVENT_LOGGER_ARCH_H__ +#define __KERNEL_EVENT_LOGGER_ARCH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get the identification of the current interrupt. + * + * This routine obtain the key of the interrupt that is currently processed + * if it is called from a ISR context. + * + * @return The key of the interrupt that is currently being processed. + */ +int _sys_current_irq_key_get(void) +{ + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __KERNEL_EVENT_LOGGER_ARCH_H__ */ diff --git a/arch/riscv64/include/memaccess.h b/arch/riscv64/include/memaccess.h new file mode 100644 index 0000000..564762b --- /dev/null +++ b/arch/riscv64/include/memaccess.h @@ -0,0 +1,16 @@ +/** + * @file Access methods declaration to the memory mapped devices. + */ + +#ifndef _RISCV_CORE_MEMACCESS_H_ +#define _RISCV_CORE_MEMACCESS_H_ + +#include <stdint.h> + +extern uint16_t READ16(volatile uint16_t *addr); +extern uint32_t READ32(volatile uint32_t *addr); +extern uint64_t READ64(volatile uint64_t *addr); +extern void WRITE32(volatile uint32_t *addr, uint32_t val); +extern void WRITE64(volatile uint64_t *addr, uint64_t val); + +#endif // _RISCV_CORE_MEMACCESS_H_ diff --git a/arch/riscv64/include/offsets_short_arch.h b/arch/riscv64/include/offsets_short_arch.h new file mode 100644 index 0000000..d28ff64 --- /dev/null +++ b/arch/riscv64/include/offsets_short_arch.h @@ -0,0 +1,4 @@ +#ifndef __OFFSETS_SHORT_ARCH_H__ +#define __OFFSETS_SHORT_ARCH_H__ + +#endif // __OFFSETS_SHORT_ARCH_H__ diff --git a/arch/riscv64/soc/riscv_gnss/Kbuild b/arch/riscv64/soc/riscv_gnss/Kbuild new file mode 100644 index 0000000..d035736 --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/Kbuild @@ -0,0 +1,8 @@ +ccflags-y +=-I$(srctree)/arch/riscv64/include +ccflags-y +=-I$(srctree)/include +ccflags-y +=-I$(srctree)/include/drivers +ccflags-y +=-I$(srctree)/drivers + +asflags-y := ${ccflags-y} + +obj-y += soc.o diff --git a/arch/riscv64/soc/riscv_gnss/Kconfig.defconfig b/arch/riscv64/soc/riscv_gnss/Kconfig.defconfig new file mode 100644 index 0000000..31da98c --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/Kconfig.defconfig @@ -0,0 +1,33 @@ +# Kconfig - Atmel SAM3 family processor configuration options + +# +# Copyright (c) 2016 Intel Corporation. +# Copyright (c) 2014-2015 Wind River Systems, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if SOC_RISCV_GNSS + +config SOC + default riscv_gnss + +config NUM_IRQS + int + default 6 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 40000000 + +endif # SOC_RISCV_GNSS diff --git a/arch/riscv64/soc/riscv_gnss/Kconfig.soc b/arch/riscv64/soc/riscv_gnss/Kconfig.soc new file mode 100644 index 0000000..84626cb --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/Kconfig.soc @@ -0,0 +1,5 @@ + +config SOC_RISCV_GNSS + bool "RISC-V SOC by Gnss Sensor Ltd" + help + Synthezable SoC based on open ISA RISC-V. diff --git a/arch/riscv64/soc/riscv_gnss/Makefile b/arch/riscv64/soc/riscv_gnss/Makefile new file mode 100644 index 0000000..3caaddb --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/Makefile @@ -0,0 +1,6 @@ + +arch-cflags += $(call cc-option,-mthumb -march=rv64ima -Wunused-function -Wint-to-pointer-cast) + +KBUILD_AFLAGS += $(arch-cflags) +KBUILD_CXXFLAGS += $(arch-cflags) +KBUILD_CFLAGS += $(arch-cflags) diff --git a/arch/riscv64/soc/riscv_gnss/linker.ld b/arch/riscv64/soc/riscv_gnss/linker.ld new file mode 100644 index 0000000..6a68292 --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/linker.ld @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014-2015 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * generate a symbol to mark the start of the device initialization objects for + * the specified level, then link all of those objects (sorted by priority); + * ensure the objects aren't discarded if there is no direct reference to them + */ + +#include <arch/riscv64/linker.ld> + diff --git a/arch/riscv64/soc/riscv_gnss/soc.c b/arch/riscv64/soc/riscv_gnss/soc.c new file mode 100644 index 0000000..72639bd --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/soc.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2016, GNSS Sensor Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief System/hardware module for GNSS RISC-V family processor + * + * This module provides routines to initialize and support board-level hardware + * for the GNSS RISC-V family processor. + */ + +#include <stdint.h> +#include <errno.h> +#include <nanokernel.h> +#include <device.h> +#include <init.h> +#include <soc.h> +#include <misc/printk.h> +#include <misc/shell.h> +#include <sw_isr_table.h> +#include <memaccess.h> + +#define SHELL_SOC "soc" + +extern void _IsrWrapper(int idx, void *arg); + +typedef union DescriptorTableType { + union DescriptorItemType { + MasterConfigType mst; + SlaveConfigType slv; + } *item; + uint8_t *buf; +} DescriptorTableType; + +const char *const VENDOR_NAME = "GNSS Sensor Ltd."; + +const char *const MST_DID_EMPTY_NAME = "Empty master slot"; +const char *const SLV_DID_EMPTY_NAME = "Empty slave slot"; + +const char *const UNKOWN_ID_NAME = "Unknown"; + +static const char *const GNSS_SENSOR_MST_DEVICE_NAMES[] = { + "Rocket Cached TileLink", // 0x500 + "Rocket Uncached TileLink", // 0x501 + "Gaisler Ethernet MAC with DMA", // 0x502 + "Gaisler Ethernet EDCL with DMA", // 0x503 + "Reserved", // 0x504 + "RISC-V River CPU", // 0x505 +}; + +static const char *const GNSS_SENSOR_SLV_DEVICE_NAMES[] = { + "GNSS Engine stub", // 0x68 + "Reserved", // 0x69 + "Reserved", // 0x6a + "Reserved", // 0x6b + "Reserved", // 0x6c + "Reserved", // 0x6d + "Reserved", // 0x6e + "Reserved", // 0x6f + "Reserved", // 0x70 + "Boot ROM", // 0x71 + "FW Image ROM", // 0x72 + "Internal SRAM", // 0x73 + "Plug'n'Play support", // 0x74 + "SD Controller", // 0x75 + "Generic GPIO", // 0x76 + "RF front-end controller", // 0x77 + "GNSS Engine", // 0x78 + "GPS FSE", // 0x79 + "Generic UART", // 0x7a + "Accelerometer", // 0x7b + "Gyroscope", // 0x7c + "Interrupt Controller", // 0x7d + "Reserved", // 0x7e + "Ethernet MAC", // 0x7f + "Debug Support Unit (DSU)", // 0x80 + "GP Timers" // 0x81 +}; + +/** + * @brief Get technology name + */ +const char *const get_tech_name(uint32_t tech) +{ + switch (tech) { + case TECH_INFERRED: return "inferred"; + case TECH_VIRTEX6: return "Virtex6"; + case TECH_KINTEX7: return "Kintex7"; + default:; + } + return "unknown"; +} + +/** + * @brief Get device Vendor name by its ID + */ +static const char *get_vendor_name(uint16_t vid) +{ + if (vid != VENDOR_GNSSSENSOR) { + return UNKOWN_ID_NAME; + } + return VENDOR_NAME; +} + +/** + * @brief Get device Name by Vendor ID and Device ID + */ +static const char *get_device_name(uint16_t vid, uint16_t did) +{ + if (vid != VENDOR_GNSSSENSOR) { + return UNKOWN_ID_NAME; + } + if (did == MST_DID_EMPTY) { + return MST_DID_EMPTY_NAME; + } + if (did == SLV_DID_EMPTY) { + return SLV_DID_EMPTY_NAME; + } + if (did >= GNSSSENSOR_ENGINE_STUB && did <= GNSSSENSOR_GPTIMERS) { + return GNSS_SENSOR_SLV_DEVICE_NAMES[did - GNSSSENSOR_ENGINE_STUB]; + } + if (did >= RISCV_CACHED_TILELINK && did <= RISCV_RIVER_CPU) { + return GNSS_SENSOR_MST_DEVICE_NAMES[did - RISCV_CACHED_TILELINK]; + } + return UNKOWN_ID_NAME; +} + +/** + * @brief Print Plug'n'Play information + * + * This function reads information from the PNP slave device that is mapped + * into hardcoded address __PNP (0xFFFFF000). + */ +static int shell_cmd_soc_info(int argc, char *argv[]) +{ + printk("RISC-V synthesizable SoC platform available for download at:\n"); + printk(" https://github.com/sergeykhbr/riscv_vhdl\n\n"); + printk("Author: Sergey Khabarov - sergeykhbr@gmail.com\n"); + return 0; +} + +/** + * @brief Print Plug'n'Play information + * + * This function reads information from the PNP slave device that is mapped + * into hardcoded address __PNP (0xFFFFF000). + */ +static int shell_cmd_soc_pnp(int argc, char *argv[]) +{ + uint32_t slaves_total, tech, hwid; + uint16_t vid, did; + adr_type xaddr, xmask, xsize; + volatile uint32_t *iter; + MasterDescrWord mcfg; + int mst_cnt=0, slv_cnt=0; + + tech = READ32(&__PNP->tech); + slaves_total = (tech >> 8) & 0xff; + printk("# RISC-V: Rocket-Chip demonstration design\n"); + hwid = READ32(&__PNP->hwid); + printk("# HW id: 0x%x\n", hwid); + hwid = READ32(&__PNP->fwid); + printk("# FW id: 0x%x\n", hwid); + printk("# Target technology: %s\n", get_tech_name(tech & 0xFF)); + + iter = (volatile uint32_t *)__PNP->cfg_table; + mcfg.val = READ32(iter); + while (mcfg.bits.descrtype != PNP_CFG_TYPE_INVALID) { + if (mcfg.bits.descrtype == PNP_CFG_TYPE_MASTER) { + MasterConfigType *pmst = (MasterConfigType *)iter; + vid = READ16(&pmst->vid); + did = READ16(&pmst->did); + printk("# AXI4: mst%d: %s %s\n", mst_cnt++, + get_vendor_name(vid), get_device_name(vid, did)); + } else { + SlaveConfigType *pslv = (SlaveConfigType *)iter; + vid = READ16(&pslv->vid); + did = READ16(&pslv->did); + printk("# AXI4: slv%d: %s %s\n", slv_cnt++, + get_vendor_name(vid), get_device_name(vid, did)); + + xaddr = READ32(&pslv->xaddr); + xmask = READ32(&pslv->xmask); + xmask ^= 0xFFFFFFFF; + xsize = xmask + 1; + + + printk("# %x...%x, size = ", + (unsigned long)xaddr, (unsigned long)(xaddr + xmask)); + if (xsize < 1024) { + printk("%d bytes\n", (int)xsize); + } else if (xsize < 1024*1024) { + printk("%d KB\n", (int)(xsize >> 10)); + } else { + printk("%d MB\n", (int)(xsize >> 20)); + } + } + + iter = (volatile uint32_t *)((uint8_t *)iter + mcfg.bits.descrsize); + mcfg.val = READ32(iter); + } + return 0; +} + +/** + * @brief Check hardware target configuration is it inferred or not. + * + * inferred hardware target is used for RTL simulation of the whole SOC design. + */ +uint32_t soc_is_rtl_simulation() +{ + uint32_t tech = READ32(&__PNP->tech); + return (tech & 0xff) == TECH_INFERRED ? 1: 0; +} + +/** + * + * @brief perform basic hardware initialization + * + * Hardware initialized: + * - interrupt unit + * + * RETURNS: N/A + */ +static int riscv_gnss_soc_init(struct device *arg) +{ + ARG_UNUSED(arg); + WRITE64(&__IRQCTRL->isr_table, (uint64_t)_IsrWrapper); + WRITE32(&__IRQCTRL->irq_lock, 0); + return 0; +} + +struct shell_cmd soc_commands[] = { + { "info", shell_cmd_soc_info, "Show SoC RTL download link" }, + { "pnp", shell_cmd_soc_pnp, "Show Plug'n'Play information" }, + { NULL, NULL } +}; + +SYS_INIT(riscv_gnss_soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); + +SHELL_REGISTER(SHELL_SOC, soc_commands); diff --git a/arch/riscv64/soc/riscv_gnss/soc.h b/arch/riscv64/soc/riscv_gnss/soc.h new file mode 100644 index 0000000..9206f41 --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/soc.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016, GNSS Sensor Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SoC configuration macros for the GNSS Sensor Risc-V family processors. + */ + +#ifndef _RISCV_SOC_GNSS_H_ +#define _RISCV_SOC_GNSS_H_ + +#include <device.h> +#include <misc/util.h> +#include <drivers/rand32.h> + +#include "soc_registers.h" + +#define VENDOR_GNSSSENSOR 0x00F1 + +#define MST_DID_EMPTY 0x7755 +#define SLV_DID_EMPTY 0x5577 /// Dummy device + +/// Known master device IDs +#define RISCV_CACHED_TILELINK 0x0500 +#define RISCV_UNCACHED_TILELINK 0x0501 +#define GAISLER_ETH_MAC_MASTER 0x0502 +#define GAISLER_ETH_EDCL_MASTER 0x0503 +#define RISCV_RIVER_CPU 0x0505 +/// Known slave device IDs +#define GNSSSENSOR_BOOTROM 0x0071 /// Boot ROM Device ID +#define GNSSSENSOR_FWIMAGE 0x0072 /// FW ROM image Device ID +#define GNSSSENSOR_SRAM 0x0073 /// Internal SRAM block Device ID +#define GNSSSENSOR_PNP 0x0074 /// Configuration Registers Module Device ID provided by gnsslib +#define GNSSSENSOR_SPI_FLASH 0x0075 /// SD-card controller Device ID provided by gnsslib +#define GNSSSENSOR_GPIO 0x0076 /// General purpose IOs Device ID provided by gnsslib +#define GNSSSENSOR_RF_CONTROL 0x0077 /// RF front-end controller Device ID provided by gnsslib +#define GNSSSENSOR_ENGINE 0x0078 /// GNSS Engine Device ID provided by gnsslib +#define GNSSSENSOR_ENGINE_STUB 0x0068 /// GNSS Engine stub +#define GNSSSENSOR_FSE_V2 0x0079 /// Fast Search Engines Device ID provided by gnsslib +#define GNSSSENSOR_UART 0x007a /// rs-232 UART Device ID +#define GNSSSENSOR_ACCELEROMETER 0x007b /// Accelerometer Device ID provided by gnsslib +#define GNSSSENSOR_GYROSCOPE 0x007c /// Gyroscope Device ID provided by gnsslib +#define GNSSSENSOR_IRQCTRL 0x007d /// Interrupt controller +#define GNSSSENSOR_ETHMAC 0x007f +#define GNSSSENSOR_DSU 0x0080 +#define GNSSSENSOR_GPTIMERS 0x0081 + +#define PNP_CFG_TYPE_INVALID 0 +#define PNP_CFG_TYPE_MASTER 1 +#define PNP_CFG_TYPE_SLAVE 2 + +#define TECH_INFERRED 0 +#define TECH_VIRTEX6 36 +#define TECH_KINTEX7 49 + + + +#define ADDR_NASTI_SLAVE_FWIMAGE 0x00100000 +#define ADDR_NASTI_SLAVE_SRAM 0x10000000 +#define ADDR_NASTI_SLAVE_GPIO 0x80000000 +#define ADDR_NASTI_SLAVE_UART1 0x80001000 +#define ADDR_NASTI_SLAVE_IRQCTRL 0x80002000 +#define ADDR_NASTI_SLAVE_GNSSENGINE 0x80003000 +#define ADDR_NASTI_SLAVE_RFCTRL 0x80004000 +#define ADDR_NASTI_SLAVE_GPTIMERS 0x80005000 +#define ADDR_NASTI_SLAVE_FSEGPS 0x8000a000 +#define ADDR_NASTI_SLAVE_ETHMAC 0x80040000 +#define ADDR_NASTI_SLAVE_PNP 0xfffff000 + +/* Interrupts pins assignments */ +#define CFG_IRQ_UNUSED 0 +#define CFG_IRQ_UART1 1 +#define CFG_IRQ_ETH 2 +#define CFG_IRQ_SYS_TIMER 3 +#define CFG_IRQ_MISS_ACCESS 4 +#define CFG_IRQ_GNSS_ENGINE 5 + +/* Use this general purpose timer as a system timer */ +#define CFG_SYS_TIMER_IDX 0 + +/* PNP */ +#define PNP_CONFIG_DEFAULT_BYTES 16 + +/* uart configuration settings */ +#define UART_IRQ_FLAGS 0 // used in console driver + + +#ifndef _ASMLANGUAGE + +typedef uint64_t adr_type; + + +typedef void (*IRQ_HANDLER)(void *arg); + + +#define __PNP ((volatile struct pnp_map *)ADDR_NASTI_SLAVE_PNP) +/** @todo remove hardcoded addresses except __PNP. */ +#define __UART1 ((volatile struct uart_map *)ADDR_NASTI_SLAVE_UART1) +#define __IRQCTRL ((volatile struct irqctrl_map *)ADDR_NASTI_SLAVE_IRQCTRL) +#define __TIMERS ((volatile struct gptimers_map *)ADDR_NASTI_SLAVE_GPTIMERS) + +/** + * @brief Print Plug'n'Play information + * + * Each devices in a SOC implements sideband signals that are connected to + * PNP module. These signals provide such information as Vendor/Device IDs, + * memory address and allocated memory range. + */ +extern void soc_print_pnp(); + +/** + * @brief Check hardware target configuration is it inferred or not. + * + * inferred hardware target is used for RTL simulation of the whole SOC design. + */ +extern uint32_t soc_is_rtl_simulation(); + +#endif /* !_ASMLANGUAGE */ + +#endif /* _RISCV_SOC_GNSS_H_ */ diff --git a/arch/riscv64/soc/riscv_gnss/soc_registers.h b/arch/riscv64/soc/riscv_gnss/soc_registers.h new file mode 100644 index 0000000..4bbb4d6 --- /dev/null +++ b/arch/riscv64/soc/riscv_gnss/soc_registers.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, GNSS Sensor Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SoC configuration macros for the Atmel SAM3 family processors. + * + * Refer to the datasheet for more information about these registers. + */ + +#ifndef _RISCV_GNSS_SOC_REGS_H_ +#define _RISCV_GNSS_SOC_REGS_H_ + +typedef struct MasterDescrWordBits { + uint32_t descrsize : 8; + uint32_t descrtype : 2; + uint32_t rsrv : 14; + uint32_t master_idx : 8; +} MasterDescrWordBits; + +typedef union MasterDescrWord { + MasterDescrWordBits bits; + uint32_t val; +} MasterDescrWord; + +typedef struct MasterConfigType { + MasterDescrWord descr; + uint16_t did; + uint16_t vid; +} MasterConfigType; + +typedef struct SlaveDescrWordBits { + uint32_t descrsize : 8; + uint32_t descrtype : 2; + uint32_t bar_total : 2; + uint32_t rsrv1 : 4; + uint32_t irq_idx : 8; + uint32_t rsrv2 : 8; +} SlaveDescrWordBits; + +typedef union SlaveDescrWord { + SlaveDescrWordBits bits; + uint32_t val; +} SlaveDescrWord; + +typedef struct SlaveConfigType { + SlaveDescrWord descr; + uint16_t did; + uint16_t vid; + uint32_t xmask; + uint32_t xaddr; +} SlaveConfigType; + +typedef struct pnp_map { + volatile uint32_t hwid; /// Read only HW ID + volatile uint32_t fwid; /// Read/Write Firmware ID + volatile uint32_t tech; /// Read only technology index + volatile uint32_t rsrv1; /// + volatile uint64_t idt; /// + volatile uint64_t malloc_addr; /// debuggind memalloc pointer + volatile uint64_t malloc_size; /// debugging memalloc size + volatile uint64_t fwdbg1; /// FW debug register + volatile uint64_t rsrv[2]; + uint8_t cfg_table[(1 << 12) - 0x40]; /// 0xfffff040: RO: PNP configuration +} pnp_map; + +typedef struct uart_map { + volatile uint32_t status; + volatile uint32_t scaler; + uint32_t rsrv[2]; + volatile uint32_t data; +} uart_map; + + +typedef struct irqctrl_map { + volatile uint32_t irq_mask; // 0x00: [RW] 1=disable; 0=enable + volatile uint32_t irq_pending; // 0x04: [RW] + volatile uint32_t irq_clear; // 0x08: [WO] + volatile uint32_t irq_rise; // 0x0C: [WO] + volatile uint64_t isr_table; // 0x10: [RW] + volatile uint64_t dbg_cause; // 0x18: + volatile uint64_t dbg_epc; // 0x20: + volatile uint32_t irq_lock; // 0x28: interrupts wait while lock=1 + volatile uint32_t irq_cause_idx;// 0x2c: +} irqctrl_map; + + +typedef struct gptimer_type { + volatile uint32_t control; // [0] = count_ena; [1] = irq_ena + volatile uint32_t rsv1; + volatile uint64_t cur_value; + volatile uint64_t init_value; +} gptimer_type; + +typedef struct gptimers_map { + volatile uint64_t highcnt; + volatile uint32_t pending; + uint32_t rsv1[13]; + gptimer_type tmr[2]; +} gptimer_map; + +#endif /* _RISCV_GNSS_SOC_REGS_H_ */ diff --git a/boards/riscv64/riscv_gnss/Kconfig.board b/boards/riscv64/riscv_gnss/Kconfig.board new file mode 100644 index 0000000..f6662ef --- /dev/null +++ b/boards/riscv64/riscv_gnss/Kconfig.board @@ -0,0 +1,6 @@ + +config BOARD_RISCV_GNSS + bool "RISC-V based FPGA SoC" + depends on SOC_RISCV_GNSS + help + The RISC-v VHDL FPGA development boards diff --git a/boards/riscv64/riscv_gnss/Kconfig.defconfig b/boards/riscv64/riscv_gnss/Kconfig.defconfig new file mode 100644 index 0000000..8e55bc5 --- /dev/null +++ b/boards/riscv64/riscv_gnss/Kconfig.defconfig @@ -0,0 +1,22 @@ + +if BOARD_RISCV_GNSS + +config BOARD + default riscv_gnss + +config CONSOLE + def_bool y + +config UART_CONSOLE + def_bool y + +config UART_INTERRUPT_DRIVEN + def_bool y + +config CONSOLE_HANDLER_SHELL + def_bool y + +config STDOUT_CONSOLE + def_bool y + +endif # BOARD_RISCV_GNSS diff --git a/boards/riscv64/riscv_gnss/Makefile b/boards/riscv64/riscv_gnss/Makefile new file mode 100644 index 0000000..7414f8c --- /dev/null +++ b/boards/riscv64/riscv_gnss/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -I$(srctree)/include/drivers +ccflags-y += -I$(srctree)/drivers +asflags-y := ${ccflags-y} + +# Force kbuild to make empty built-in.o if necessary +obj- := dummy.o diff --git a/boards/riscv64/riscv_gnss/board.h b/boards/riscv64/riscv_gnss/board.h new file mode 100644 index 0000000..55029f6 --- /dev/null +++ b/boards/riscv64/riscv_gnss/board.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __INC_BOARD_H +#define __INC_BOARD_H + +#include <soc.h> + +#endif /* __INC_BOARD_H */ diff --git a/boards/riscv64/riscv_gnss/riscv_gnss_defconfig b/boards/riscv64/riscv_gnss/riscv_gnss_defconfig new file mode 100644 index 0000000..f5ac997 --- /dev/null +++ b/boards/riscv64/riscv_gnss/riscv_gnss_defconfig @@ -0,0 +1,39 @@ +CONFIG_RISCV64=y +CONFIG_SOC_RISCV_GNSS=y +CONFIG_BOARD_RISCV_GNSS=y +CONFIG_PRINTK=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_ENABLE_SHELL=y +xCONFIG_KERNEL_DEBUG=y +CONFIG_CONSOLE=y +CONFIG_EARLY_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_BOOT_BANNER=y +CONFIG_CONSOLE_HAS_DRIVER=y +CONFIG_CONSOLE_HANDLER=y +CONFIG_CONSOLE_HANDLER_SHELL=y +CONFIG_CONSOLE_HANDLER_SHELL_STACKSIZE=2000 +CONFIG_UART_CONSOLE=y +CONFIG_UART_CONSOLE_ON_DEV_NAME="UART_0" +CONFIG_NUM_COOP_PRIORITIES=16 +CONFIG_NUM_PREEMPT_PRIORITIES=15 +CONFIG_ISR_STACK_SIZE=2048 +CONFIG_PRIORITY_CEILING=0 +CONFIG_NUM_IRQS=6 +CONFIG_SYS_CLOCK_EXISTS=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=40000000 +CONFIG_SYS_CLOCK_TICKS_PER_SEC=200 +CONFIG_NANO_TIMEOUTS=y +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_PRIORITY=-1 +CONFIG_OFFLOAD_WORKQUEUE_STACK_SIZE=2048 +CONFIG_OFFLOAD_WORKQUEUE_PRIORITY=-1 +CONFIG_KERNEL_EVENT_LOGGER_BUFFER_SIZE=128 +CONFIG_MAIN_THREAD_PRIORITY=0 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_IDLE_STACK_SIZE=1024 +CONFIG_SYSTEM_CLOCK_INIT_PRIORITY=0 +CONFIG_KERNEL_INIT_PRIORITY_DEFAULT=40 +CONFIG_ERRNO=y +CONFIG_NUM_MBOX_ASYNC_MSGS=10 +CONFIG_NUM_PIPE_ASYNC_MSGS=10 diff --git a/drivers/console/shells/kernel_service.c b/drivers/console/shells/kernel_service.c index 30bf90d..80b96a6 100644 --- a/drivers/console/shells/kernel_service.c +++ b/drivers/console/shells/kernel_service.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <kernel_version.h> #include <misc/printk.h> #include <misc/shell.h> #include <init.h> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6bfd267..7b2d020 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -87,4 +87,6 @@ source "drivers/serial/Kconfig.cc32xx" source "drivers/serial/Kconfig.cmsdk_apb" +source "drivers/serial/Kconfig.gnss" + endif diff --git a/drivers/serial/Kconfig.gnss b/drivers/serial/Kconfig.gnss new file mode 100644 index 0000000..9465075 --- /dev/null +++ b/drivers/serial/Kconfig.gnss @@ -0,0 +1,7 @@ +menuconfig UART_RISCV_GNSS + bool "RISC-V GNSS board UART driver" + default y + help + Enable the UART driver, built in generic CPU designs generated from + VHDL. + diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 13d56c3..d3366be 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_UART_NRF5) += uart_nrf5.o obj-$(CONFIG_UART_ALTERA_JTAG) += uart_altera_jtag.o obj-$(CONFIG_UART_CC32XX) += uart_cc32xx.o obj-$(CONFIG_UART_CMSDK_APB) += uart_cmsdk_apb.o +obj-$(CONFIG_UART_RISCV_GNSS) += uart_gnss.o diff --git a/drivers/serial/uart_gnss.c b/drivers/serial/uart_gnss.c new file mode 100644 index 0000000..d39af24 --- /dev/null +++ b/drivers/serial/uart_gnss.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2016, GNSS Sensor Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <nanokernel.h> +#include <arch/cpu.h> +#include <sections.h> +#include <misc/__assert.h> +#include <stdint.h> +#include <misc/util.h> +#include <string.h> +#include <board.h> +#include <init.h> +#include <uart.h> +#include <irq.h> +#include <memaccess.h> + +#define UART_STATUS_TX_FULL 0x00000001 +#define UART_STATUS_TX_EMPTY 0x00000002 +#define UART_STATUS_RX_FULL 0x00000010 +#define UART_STATUS_RX_EMPTY 0x00000020 +#define UART_STATUS_ERR_PARITY 0x00000100 +#define UART_STATUS_ERR_STOPBIT 0x00000200 +#define UART_CONTROL_RX_IRQ_ENA 0x00002000 +#define UART_CONTROL_TX_IRQ_ENA 0x00004000 +#define UART_CONTROL_PARITY_ENA 0x00008000 + + +static struct uart_driver_api uart_gnss_driver_api; +/* Device data structure */ +struct uart_gnss_dev_data_t { + uint32_t baud_rate; /* Baud rate */ + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_t cb; /**< Callback function pointer */ +#endif +}; + +static struct uart_gnss_dev_data_t uart_gnss_dev_data_0 = { + 115200, // .baud_rate + NULL +}; + + +/** + * @brief Interrupt service routine. + * + * This simply calls the callback function, if one exists. + * + * @param arg Argument to ISR. + * + * @return N/A + */ +void uart_gnss_isr(void *arg) { + struct device *dev = (struct device *)arg; + struct uart_gnss_dev_data_t *data = + (struct uart_gnss_dev_data_t *)dev->driver_data; + if (data->cb) { + data->cb(dev); + } +} + +/* + * @brief Output a character to serial port + * + * @param dev UART device struct + * @param c character to output + */ +unsigned char uart_gnss_poll_out(struct device *dev, unsigned char c) +{ + /* wait for transmitter to ready to accept a character */ + uint32_t status = READ32(&__UART1->status); + while (status & UART_STATUS_TX_FULL) { + status = READ32(&__UART1->status); + } + WRITE32(&__UART1->data, c); + return c; +} + +static int uart_gnss_poll_in(struct device *dev, unsigned char *c) +{ + return -ENOTSUP; + +} + +/** + * @brief Read data from FIFO + * + * @param dev UART device struct + * @param rx_data Pointer to data container + * @param size Container size + * + * @return Number of bytes read + */ +static int uart_gnss_fifo_read(struct device *dev, uint8_t *rx_data, + const int size) +{ + uint32_t status = READ32(&__UART1->status); + uint8_t num_rx = 0; + + while ((size - num_rx > 0) && ((status & UART_STATUS_RX_EMPTY) == 0)) { + rx_data[num_rx++] = (uint8_t)READ32(&__UART1->data); + status = READ32(&__UART1->status); + } + + return num_rx; +} + +void uart_gnss_irq_tx_enable(struct device *dev) { + uint32_t status = READ32(&__UART1->status); + status |= UART_CONTROL_TX_IRQ_ENA; + WRITE32(&__UART1->status, status); +} + +void uart_gnss_irq_tx_disable(struct device *dev) { + uint32_t status = READ32(&__UART1->status); + status &= ~UART_CONTROL_TX_IRQ_ENA; + WRITE32(&__UART1->status, status); +} + +void uart_gnss_irq_rx_enable(struct device *dev) { + uint32_t status = READ32(&__UART1->status); + status |= UART_CONTROL_RX_IRQ_ENA; + WRITE32(&__UART1->status, status); +} + +void uart_gnss_irq_rx_disable(struct device *dev) { + uint32_t status = READ32(&__UART1->status); + status &= ~UART_CONTROL_RX_IRQ_ENA; + WRITE32(&__UART1->status, status); +} + +int uart_gnss_irq_tx_empty(struct device *dev) { + uint32_t status = READ32(&__UART1->status); + return ((status & UART_STATUS_TX_EMPTY) ? 1: 0); +} + +/** + * @brief Check if Rx IRQ has been raised + * + * @param dev UART device struct + * + * @return 1 if an IRQ is ready, 0 otherwise + */ +static int uart_gnss_irq_rx_ready(struct device *dev) +{ + uint32_t status = READ32(&__UART1->status); + + return ((status & UART_STATUS_RX_EMPTY) ? 0: 1); +} + + +/** + * @brief Check if Tx or Rx IRQ is pending + * + * @param dev UART device struct + * + * @return 1 if a Tx or Rx IRQ is pending, 0 otherwise + */ +static int uart_gnss_irq_is_pending(struct device *dev) +{ + /* Look only at Tx and Rx data interrupt flags */ + return uart_gnss_irq_rx_ready(dev); +} + + +/** + * @brief Update IRQ status + * + * @param dev UART device struct + * + * @return Always 1 + */ +static int uart_gnss_irq_update(struct device *dev) +{ + return 1; +} + +/** + * @brief Set the callback function pointer for IRQ. + * + * @param dev UART device struct + * @param cb Callback function pointer. + * + * @return N/A + */ + static void uart_gnss_irq_callback_set(struct device *dev, + uart_irq_callback_t cb) +{ + struct uart_gnss_dev_data_t * const dev_data = dev->driver_data; + dev_data->cb = cb; +} + +static struct uart_driver_api uart_gnss_driver_api = { + uart_gnss_poll_in, // poll_in + uart_gnss_poll_out, // poll_out + NULL,//int (*err_check)(struct device *dev); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + NULL,//int (*fifo_fill)(struct device *dev, const uint8_t *tx_data, int len); + uart_gnss_fifo_read, + uart_gnss_irq_tx_enable, + uart_gnss_irq_tx_disable, + NULL,//int (*irq_tx_ready)(struct device *dev); + uart_gnss_irq_rx_enable, + uart_gnss_irq_rx_disable, + uart_gnss_irq_tx_empty, + uart_gnss_irq_rx_ready, + NULL,//void (*irq_err_enable)(struct device *dev); + NULL,//void (*irq_err_disable)(struct device *dev); + uart_gnss_irq_is_pending, + uart_gnss_irq_update, + uart_gnss_irq_callback_set, +#endif + +#ifdef CONFIG_UART_LINE_CTRL + NULL,//int (*line_ctrl_set)(struct device *dev, uint32_t ctrl, uint32_t val); +#endif + +#ifdef CONFIG_UART_DRV_CMD + NULL,//int (*drv_cmd)(struct device *dev, uint32_t cmd, uint32_t p); +#endif +}; + +/** + * @brief Initialize fake serial port + * + * @param dev UART device struct + * + * @return DEV_OK + */ +static int uart_gnss_init(struct device *dev) +{ + dev->driver_api = &uart_gnss_driver_api; + dev->driver_data = &uart_gnss_dev_data_0; + + // Speed-up RTL simulation avoidig long polling of the status register. + if (soc_is_rtl_simulation() != 0) { + WRITE32(&__UART1->scaler, 20); + } else { + WRITE32(&__UART1->scaler, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC/115200/2); + } + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_gnss_irq_rx_enable(dev); + IRQ_CONNECT(CFG_IRQ_UART1, CFG_IRQ_UART1, uart_gnss_isr, dev, UART_IRQ_FLAGS); + irq_enable(CFG_IRQ_UART1); +#endif + return 0; +} + + +DEVICE_INIT(uart_gnss0, "UART_0", &uart_gnss_init, + NULL, NULL, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 205407c..b2a1c54 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_LOAPIC_TIMER) += loapic_timer.o obj-$(CONFIG_ARCV2_TIMER) += arcv2_timer0.o obj-$(CONFIG_ALTERA_AVALON_TIMER) += altera_avalon_timer.o +obj-$(CONFIG_RISCV_SYSTIMER) += riscv_systimer.o _CORTEX_M_SYSTICK_AND_GDB_INFO_yy = y obj-$(CONFIG_CORTEX_M_SYSTICK) += cortex_m_systick.o diff --git a/drivers/timer/riscv_systimer.c b/drivers/timer/riscv_systimer.c new file mode 100644 index 0000000..469be9a --- /dev/null +++ b/drivers/timer/riscv_systimer.c @@ -0,0 +1,148 @@ +#include <nanokernel.h> +#include <arch/cpu.h> +#include <device.h> +#include <drivers/system_timer.h> +#include <soc.h> +#include <memaccess.h> + +/* running total of timer count */ +static uint32_t __noinit cycles_per_tick; +static uint32_t accumulated_cycle_count; + +#define GPTIMER_CONTROL_COUNT_ENA 0x1 +#define GPTIMER_CONTROL_IRQ_ENA 0x2 + +/** + * + * @brief Read the platform's timer hardware + * + * This routine returns the current time in terms of timer hardware clock + * cycles. + * + * @return up counter of elapsed clock cycles + * + * \INTERNAL WARNING + * If this routine is ever enhanced to return all 64 bits of the counter + * it will need to call _hpetMainCounterAtomic(). + */ + +uint32_t k_cycle_get_32(void) +{ + //return (uint32_t)READ64(&__TIMERS->tmr[CFG_SYS_TIMER_IDX].cur_value); + return (uint32_t)READ64(&__TIMERS->highcnt); +} + +uint64_t k_cycle_get_64(void) +{ + return READ64(&__TIMERS->highcnt); +} + +#if defined(CONFIG_SYSTEM_CLOCK_DISABLE) +/** + * + * @brief Stop announcing ticks into the kernel + * + * This routine disables timer interrupt generation and delivery. + * Note that the timer's counting cannot be stopped by software. + * + * @return N/A + */ +void sys_clock_disable(void) +{ + unsigned int key; /* interrupt lock level */ + uint32_t control; /* timer control register value */ + + key = irq_lock(); + + /* disable interrupt generation */ + + control = timer0_control_register_get(); + timer0_control_register_set(control & ~_ARC_V2_TMR_CTRL_IE); + + irq_unlock(key); + + /* disable interrupt in the interrupt controller */ + + irq_disable(CONFIG_ARCV2_TIMER0_INT_LVL); +} +#endif /* CONFIG_SYSTEM_CLOCK_DISABLE */ + + +#ifdef CONFIG_TICKLESS_IDLE +static INLINE void update_accumulated_count(void) +{ + accumulated_cycle_count += (_sys_idle_elapsed_ticks * cycles_per_tick); +} +#else /* CONFIG_TICKLESS_IDLE */ +static INLINE void update_accumulated_count(void) +{ + accumulated_cycle_count += cycles_per_tick; +} +#endif /* CONFIG_TICKLESS_IDLE */ + +/** + * + * @brief System clock periodic tick handler + * + * This routine handles the system clock periodic tick interrupt. It always + * announces one tick. + * + * @return N/A + */ +void _timer_int_handler(void *unused) +{ + ARG_UNUSED(unused); + + /* clear the interrupt by writing 0 to IP bit of the control register */ + WRITE32(&__IRQCTRL->irq_clear, (1u << CFG_IRQ_SYS_TIMER)); + WRITE32(&__TIMERS->pending, 0); + +#if defined(CONFIG_TICKLESS_IDLE) + timer0_limit_register_set(cycles_per_tick - 1); + + _sys_idle_elapsed_ticks = 1; +#endif + + update_accumulated_count(); + _sys_clock_tick_announce(); +} + +/* + * @brief initialize the tickless idle feature + * + * This routine initializes the tickless idle feature. + * + * @return N/A + */ +static void tickless_idle_init(void) {} + +int _sys_clock_driver_init(struct device *device) { + ARG_UNUSED(device); + + /* ensure that the timer will not generate interrupts */ + WRITE32(&__TIMERS->tmr[CFG_SYS_TIMER_IDX].control, 0); + + sys_clock_hw_cycles_per_tick = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / + sys_clock_ticks_per_sec; + cycles_per_tick = sys_clock_hw_cycles_per_tick; + accumulated_cycle_count = 0; + + IRQ_CONNECT(CFG_IRQ_SYS_TIMER, 0, _timer_int_handler, 0, 0); + + /* + * Set the reload value to achieve the configured tick rate, enable the + * counter and interrupt generation. + */ + + tickless_idle_init(); + + WRITE64(&__TIMERS->tmr[CFG_SYS_TIMER_IDX].init_value, cycles_per_tick - 1); + WRITE32(&__TIMERS->tmr[CFG_SYS_TIMER_IDX].control, + GPTIMER_CONTROL_COUNT_ENA | GPTIMER_CONTROL_IRQ_ENA); + + /* everything has been configured: safe to enable the interrupt */ + + irq_enable(CFG_IRQ_SYS_TIMER); + + return 0; +} diff --git a/include/arch/cpu.h b/include/arch/cpu.h index 11f5b8e..513f101 100644 --- a/include/arch/cpu.h +++ b/include/arch/cpu.h @@ -27,6 +27,8 @@ #include <arch/arc/arch.h> #elif defined(CONFIG_NIOS2) #include <arch/nios2/arch.h> +#elif defined(CONFIG_RISCV64) +#include <arch/riscv64/arch.h> #else #error "Unknown Architecture" #endif diff --git a/include/arch/riscv64/arch.h b/include/arch/riscv64/arch.h new file mode 100644 index 0000000..1dc50b5 --- /dev/null +++ b/include/arch/riscv64/arch.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief RISC-V specific nanokernel interface header + * + * This header contains the ARC specific nanokernel interface. It is + * included by the nanokernel interface architecture-abstraction header + * (nanokernel/cpu.h) + */ + +#ifndef _RISCV_ARCH__H_ +#define _RISCV_ARCH__H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* APIs need to support non-byte addressible architectures */ + +#define OCTET_TO_SIZEOFUNIT(X) (X) +#define SIZEOFUNIT_TO_OCTET(X) (X) + +#include <sw_isr_table.h> +#include <stdint.h> +#include <toolchain.h> +#include "asm_inline.h" + +#define STACK_ALIGN 8 + +#ifdef _ASMLANGUAGE + + +#else // !_ASMLANGUAGE +/** interrupt/exception/error related definitions */ +typedef void (*NANO_EOI_GET_FUNC) (void *); + +/** + * @brief Disable all interrupts on the CPU (inline) + * + * This routine disables interrupts. It can be called from either interrupt, + * task or fiber level. This routine returns an architecture-dependent + * lock-out key representing the "interrupt disable state" prior to the call; + * this key can be passed to irq_unlock() to re-enable interrupts. + * + * The lock-out key should only be used as the argument to the irq_unlock() + * API. It should never be used to manually re-enable interrupts or to inspect + * or manipulate the contents of the source register. + * + * This function can be called recursively: it will return a key to return the + * state of interrupt locking to the previous level. + * + * WARNINGS + * Invoking a kernel routine with interrupts locked may result in + * interrupts being re-enabled for an unspecified period of time. If the + * called routine blocks, interrupts will be re-enabled while another + * thread executes, or while the system is idle. + * + * The "interrupt disable state" is an attribute of a thread. Thus, if a + * fiber or task disables interrupts and subsequently invokes a kernel + * routine that causes the calling thread to block, the interrupt + * disable state will be restored when the thread is later rescheduled + * for execution. + * + * @return An architecture-dependent lock-out key representing the + * "interrupt disable state" prior to the call. + * + */ + +extern unsigned int _arch_irq_lock(void); + + +/** + * + * @brief Enable all interrupts on the CPU (inline) + * + * This routine re-enables interrupts on the CPU. The @a key parameter + * is an architecture-dependent lock-out key that is returned by a previous + * invocation of irq_lock(). + * + * This routine can be called from either interrupt, task or fiber level. + * + * @return N/A + * + */ + +extern void _arch_irq_unlock(unsigned int key); + +/** + * + * @brief Read interrupts state on the CPU (inline) + * + * This routine check interrupts on the CPU. + * This routine can be called from either interrupt, task or fiber level. + * + * @return N/A + * + */ + +extern unsigned int _arch_irq_lock_state(); + +/** + * + * @brief Enable an interrupt line + * + * Clear possible pending interrupts on the line, and enable the interrupt + * line. After this call, the CPU will receive interrupts for the specified + * <irq>. + * + * @return N/A + */ +extern void _arch_irq_enable(unsigned int irq); + +/** + * + * @brief Disable an interrupt line + * + * Disable an interrupt line. After this call, the CPU will stop receiving + * interrupts for the specified <irq>. + * + * @return N/A + */ +extern void _arch_irq_disable(unsigned int irq); + +/** + * Configure a dynamic interrupt. + * + * @param irq IRQ line number + * @param priority Interrupt priority + * @param routine Interrupt service routine + * @param parameter ISR parameter + * @param flags Arch-specific IRQ configuration flags + * + * @return The vector assigned to this interrupt + */ +int _arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(void *parameter), void *parameter, + uint32_t flags); + + +/** + * Configure a static interrupt. + * + * All arguments must be computable by the compiler at build time; if this + * can't be done use irq_connect_dynamic() instead. + * + * Internally this function does a few things: + * + * 1. The enum statement has no effect but forces the compiler to only + * accept constant values for the irq_p parameter, very important as the + * numerical IRQ line is used to create a named section. + * + * 2. An instance of _IsrTableEntry is created containing the ISR and its + * parameter. If you look at how _sw_isr_table is created, each entry in the + * array is in its own section named by the IRQ line number. What we are doing + * here is to override one of the default entries (which points to the + * spurious IRQ handler) with what was supplied here. + * + * 3. The priority level for the interrupt is configured by a call to + * _irq_priority_set() + * + * @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 triggering options (currently unused) + * + * @return The vector assigned to this interrupt + */ +#define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ + _arch_irq_connect_dynamic(irq_p, priority_p, isr_p, isr_param_p, \ + flags_p) + + + +/** + * The NANO_SOFT_IRQ macro must be used as the value for the @a irq parameter + * to NANO_CPU_INT_REGSITER when connecting to an interrupt that does not + * correspond to any IRQ line (such as spurious vector or SW IRQ) + */ +#define NANO_SOFT_IRQ ((unsigned int) (-1)) + +/** + * @brief Nanokernel Exception Stack Frame + * + * A pointer to an "exception stack frame" (ESF) is passed as an argument + * to exception handlers registered via nanoCpuExcConnect(). As the system + * always operates at ring 0, only the EIP, CS and EFLAGS registers are pushed + * onto the stack when an exception occurs. + * + * The exception stack frame includes the volatile registers (EAX, ECX, and + * EDX) as well as the 5 non-volatile registers (EDI, ESI, EBX, EBP and ESP). + * Those registers are pushed onto the stack by _ExcEnt(). + */ + +typedef struct nanoEsf { + unsigned int esp; + unsigned int ebp; + unsigned int ebx; + unsigned int esi; + unsigned int edi; + unsigned int edx; + unsigned int eax; + unsigned int ecx; + unsigned int errorCode; + unsigned int eip; + unsigned int cs; + unsigned int eflags; +} NANO_ESF; + +/** + * @brief Nanokernel "interrupt stack frame" (ISF) + * + * An "interrupt stack frame" (ISF) as constructed by the processor + * and the interrupt wrapper function _IntEnt(). As the system always operates + * at ring 0, only the EIP, CS and EFLAGS registers are pushed onto the stack + * when an interrupt occurs. + * + * The interrupt stack frame includes the volatile registers EAX, ECX, and EDX + * pushed on the stack by _IntEnt(). + */ + +typedef struct nanoIsf { + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned int eip; + unsigned int cs; + unsigned int eflags; +} NANO_ISF; + + +/* + * Reason codes passed to both _NanoFatalErrorHandler() + * and _SysFatalErrorHandler(). + */ + +/** Unhandled exception/interrupt */ +#define _NANO_ERR_SPURIOUS_INT (0) +/** Page fault */ +#define _NANO_ERR_PAGE_FAULT (1) +/** General protection fault */ +#define _NANO_ERR_GEN_PROT_FAULT (2) +/** Invalid task exit */ +#define _NANO_ERR_INVALID_TASK_EXIT (3) +/** Stack corruption detected */ +#define _NANO_ERR_STACK_CHK_FAIL (4) +/** Kernel Allocation Failure */ +#define _NANO_ERR_ALLOCATION_FAIL (5) +/** Unhandled exception */ +#define _NANO_ERR_CPU_EXCEPTION (6) + + +#include <stddef.h> /* for size_t */ + +extern void nano_cpu_idle(void); + +/** Nanokernel provided routine to report any detected fatal error. */ +extern FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason, + const NANO_ESF * pEsf); +/** User provided routine to handle any detected fatal error post reporting. */ +extern FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason, + const NANO_ESF * pEsf); +/** Dummy ESF for fatal errors that would otherwise not have an ESF */ +extern const NANO_ESF _default_esf; + +#endif // _ASMLANGUAGE/!_ASMLANGUAGE + +#ifdef __cplusplus +} +#endif + + +#endif /* _RISCV_ARCH__H_ */ diff --git a/include/arch/riscv64/asm_inline.h b/include/arch/riscv64/asm_inline.h new file mode 100644 index 0000000..9724134 --- /dev/null +++ b/include/arch/riscv64/asm_inline.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ASM_INLINE_PUBLIC_H +#define _ASM_INLINE_PUBLIC_H + +/* + * The file must not be included directly + * Include kernel.h instead + */ + +#if defined(__GNUC__) +#include <arch/riscv64/asm_inline_gcc.h> +#elif defined _WIN32 +#include <arch/riscv64/asm_inline_cl.h> +#else +#include <arch/riscv64/asm_inline_other.h> +#endif + +#endif /* _ASM_INLINE_PUBLIC_H */ diff --git a/include/arch/riscv64/asm_inline_cl.h b/include/arch/riscv64/asm_inline_cl.h new file mode 100644 index 0000000..8a67967 --- /dev/null +++ b/include/arch/riscv64/asm_inline_cl.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Either public functions or macros or invoked by public functions */ + +#ifndef _ASM_INLINE_GCC_PUBLIC_CL_H +#define _ASM_INLINE_GCC_PUBLIC_CL_H + +#include <stdint.h> +#include <toolchain.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The file must not be included directly + * Include arch/cpu.h instead + */ + + +/** + * + * @brief find least significant bit set in a 32-bit word + * + * This routine finds the first bit set starting from the least significant bit + * in the argument passed in and returns the index of that bit. Bits are + * numbered starting at 1 from the least significant bit. A return value of + * zero indicates that the value passed is zero. + * + * @return least significant bit set, 0 if @a op is 0 + */ + +static ALWAYS_INLINE unsigned int find_lsb_set(uint32_t op) +{ + unsigned int ret = 1; + if (op == 0) { + return 0; + } + while ((op & 1) == 0) { + op >>= 1; + ret++; + } + return ret; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASM_INLINE_GCC_PUBLIC_CL_H */ diff --git a/include/arch/riscv64/asm_inline_gcc.h b/include/arch/riscv64/asm_inline_gcc.h new file mode 100644 index 0000000..11a5961 --- /dev/null +++ b/include/arch/riscv64/asm_inline_gcc.h @@ -0,0 +1,57 @@ +/* ARM Cortex-M GCC specific public inline assembler functions and macros */ + +/* + * Copyright (c) 2015, Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Either public functions or macros or invoked by public functions */ + +#ifndef _ASM_INLINE_GCC_PUBLIC_GCC_H +#define _ASM_INLINE_GCC_PUBLIC_GCC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The file must not be included directly + * Include arch/cpu.h instead + */ + +#ifdef _ASMLANGUAGE + +#else /* !_ASMLANGUAGE */ +#include <stdint.h> + +static ALWAYS_INLINE unsigned int find_lsb_set(uint32_t op) +{ + unsigned int ret = 1; + if (op == 0) { + return 0; + } + while ((op & 1) == 0) { + op >>= 1; + ret++; + } + return ret; +} + +#endif /* _ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ASM_INLINE_GCC_PUBLIC_GCC_H */ diff --git a/include/arch/riscv64/linker.ld b/include/arch/riscv64/linker.ld new file mode 100644 index 0000000..f4ee018 --- /dev/null +++ b/include/arch/riscv64/linker.ld @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014-2015 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief Common parts of the linker scripts for the RISC-V targets. + */ + +#define _LINKER +#define _ASMLANGUAGE + +#include <autoconf.h> +#include <sections.h> + +#include <linker-defs.h> +#include <linker-tool.h> + +/* physical address of RAM */ +#define ROMABLE_REGION SRAM +#define RAMABLE_REGION SRAM + +MEMORY { + SRAM (rwx) : ORIGIN = CONFIG_SRAM_BASE_ADDRESS, LENGTH = CONFIG_SRAM_SIZE*1k +} + +SECTIONS { + GROUP_START(ROMABLE_REGION) + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,ALIGN(8)) { + _image_rom_start = .; + _image_text_start = .; + + *(.text) + *(".text.*") + *(.gnu.linkonce.t.*) + + _image_text_end = .; + } GROUP_LINK_IN(ROMABLE_REGION) + +#include <linker/common-rom.ld> + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) { + *(.rodata) + *(".rodata.*") + *(.gnu.linkonce.r.*) + } GROUP_LINK_IN(ROMABLE_REGION) + + _image_rom_end = .; + __data_rom_start = ALIGN(4); /* XIP imaged DATA ROM start addr */ + + GROUP_END(ROMABLE_REGION) + + GROUP_START(RAMABLE_REGION) + + SECTION_PROLOGUE(_DATA_SECTION_NAME,,) { + + _image_ram_start = .; + __data_ram_start = .; + *(.data) + *(".data.*") + + + + KEEP(*(._sw_isr_table)) + KEEP(*(.isr_demux_table)) + + } GROUP_LINK_IN(RAMABLE_REGION) + +#include <linker/common-ram.ld> + + __data_ram_end = .; + + SECTION_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 = .; + *(.bss) + *(".bss.*") + COMMON_SYMBOLS + /* + * BSP clears this memory in words only and doesn't clear any + * potential left over bytes. + */ + __bss_end = ALIGN(4); + } GROUP_LINK_IN(RAMABLE_REGION) + + 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.*") + + } GROUP_LINK_IN(RAMABLE_REGION) + + /* Define linker symbols */ + _image_ram_end = .; + _end = .; /* end of image */ + __bss_num_words = (__bss_end - __bss_start) >> 2; + + GROUP_END(RAMABLE_REGION) + + /* Data Closely Coupled Memory (DCCM) */ + GROUP_START(DCCM) + GROUP_END(DCCM) + + SECTION_PROLOGUE(initlevel_error, (OPTIONAL),) + { + DEVICE_INIT_UNDEFINED_SECTION() + } + ASSERT(SIZEOF(initlevel_error) == 0, "Undefined initialization levels used.") + + } + diff --git a/include/drivers/console/uart_console.h b/include/drivers/console/uart_console.h index eea285c..e290886 100644 --- a/include/drivers/console/uart_console.h +++ b/include/drivers/console/uart_console.h @@ -27,7 +27,7 @@ extern "C" { #define MAX_LINE_LEN 256 struct uart_console_input { - int _unused; + void *_unused; char line[MAX_LINE_LEN]; }; diff --git a/include/kernel.h b/include/kernel.h index d49f878..4d322ae 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -29,6 +29,7 @@ #include <sections.h> #include <atomic.h> #include <errno.h> +#include <irq.h> #include <misc/__assert.h> #include <misc/dlist.h> #include <misc/slist.h> @@ -650,7 +651,11 @@ struct _timeout { sys_dlist_t node; struct k_thread *thread; sys_dlist_t *wait_q; +#ifdef CONFIG_RISCV64 + int64_t delta_ticks_from_prev; +#else int32_t delta_ticks_from_prev; +#endif _timeout_func_t func; }; diff --git a/include/kernel_version.h b/include/kernel_version.h index 9e2ed5e..4392e88 100644 --- a/include/kernel_version.h +++ b/include/kernel_version.h @@ -19,6 +19,8 @@ #ifndef _kernel_version__h_ #define _kernel_version__h_ +#include <stdint.h> + #ifdef __cplusplus extern "C" { #endif diff --git a/include/linker-defs.h b/include/linker-defs.h index f9df709..f6d5478 100644 --- a/include/linker-defs.h +++ b/include/linker-defs.h @@ -41,6 +41,8 @@ /* Nothing yet to include */ #elif defined(CONFIG_NIOS2) /* Nothing yet to include */ +#elif defined(CONFIG_RISCV64) +/* Nothing yet to include */ #else #error Arch not supported. #endif diff --git a/include/linker-tool-gcc.h b/include/linker-tool-gcc.h index 782bd2e..3a354e2 100644 --- a/include/linker-tool-gcc.h +++ b/include/linker-tool-gcc.h @@ -39,6 +39,8 @@ #endif #elif defined(CONFIG_NIOS2) OUTPUT_FORMAT("elf32-littlenios2", "elf32-bignios2", "elf32-littlenios2") +#elif defined(CONFIG_RISCV64) + OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") #else #error Arch not supported. #endif diff --git a/include/misc/shell.h b/include/misc/shell.h index 158f96f..3a0be96 100644 --- a/include/misc/shell.h +++ b/include/misc/shell.h @@ -16,6 +16,9 @@ * limitations under the License. */ +#ifndef __MISC_SHELL_H__ +#define __MISC_SHELL_H__ + #ifdef __cplusplus extern "C" { #endif @@ -126,3 +129,4 @@ static inline int shell_run(struct device *dev) { return 0; } } #endif +#endif // __MISC_SHELL_H__ diff --git a/include/toolchain/common.h b/include/toolchain/common.h index 518c12f..b298969 100644 --- a/include/toolchain/common.h +++ b/include/toolchain/common.h @@ -86,6 +86,10 @@ #define PERFOPT_ALIGN .balign 4 + #elif defined(CONFIG_RISCV64) + + #define PERFOPT_ALIGN .balign 8 + #else #error Architecture unsupported diff --git a/include/toolchain/gcc.h b/include/toolchain/gcc.h index 4cf420f..c516f02 100644 --- a/include/toolchain/gcc.h +++ b/include/toolchain/gcc.h @@ -279,6 +279,11 @@ A##a: ",%0" \ "\n\t.type\t" #name ",%%object" : : "n"(value)) +#elif defined(CONFIG_RISCV64) + +#define GEN_ABSOLUTE_SYM(name, value) \ + __asm__(".globl\t" #name "\n") + #else #error processor architecture not supported #endif diff --git a/kernel/unified/atomic_c.c b/kernel/unified/atomic_c.c index b8f2a19..981765a 100644 --- a/kernel/unified/atomic_c.c +++ b/kernel/unified/atomic_c.c @@ -31,6 +31,7 @@ #include <atomic.h> #include <toolchain.h> #include <arch/cpu.h> +#include <irq.h> /** * diff --git a/kernel/unified/idle.c b/kernel/unified/idle.c index b6e36a3..83588b1 100644 --- a/kernel/unified/idle.c +++ b/kernel/unified/idle.c @@ -154,6 +154,11 @@ void idle(void *unused1, void *unused2, void *unused3) (void)irq_lock(); _sys_power_save_idle(_get_next_timeout_expiry()); +#ifdef CONFIG_RISCV64 + // I didn't understood where preemptive switch must occurs + k_yield(); +#else IDLE_YIELD_IF_COOP(); +#endif } } diff --git a/kernel/unified/include/kernel_structs.h b/kernel/unified/include/kernel_structs.h index 8ec5d99..f29402b 100644 --- a/kernel/unified/include/kernel_structs.h +++ b/kernel/unified/include/kernel_structs.h @@ -150,6 +150,9 @@ struct _kernel { /* nested interrupt count */ uint32_t nested; +#ifdef CONFIG_RISCV64 + uint32_t dummy_align8; +#endif /* interrupt stack pointer base */ char *irq_stack; diff --git a/kernel/unified/init.c b/kernel/unified/init.c index 67e12d0..ad64cf3 100644 --- a/kernel/unified/init.c +++ b/kernel/unified/init.c @@ -370,7 +370,11 @@ FUNC_NORETURN void _Cstart(void) #else /* floating point is NOT used during nanokernel init */ +#ifdef CONFIG_RISCV64 + char __stack dummy_stack[sizeof(struct k_thread)]; +#else char __stack dummy_stack[_K_THREAD_NO_FLOAT_SIZEOF]; +#endif void *dummy_thread = dummy_stack; #endif diff --git a/lib/libc/minimal/include/sys/types.h b/lib/libc/minimal/include/sys/types.h index 25a2fec..60d88ff 100644 --- a/lib/libc/minimal/include/sys/types.h +++ b/lib/libc/minimal/include/sys/types.h @@ -28,6 +28,8 @@ typedef int ssize_t; typedef int ssize_t; #elif defined(__NIOS2__) typedef int ssize_t; +#elif defined(CONFIG_RISCV64) +typedef long long ssize_t; #else #error "The minimal libc library does not recognize the architecture!\n" #endif @@ -45,6 +47,8 @@ typedef int off_t; typedef int off_t; #elif defined(__NIOS2__) typedef int off_t; +#elif defined(CONFIG_RISCV64) +typedef long long off_t; #else #error "The minimal libc library does not recognize the architecture!\n" #endif diff --git a/scripts/gen_offset_header/Makefile b/scripts/gen_offset_header/Makefile index 8e6f3b3..9458eb8 100644 --- a/scripts/gen_offset_header/Makefile +++ b/scripts/gen_offset_header/Makefile @@ -1,4 +1,7 @@ HOSTCFLAGS_gen_offset_header.o += -DKERNEL_VERSION=0 -Wall -Werror -g +ifeq ($(ARCH),riscv64) +HOSTCFLAGS_gen_offset_header.o += -DARCH_64BITS +endif HOSTCFLAGS_gen_idt.o += -Wno-unused-result hostprogs-y += gen_offset_header diff --git a/scripts/gen_offset_header/elf.h b/scripts/gen_offset_header/elf.h index 449e6ad..da86c85 100644 --- a/scripts/gen_offset_header/elf.h +++ b/scripts/gen_offset_header/elf.h @@ -28,9 +28,16 @@ extern "C" { #endif +#ifdef ARCH_64BITS +#include <inttypes.h> +typedef uint64_t Elf32_Addr; +typedef uint64_t Elf32_Off; +typedef uint64_t Elf32_DWord; +#else typedef unsigned int Elf32_Addr; -typedef unsigned short Elf32_Half; typedef unsigned int Elf32_Off; +#endif +typedef unsigned short Elf32_Half; typedef int Elf32_Sword; typedef unsigned int Elf32_Word; @@ -168,14 +175,26 @@ typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; /* SHT_... */ +#ifdef ARCH_64BITS + Elf32_DWord sh_flags; /* SHF_... */ + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_DWord sh_size; +#else Elf32_Word sh_flags; /* SHF_... */ Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; +#endif Elf32_Word sh_link; Elf32_Word sh_info; +#ifdef ARCH_64BITS + Elf32_DWord sh_addralign; + Elf32_DWord sh_entsize; +#else Elf32_Word sh_addralign; Elf32_Word sh_entsize; +#endif } Elf32_Shdr; #define SHDRSZ sizeof(Elf32_Shdr) @@ -228,11 +247,19 @@ typedef struct typedef struct { Elf32_Word st_name; +#ifdef ARCH_64BITS + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; + Elf32_Addr st_value; + Elf32_DWord st_size; +#else Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; +#endif } Elf32_Sym; #define STN_UNDEF 0 @@ -300,10 +327,17 @@ typedef struct Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; +#ifdef ARCH_64BITS + Elf32_DWord p_filesz; + Elf32_DWord p_memsz; + Elf32_DWord p_flags; + Elf32_DWord p_align; +#else Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; +#endif } Elf32_Phdr; #define PHDRSZ sizeof(Elf32_Phdr) diff --git a/scripts/gen_offset_header/gen_offset_header.c b/scripts/gen_offset_header/gen_offset_header.c index 7f72fed..fd22f25 100644 --- a/scripts/gen_offset_header/gen_offset_header.c +++ b/scripts/gen_offset_header/gen_offset_header.c @@ -259,11 +259,19 @@ static int ehdrLoad(int fd) /* 64-bit ELF module not supported (for now) */ +#ifdef ARCH_64BITS + if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) + { + fprintf(stderr, "ELF32 class not supported\n"); + return -1; + } +#else if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { fprintf(stderr, "ELF64 class not supported\n"); return -1; } +#endif /* * Dynamically determine the endianess of the host (in the absence of @@ -341,7 +349,7 @@ static int shdrsLoad(int fd) * @param pSymTblSize ptr to symbol table size * @returns 0 if found, -1 if not */ -static int symTblFind(unsigned *pSymTblOffset, unsigned *pSymTblSize) +static int symTblFind(Elf32_Off *pSymTblOffset, unsigned *pSymTblSize) { unsigned ix; /* loop index */ @@ -534,8 +542,13 @@ static void headerAbsoluteSymbolsDump(int fd, FILE *fp, Elf32_Off symTblOffset, (strstr(&pStringTable[aSym.st_name], STRUCT_SIZ_SUFFIX) != NULL)) { +#ifdef ARCH_64BITS + fprintf(fp, "#define\t%s\t0x%" PRIx64 "\n", + &pStringTable[aSym.st_name], aSym.st_value); +#else fprintf(fp, "#define\t%s\t0x%X\n", &pStringTable[aSym.st_name], aSym.st_value); +#endif } } }