riscv32: added support for the riscv32-qemu soc

Change-Id: I7cf71f7a99fed7c83ed761ead9295697929d767d
Signed-off-by: Jean-Paul Etienne <fractalclone@gmail.com>
This commit is contained in:
Jean-Paul Etienne 2017-01-11 00:24:30 +01:00 committed by Andrew Boie
parent 9f418fe944
commit dae36b97e8
13 changed files with 642 additions and 0 deletions

View File

@ -0,0 +1,7 @@
ccflags-y +=-I$(srctree)/include
ccflags-y +=-I$(srctree)/include/drivers
ccflags-y +=-I$(srctree)/drivers
asflags-y := ${ccflags-y}
obj-y = soc_irq.o vector.o qemu_irq.o

View File

@ -0,0 +1,43 @@
if SOC_RISCV32_QEMU
config SOC
string
default "riscv32-qemu"
config SYS_CLOCK_HW_CYCLES_PER_SEC
int
default 10000000
config RISCV_SOC_INTERRUPT_INIT
bool
default y
config INCLUDE_RESET_VECTOR
bool
default y
config NUM_IRQS
int
default 32
config ATOMIC_OPERATIONS_C
bool
default y
config VECTOR_BASE_ADDR
hex
default 0x00001000
config VECTOR_SIZE
hex
default 0x1000
config RAM_BASE_ADDR
hex
default 0x80000000
config RAM_SIZE_MB
int
default 32
endif # SOC_RISCV32_QEMU

View File

@ -0,0 +1,2 @@
config SOC_RISCV32_QEMU
bool "riscv32_qemu SOC implementation"

View File

@ -0,0 +1 @@
soc-cflags := -I/$(srctree)/arch/$(ARCH)/soc/$(SOC_PATH)/

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 Linker script for riscv32-qemu
*/
#include <arch/riscv32/riscv32-qemu/linker.ld>

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 riscv32-qemu interrupt management code
*/
#include <irq.h>
#include <soc.h>
void _arch_irq_enable(unsigned int irq)
{
uint32_t mie;
/*
* Since only internal Timer device has interrupt within in
* riscv32-qemu, use only mie CSR register to enable device interrupt.
* CSR mie register is updated using atomic instruction csrrs
* (atomic read and set bits in CSR register)
*/
__asm__ volatile ("csrrs %0, mie, %1\n"
: "=r" (mie)
: "r" (1 << irq));
}
void _arch_irq_disable(unsigned int irq)
{
uint32_t mie;
/*
* Use atomic instruction csrrc to disable device interrupt in mie CSR.
* (atomic read and clear bits in CSR register)
*/
__asm__ volatile ("csrrc %0, mie, %1\n"
: "=r" (mie)
: "r" (1 << irq));
};
int _arch_irq_is_enabled(unsigned int irq)
{
uint32_t mie;
__asm__ volatile ("csrr %0, mie" : "=r" (mie));
return !!(mie & (1 << irq));
}
#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT)
void soc_interrupt_init(void)
{
/* ensure that all interrupts are disabled */
(void)irq_lock();
__asm__ volatile ("csrwi mie, 0\n"
"csrwi sie, 0\n"
"csrwi mip, 0\n"
"csrwi sip, 0\n");
}
#endif

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 riscv-qemu
*/
#ifndef __RISCV32_QEMU_SOC_H_
#define __RISCV32_QEMU_SOC_H_
/* CSR Registers */
#define RISCV_QEMU_MSTATUS mstatus /* Machine Status Register */
/* IRQ numbers */
#define RISCV_QEMU_TIMER_IRQ 7 /* Timer Interrupt */
/* Exception numbers */
#define RISCV_QEMU_ECALL_EXP 11 /* ECALL Instruction */
/*
* SOC-specific MSTATUS related info
*/
/* MSTATUS register to save/restore upon interrupt/exception/context switch */
#define SOC_MSTATUS_REG RISCV_QEMU_MSTATUS
#define SOC_MSTATUS_IEN (1 << 3) /* Machine Interrupt Enable bit */
/* Previous Privilege Mode - Machine Mode */
#define SOC_MSTATUS_MPP_M_MODE (3 << 11)
/* Interrupt Enable Bit in Previous Privilege Mode */
#define SOC_MSTATUS_MPIE (1 << 7)
/*
* Default MSTATUS register value to restore from stack
* upon scheduling a thread for the first time
*/
#define SOC_MSTATUS_DEF_RESTORE (SOC_MSTATUS_MPP_M_MODE | SOC_MSTATUS_MPIE)
/* SOC-specific MCAUSE bitfields */
/* Exception code Mask */
#define SOC_MCAUSE_IRQ_MASK 0x7FFFFFFF
/* ECALL exception number */
#define SOC_MCAUSE_ECALL_EXP RISCV_QEMU_ECALL_EXP
/* SOC-Specific EXIT ISR command */
#define SOC_ERET mret
/* UART configuration */
#define RISCV_QEMU_UART_BASE 0x40002000
/* Timer configuration */
#define RISCV_QEMU_TIMER_BASE 0x40000000
#ifndef _ASMLANGUAGE
#include <irq.h>
#include <misc/util.h>
#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT)
void soc_interrupt_init(void);
#endif
/* lib-c hooks required RAM defined variables */
#define RISCV_RAM_BASE CONFIG_RAM_BASE_ADDR
#define RISCV_RAM_SIZE MB(CONFIG_RAM_SIZE_MB)
#endif /* !_ASMLANGUAGE */
#endif /* __RISCV32_QEMU_SOC_H_ */

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 <kernel_structs.h>
#include <offsets.h>
#include <toolchain.h>
#include <sections.h>
#include <soc.h>
/* exports */
GTEXT(__soc_is_irq)
GTEXT(__soc_handle_irq)
/*
* SOC-specific function to handle pending IRQ number generating the interrupt.
* Exception number is given as parameter via register a0.
*/
SECTION_FUNC(exception.other, __soc_handle_irq)
/* Clear exception number from CSR mip register */
li t1, 1
sll t0, t1, a0
csrrc t1, mip, t0
/* Return */
jalr x0, ra
/*
* SOC-specific function to determine if the exception is the result of a
* an interrupt or an exception
* return 1 (interrupt) or 0 (exception)
*/
SECTION_FUNC(exception.other, __soc_is_irq)
/* Get exception number from the mcause CSR register. */
csrr t0, mcause
li t1, SOC_MCAUSE_IRQ_MASK
and t0, t0, t1
/* if IRQ number != RISCV_QEMU_TIMER_IRQ, not interrupt */
li t1, RISCV_QEMU_TIMER_IRQ
addi a0, x0, 0
bne t0, t1, not_interrupt
addi a0, a0, 1
not_interrupt:
/* return */
jalr x0, ra

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 <toolchain.h>
/* imports */
GTEXT(__reset)
GTEXT(__irq_wrapper)
/*
* following riscv32-qemu specs
* IVT is placed at 0x000001000 and is mapped as follows:
* 0x00001000: reset
* 0x00001004: non-maskable interrupt (nmi) vector
* 0x00001010: machine trap (mt) vector
*
* Call __irq_wrapper to handle all interrupts/exceptions/faults
*/
SECTION_FUNC(vectors, vinit)
.option norvc;
/*
* jal instruction cannot be used to jump to address whose offset
* is > 12-bits wide. In this case, we have to use a call or tail
* instruction to jump to a far-away sub-routine.
*
* Given that IVT is found at a different address-space than the
* RAM in riscv32-qemu, we have to use call or tail instructions
* to jump to __reset or __isr_wrapper subroutines.
* However, call or tail instructions are pseudo instructions,
* which generate two base-instructions upon compilation. In this case,
* using them at a particular entry in the IVT will overwrite the next
* entry in the IVT. For example, using tail instruction in the
* reset vector, will overwrite the nmi-vector entry. To prevent this,
* perform a two-phase jump instructions to __reset or __irq_wrapper
* subroutines. The first jump performs a jal instruction, which will
* jump to an offset in the same vector address-space, but outside the
* IVT. The second jump performs a tail instruction to the __reset
* or __irq_wrapper subroutines.
*/
/* Call __reset for reset vector */
jal x0, do_reset
/* Call __irq_wrapper for nmi vector */
jal x0, do_irq_wrapper
.org 0x10
/* Call __irq_wrapper for mt vector */
jal x0, do_irq_wrapper
.org 0x400 /* we are outside IVT */
do_reset:
/*
* Set mtvec (Machine Trap-Vector Base-Address Register)
* to __irq_wrapper, so that we jump directly to __irq_wrapper,
* instead to the default machine trap vector address in IVT.
* This will preserve us from performing two jump instructions upon
* an interrupt.
*/
la t0, __irq_wrapper
csrw mtvec, t0
/* Jump to __reset */
tail __reset
do_irq_wrapper:
tail __irq_wrapper

View File

@ -140,6 +140,8 @@ static ALWAYS_INLINE void _arch_irq_unlock(unsigned int key)
#if defined(CONFIG_SOC_RISCV32_PULPINO)
#include <arch/riscv32/pulpino/asm_inline.h>
#elif defined(CONFIG_SOC_RISCV32_QEMU)
#include <arch/riscv32/riscv32-qemu/asm_inline.h>
#endif
#ifdef __cplusplus

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 arch/cpu.h instead
*/
#if defined(__GNUC__)
#include <arch/riscv32/riscv32-qemu/asm_inline_gcc.h>
#else
#error "Supports only GNU C compiler"
#endif
#endif /* _ASM_INLINE_PUBLIC_H */

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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_GCC_H
#define _ASM_INLINE_GCC_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* The file must not be included directly
* Include arch/cpu.h instead
* riscv32-qemu does not have bit manipulation asm opcodes.
* Handle find_lsb_set and find_msb_set in C.
*/
#ifndef _ASMLANGUAGE
#include <toolchain.h>
/**
*
* @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)
{
return __builtin_ffs(op);
}
/**
*
* @brief find most significant bit set in a 32-bit word
*
* This routine finds the first bit set starting from the most 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 most significant bit set, 0 if @a op is 0
*/
static ALWAYS_INLINE unsigned int find_msb_set(uint32_t op)
{
if (!op)
return 0;
return 32 - __builtin_clz(op);
}
#endif /* _ASMLANGUAGE */
#ifdef __cplusplus
}
#endif
#endif /* _ASM_INLINE_GCC_PUBLIC_GCC_H */

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* 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 Linker command/script file
*
* Linker script for the riscv32-qemu platform
*/
#define _LINKER
#define _ASMLANGUAGE
#include <autoconf.h>
#include <sections.h>
#include <linker-defs.h>
#include <linker-tool.h>
#define ROMABLE_REGION RAM
#define RAMABLE_REGION RAM
#define _VECTOR_SECTION_NAME vector
#define _EXCEPTION_SECTION_NAME exceptions
#define _RESET_SECTION_NAME reset
#define RAM_LENGTH (CONFIG_RAM_SIZE_MB * 1024 * 1024)
ENTRY(__reset)
MEMORY
{
VECTOR (rx) : ORIGIN = CONFIG_VECTOR_BASE_ADDR, LENGTH = CONFIG_VECTOR_SIZE
RAM (rwx) : ORIGIN = CONFIG_RAM_BASE_ADDR, LENGTH = RAM_LENGTH
}
SECTIONS
{
GROUP_START(VECTOR)
SECTION_PROLOGUE(_VECTOR_SECTION_NAME,,)
{
. = ALIGN(4);
KEEP(*(.vectors.*))
} GROUP_LINK_IN(VECTOR)
GROUP_END(VECTOR)
GROUP_START(RAM)
SECTION_PROLOGUE(_RESET_SECTION_NAME,,)
{
KEEP(*(.reset.*))
} GROUP_LINK_IN(RAM)
SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,)
{
KEEP(*(".exception.entry.*"))
*(".exception.other.*")
} GROUP_LINK_IN(RAM)
SECTION_PROLOGUE(_TEXT_SECTION_NAME,,)
{
. = ALIGN(4);
_image_text_start = .;
*(.text)
*(".text.*")
*(.gnu.linkonce.t.*)
} GROUP_LINK_IN(RAM)
_image_text_end = .;
GROUP_END(RAM)
GROUP_START(RAMABLE_REGION)
#include <linker/common-rom.ld>
SECTION_PROLOGUE(_RODATA_SECTION_NAME,,)
{
. = ALIGN(4);
*(.rodata)
*(".rodata.*")
*(.gnu.linkonce.r.*)
} GROUP_LINK_IN(RAMABLE_REGION)
#include <linker/common-ram.ld>
SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,)
{
. = ALIGN(4);
KEEP(*(.isr_irq*))
/* sections for IRQ0-9 */
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9])))
/* sections for IRQ10-99 */
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9])))
/* sections for IRQ100-999 */
KEEP(*(SORT(.gnu.linkonce.isr_irq[0-9][0-9][0-9])))
*(.data)
*(".data.*")
*(.sdata .sdata.* .gnu.linkonce.s.*)
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
} GROUP_LINK_IN(RAMABLE_REGION)
SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
{
/*
* For performance, BSS section is assumed to be 4 byte aligned and
* a multiple of 4 bytes
*/
. = ALIGN(4);
__bss_start = .;
*(.sbss)
*(".sbss.*")
*(.bss)
*(".bss.*")
COMMON_SYMBOLS
/*
* As memory is cleared in words only, it is simpler to ensure the BSS
* section ends on a 4 byte boundary. This wastes a maximum of 3 bytes.
*/
__bss_end = ALIGN(4);
} GROUP_LINK_IN(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)
_end = .; /* end of image */
GROUP_END(RAMABLE_REGION)
}