diff --git a/bench/bsp/config/fpga_platform_config.h b/bench/bsp/config/fpga_platform_config.h new file mode 100644 index 0000000000000000000000000000000000000000..e0bd0d49ffafaf06db0cbb1b3752f65c5c3ec297 --- /dev/null +++ b/bench/bsp/config/fpga_platform_config.h @@ -0,0 +1,48 @@ +// Copyright (c) 2020 Thales. +// +// Copyright and related rights are 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 +// https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this 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. +// +// Author: Sebastien Jacq - sjthales on github.com +// +// Additional contributions by: +// +// +// file Name: CVA6 FPGA configurtion +// Project Name: CVA6 softcore +// Language: C header +// +// Description: File which defines the FPGA platform, i.e base address for each +// peripheral and others information relating to FPAG platform. +// +// =========================================================================== # +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq Created +// =========================================================================== # + +#ifndef __FPGA_PLATFORM_CONFIG_H +#define __FPGA_PLATFORM_CONFIG_H + + +/***************************************************************************//** + * Platform frequency + */ + +#define FPGA_UART_0_FREQUENCY 25000000 + + +/***************************************************************************//** + * Peripheral base address + */ +#define FPGA_UART_0_BASE 0x10000000 + + + +#endif /* FPGA_PLATFORM_CONFIG */ diff --git a/bench/bsp/config/link.ld b/bench/bsp/config/link.ld new file mode 100644 index 0000000000000000000000000000000000000000..5856d17abf1e072ae64c013ed2128624d7470310 --- /dev/null +++ b/bench/bsp/config/link.ld @@ -0,0 +1,320 @@ +/* Copyright (c) 2020 Thales. + Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copyright (C) 2019 ETH Zürich and University of Bologna + Copyright (C) 2020 OpenHW Group + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ + +/* This linker script is adapted from the default linker script for upstream + RISC-V GCC. It has been modified for use in verification of CORE-V cores. +*/ +/* Additional contributions by: + Sebastien Jacq - sjthales on github.com + + Description: linkerscript for the CV32A6 platform + + =========================================================================== + Revisions : + Date Version Author Description + 2020-10-06 0.1 S.Jacq modification of the Test for CV32A6 softcore + =========================================================================== */ + +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", + "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) + +/* CORE-V */ +MEMORY +{ + /* Our testbench is a bit weird in that we initialize the RAM (thus + allowing initialized sections to be placed there). Infact we dump all + sections to ram. */ + + ram (rwxai) : ORIGIN = 0x80000000, LENGTH = 0x20000 + dbg (rwxai) : ORIGIN = 0x1A110800, LENGTH = 0x1000 +} + +SECTIONS +{ + /* CORE-V Debugger Code: This section address must be the same as the + DM_HaltAddress parameter in the RTL */ + .debugger (ORIGIN(dbg)): + { + KEEP(*(.debugger)); + } >dbg + .debugger_exception (0x1A111000): + { + KEEP(*(.debugger_exception)); + } >dbg + /* Debugger Stack*/ + .debugger_stack : ALIGN(16) + { + PROVIDE(__debugger_stack_start = .); + . = 0x80; + } >dbg + + /* CORE-V: we want a fixed entry point */ + PROVIDE(__boot_address = 0x80000080); + + /* CORE-V: interrupt vectors */ + .vectors (ORIGIN(ram)): + { + PROVIDE(__vector_start = .); + KEEP(*(.vectors)); + } >ram + + /* CORE-V: crt0 init code */ + .init (__boot_address): + { + KEEP (*(SORT_NONE(.init))) + KEEP (*(.text.start)) + } >ram + + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS; + .interp : { *(.interp) } >ram + .note.gnu.build-id : { *(.note.gnu.build-id) } >ram + .hash : { *(.hash) } >ram + .gnu.hash : { *(.gnu.hash) } >ram + .dynsym : { *(.dynsym) } >ram + .dynstr : { *(.dynstr) } >ram + .gnu.version : { *(.gnu.version) } >ram + .gnu.version_d : { *(.gnu.version_d) } >ram + .gnu.version_r : { *(.gnu.version_r) } >ram + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } >ram + .rela.plt : + { + *(.rela.plt) + } >ram + + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } >ram + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } >ram + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } >ram + .rodata1 : { *(.rodata1) } >ram + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } >ram + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } >ram + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } >ram + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ram + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >ram + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >ram + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ram + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } >ram + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >ram + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } >ram + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } >ram + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } >ram + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >ram + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >ram + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >ram + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >ram + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >ram + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + __DATA_BEGIN__ = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } >ram + .data1 : { *(.data1) } >ram + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + } >ram + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } >ram + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } >ram + . = ALIGN(32 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(32 / 8); + __bss_end = .; + __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, + MAX(__DATA_BEGIN__ + 0x800, __bss_end - 0x800)); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + + /* Heap grows upward towards end of ram */ + .heap : ALIGN(16) + { + PROVIDE(__heap_start = .); + /* If end of ram is not 16-byte aligned, align to previous 16-byte + boundary */ + PROVIDE(__heap_end = ALIGN(ORIGIN(ram) + LENGTH(ram) - __heap_start - 15, 16)); + . = __heap_end; + } >ram + + /* Stack grows downward from end of ram */ + .stack (__heap_start) : ALIGN(16) /* this is a requirement of the ABI(?) */ + { + PROVIDE(__stack_start = __heap_start); + . = __heap_end; + PROVIDE(__stack_end = .); + } >ram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/bench/bsp/drivers/uart/uart.c b/bench/bsp/drivers/uart/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..09421f4f12c4e8931858a898687dd9e7cbfd6558 --- /dev/null +++ b/bench/bsp/drivers/uart/uart.c @@ -0,0 +1,834 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: Driver for UART Ip of the CVA6 platform +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + + + +#include "uart.h" + +#include "plic.h" +#include "fpga_platform_config.h" + + +/******************************************************************************* + * Defines + */ +#define TX_COMPLETE 0u +#define TX_FIFO_SIZE 16u + +#define FCR_TRIG_LEVEL_MASK 0xC0u + +#define IIRF_MASK 0x0Fu + +#define INVALID_INTERRUPT 0u +#define INVALID_IRQ_HANDLER ((uart_irq_handler_t) 0) +#define NULL_HANDLER ((uart_irq_handler_t) 0) + +#define UART_DATA_READY ((uint8_t) 0x01) + + +/******************************************************************************* + * Possible values for Interrupt Identification Register Field. + */ +#define IIRF_MODEM_STATUS 0x00u +#define IIRF_THRE 0x02u +//#define IIRF_MMI 0x03u +#define IIRF_RX_DATA 0x04u +#define IIRF_RX_LINE_STATUS 0x06u +#define IIRF_DATA_TIMEOUT 0x0Cu + + +uart_instance_t g_uart_0 = { .hw_reg = FPGA_UART_0_BASE }; + +/******************************************************************************* + * Global initialization for all modes + */ +static void global_init +( + uart_instance_t * this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + + /* disable interrupts */ + this_uart->hw_reg->IER = 0u; + + /* FIFO configuration */ + this_uart->hw_reg->FCR = 0u; + + /* clear receiver FIFO */ + this_uart->hw_reg->FCR = FIFO_RX_TRIGGER_LEVEL_14_MASK | CLEAR_RX_FIFO_MASK | CLEAR_TX_FIFO_MASK | RXRDY_TXRDYN_EN_MASK; + + /* clear transmitter FIFO */ + //this_uart->hw_reg->FCR |= CLEAR_TX_FIFO_MASK; + + /* set default READY mode : Mode 0*/ + /* enable RXRDYN and TXRDYN pins. The earlier FCR write to set the TX FIFO + * trigger level inadvertently disabled the FCR_RXRDY_TXRDYN_EN bit. */ + // this_uart->hw_reg->FCR |= RXRDY_TXRDYN_EN_MASK; + + this_uart->hw_reg->MCR = 0u; + + + + /* + * Configure baud rate divisors. This uses the fractional baud rate divisor + * where possible to provide the most accurate baud rat possible. + */ + config_baud_divisors(this_uart, baud_rate); + + /* set the line control register (bit length, stop bits, parity) */ + this_uart->hw_reg->LCR = line_config; + + /* Instance setup */ + this_uart->baudrate = baud_rate; + this_uart->lineconfig = line_config; + this_uart->tx_buff_size = TX_COMPLETE; + this_uart->tx_buffer = (const uint8_t*)0; + this_uart->tx_idx = 0u; + + /* Default handlers for MSS UART interrupts */ + this_uart->rx_handler = NULL_HANDLER; + this_uart->tx_handler = NULL_HANDLER; + this_uart->linests_handler = NULL_HANDLER; + this_uart->modemsts_handler = NULL_HANDLER; + + /* Initialize the sticky status */ + this_uart->status = 0u; +} + +/******************************************************************************* + * Public Functions + *******************************************************************************/ +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_init +( + uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + + /* set default tx handler for automated TX using interrupt in USART mode */ + this_uart->tx_handler = default_tx_handler; +} + + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_polled_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + uint32_t char_idx = 0u; + // uint32_t size_sent; + uint8_t status; + //uint32_t temp_tx_size = tx_size; + + //ASSERT(pbuff != ( (uint8_t*)0)); + //ASSERT(tx_size > 0u); + + if ((pbuff != ((uint8_t*)0)) && (tx_size > 0u)) + { + /* Remain in this loop until the entire input buffer + * has been transferred to the UART. + */ + do + { + /* Wait until TX FIFO is empty. */ + do + { + status = this_uart->hw_reg->LSR; + // this_uart->status |= status; + }while (0u == (status & UART_THRE)); + + + /* Check if TX FIFO is empty. */ + // if (status & UART_THRE) + //{ + // uint32_t fill_size = TX_FIFO_SIZE; + + /* Calculate the number of bytes to transmit. */ + //if (temp_tx_size < TX_FIFO_SIZE) + //{ + // fill_size = temp_tx_size; + //} + + /* Fill the TX FIFO with the calculated the number of bytes. */ + //for (size_sent = 0u; size_sent < fill_size; ++size_sent) + //{ + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = pbuff[char_idx]; + char_idx++; + //} + + /* Calculate the number of bytes remaining(not transmitted yet)*/ + //temp_tx_size -= size_sent; + //} + }while (char_idx < tx_size); + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_polled_tx_string +( + uart_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx = 0u; + uint32_t fill_size; + uint8_t data_byte; + volatile uint8_t status; + + //ASSERT(p_sz_string != ((uint8_t*)0)); + + if (p_sz_string != ((uint8_t*)0)) + { + /* Get the first data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + + /* First check for the NULL terminator byte. + * Then remain in this loop until the entire string in the input buffer + * has been transferred to the UART. + */ + while (0u != data_byte) + { + /* Wait until TX FIFO is empty. */ + do + { + status = this_uart->hw_reg->LSR; + // this_uart->status |= status; + }while (0u == (status & UART_THRE)); + + + /* Send bytes from the input buffer until the TX FIFO is full + * or we reach the NULL terminator byte. + */ + //fill_size = 0u; + + // while ((0u != data_byte) && (fill_size < TX_FIFO_SIZE)) + //{ + /* Send the data byte */ + this_uart->hw_reg->THR = data_byte; + //++fill_size; + char_idx++; + /* Get the next data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + //} + } + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_irq_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + //ASSERT(pbuff != ((uint8_t*)0)); + //ASSERT(tx_size > 0u); + + if ((tx_size > 0u) && (pbuff != ((uint8_t*)0))) + { + /*Initialize the transmit info for the UART instance with the arguments*/ + this_uart->tx_buffer = pbuff; + this_uart->tx_buff_size = tx_size; + this_uart->tx_idx = 0u; + + /* assign default handler for data transfer */ + this_uart->tx_handler = default_tx_handler; + + /* enables TX interrupt */ + this_uart->hw_reg->IER |= ETBEI_MASK; + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +int8_t +UART_tx_complete +( + uart_instance_t * this_uart +) +{ + int8_t ret_value = 0; + uint8_t status = 0u; + + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if ((TX_COMPLETE == this_uart->tx_buff_size) && + ((status & UART_TEMT) != 0u)) + { + ret_value = (int8_t)1; + } + + return ret_value; +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +size_t +UART_get_rx +( + uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +) +{ + size_t rx_size = 0u; + uint8_t status = 0u; + + //ASSERT(rx_buff != ((uint8_t*)0)); + //ASSERT(buff_size > 0u); + + if ((rx_buff != (uint8_t*)0) && (buff_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + while (((status & UART_DATA_READY) != 0u) && (rx_size < buff_size)) + { + rx_buff[rx_size] = this_uart->hw_reg->RBR; + ++rx_size; + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + } + } + + return rx_size; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_enable_irq +( + uart_instance_t * this_uart, + uart_irq_t irq_mask +) +{ + //ASSERT(UART_INVALID_IRQ > irq_mask); + + enable_irq(this_uart); + + if (UART_INVALID_IRQ > irq_mask) + { + /* irq_mask encoding: 1- enable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + this_uart->hw_reg->IER |= ((uint8_t)(((uint32_t)irq_mask & + (uint32_t)IIRF_MASK))); + + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_rx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler, + uart_rx_trig_level_t trigger_level +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER ); + //ASSERT(trigger_level < UART_FIFO_INVALID_TRIG_LEVEL); + + if ((handler != INVALID_IRQ_HANDLER) && + (trigger_level < UART_FIFO_INVALID_TRIG_LEVEL)) + { + this_uart->rx_handler = handler; + + /* Set the receive interrupt trigger level. */ + this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & + (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | + (uint8_t)trigger_level; + + /* Enable receive interrupt. */ + this_uart->hw_reg->IER |= ERBFI_MASK; + + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_tx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER); + + if (handler != INVALID_IRQ_HANDLER) + { + this_uart->tx_handler = handler; + + /* Make TX buffer info invalid */ + this_uart->tx_buffer = (const uint8_t*)0; + this_uart->tx_buff_size = 0u; + + /* Enable transmitter holding register Empty interrupt. */ + this_uart->hw_reg->IER |= ETBEI_MASK; + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_modemstatus_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER); + + if (handler != INVALID_IRQ_HANDLER) + { + this_uart->modemsts_handler = handler; + + /* Enable modem status interrupt. */ + this_uart->hw_reg->IER |= EDSSI_MASK; + enable_irq(this_uart); + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + uart_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t status = 0u; + uint32_t size_sent = 0u; + + //ASSERT(tx_buffer != ( (uint8_t*)0)); + //ASSERT(tx_size > 0); + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if ((tx_buffer != ((uint8_t*)0)) && (tx_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if (status & UART_THRE) + { + uint32_t fill_size = TX_FIFO_SIZE; + + if (tx_size < TX_FIFO_SIZE) + { + fill_size = tx_size; + } + + /* Fill up FIFO */ + for (size_sent = 0u; size_sent < fill_size; size_sent++) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = tx_buffer[size_sent]; + } + } + } + + return size_sent; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + uart_instance_t * this_uart +) +{ + uint8_t status = UART_INVALID_PARAM; + + /* + * Extract UART receive error status. + * Bit 1 - Overflow error status + * Bit 2 - Parity error status + * Bit 3 - Frame error status + * Bit 4 - Break interrupt indicator + * Bit 7 - FIFO data error status + */ + this_uart->status |= (this_uart->hw_reg->LSR); + status = (this_uart->status & STATUS_ERROR_MASK); + /* Clear the sticky status after reading */ + this_uart->status = 0u; + + return status; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_modem_status +( + const uart_instance_t * this_uart +) +{ + uint8_t status = UART_INVALID_PARAM; + + /* + * Extract UART modem status and place in lower bits of "status". + * Bit 0 - Delta Clear to Send Indicator + * Bit 1 - Delta Clear to Receive Indicator + * Bit 2 - Trailing edge of Ring Indicator detector + * Bit 3 - Delta Data Carrier Detect indicator + * Bit 4 - Clear To Send + * Bit 5 - Data Set Ready + * Bit 6 - Ring Indicator + * Bit 7 - Data Carrier Detect + */ + status = this_uart->hw_reg->MSR; + + return status; +} + + +/***************************************************************************//** + * UART_get_tx_status. + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_tx_status +( + uart_instance_t * this_uart +) +{ + uint8_t status = UART_TX_BUSY; + + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* + * Extract the transmit status bits from the UART's Line Status Register. + * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status. + (If = 1, TX FIFO is empty) + * Bit 6 - Transmitter Empty (TEMT) status. + (If = 1, both TX FIFO and shift register are empty) + */ + status &= (UART_THRE | UART_TEMT); + + return status; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_break +( + uart_instance_t * this_uart +) +{ + /* set break character on Tx line */ + this_uart->hw_reg->LCR |= SB_MASK; +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_clear_break +( + uart_instance_t * this_uart +) +{ + /* remove break character from Tx line */ + this_uart->hw_reg->LCR &= ~SB_MASK; +} + +/***************************************************************************//** + * Configure baud divisors using fractional baud rate if possible. + */ +static void +config_baud_divisors +( + uart_instance_t * this_uart, + uint32_t baudrate +) +{ + uint32_t baud_value; + uint32_t baud_value_by_64; + uint32_t baud_value_by_128; +// uint32_t fractional_baud_value; + uint64_t pclk_freq; + + this_uart->baudrate = baudrate; + + /* Use the system clock value from hw_platform.h */ + pclk_freq = FPGA_UART_0_FREQUENCY; + + /* + * Compute baud value based on requested baud rate and PCLK frequency. + * The baud value is computed using the following equation: + * baud_value = PCLK_Frequency / (baud_rate * 16) + */ + baud_value_by_128 = (uint32_t)((8UL * pclk_freq) / baudrate); + baud_value_by_64 = baud_value_by_128 / 2u; + baud_value = baud_value_by_64 / 64u; +// fractional_baud_value = baud_value_by_64 - (baud_value * 64u); +// fractional_baud_value += (baud_value_by_128 - (baud_value * 128u)) + // - (fractional_baud_value * 2u); + + /* //ASSERT if integer baud value fits in 16-bit. */ + //ASSERT(baud_value <= UINT16_MAX); + + if (baud_value <= (uint32_t)UINT16_MAX) + { + + /* + * Use Fractional baud rate divisors + */ + /* set divisor latch */ + this_uart->hw_reg->LCR = DLAB_MASK; + + /* msb of baud value */ + this_uart->hw_reg->DLM = (uint8_t)(baud_value >> 8); + /* lsb of baud value */ + this_uart->hw_reg->DLL = (uint8_t)baud_value; + + /* reset divisor latch */ + this_uart->hw_reg->LCR = 0; + } +} + +/***************************************************************************//** + * Interrupt service routine triggered by any MSS UART interrupt. This routine + * will call the handler function appropriate to the interrupt from the + * handlers previously registered with the driver through calls to the + * UART_set_*_handler() functions, or it will call the default_tx_handler() + * function in response to transmit interrupts if UART_irq_tx() is used to + * transmit data. + */ +static void +uart_isr +( + uart_instance_t * this_uart +) +{ + uint8_t iirf; + + iirf = this_uart->hw_reg->IIR & IIRF_MASK; + + switch (iirf) + { + case IIRF_MODEM_STATUS: /* Modem status interrupt */ + { + //ASSERT(NULL_HANDLER != this_uart->modemsts_handler); + if (NULL_HANDLER != this_uart->modemsts_handler) + { + (*(this_uart->modemsts_handler))(this_uart); + } + } + break; + + case IIRF_THRE: /* Transmitter Holding Register Empty */ + { + //ASSERT(NULL_HANDLER != this_uart->tx_handler); + if (NULL_HANDLER != this_uart->tx_handler) + { + (*(this_uart->tx_handler))(this_uart); + } + } + break; + + case IIRF_RX_DATA: /* Received Data Available */ + case IIRF_DATA_TIMEOUT: /* Received Data Timed-out */ + { + //ASSERT(NULL_HANDLER != this_uart->rx_handler); + if (NULL_HANDLER != this_uart->rx_handler) + { + (*(this_uart->rx_handler))(this_uart); + } + } + break; + + case IIRF_RX_LINE_STATUS: /* Line Status Interrupt */ + { + //ASSERT(NULL_HANDLER != this_uart->linests_handler); + if (NULL_HANDLER != this_uart->linests_handler) + { + (*(this_uart->linests_handler))(this_uart); + } + } + + default: + { + //ASSERT(INVALID_INTERRUPT); /*Alternative case has been considered*/ + } + break; + } +} + + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +static void +default_tx_handler +( + uart_instance_t * this_uart +) +{ + uint8_t status; + + //ASSERT(( (uint8_t*)0 ) != this_uart->tx_buffer); + //ASSERT(0u < this_uart->tx_buff_size); + + if ((((uint8_t*)0 ) != this_uart->tx_buffer) && + (0u < this_uart->tx_buff_size)) + { + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* + * This function should only be called as a result of a THRE interrupt. + * Verify that this is true before proceeding to transmit data. + */ + if (status & UART_THRE) + { + uint32_t cnt; + uint32_t fill_size = TX_FIFO_SIZE; + uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx; + + /* Calculate the number of bytes to transmit. */ + if (tx_remain < TX_FIFO_SIZE) + { + fill_size = tx_remain; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for (cnt = 0u; cnt < fill_size; ++cnt) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx]; + ++this_uart->tx_idx; + } + } + + /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */ + if (this_uart->tx_idx == this_uart->tx_buff_size) + { + this_uart->tx_buff_size = TX_COMPLETE; + + /* disables TX interrupt */ + this_uart->hw_reg->IER &= ~ETBEI_MASK; + } + } +} + + +static void +enable_irq +( + const uart_instance_t * this_uart +) +{ + + + PLIC_IRQn_Type plic_num = 0; + + if (&g_uart_0 == this_uart ) + { + plic_num = UART_0_PLIC_IRQHandler; + } + else + { + ASSERT(0); /*Alternative case has been considered*/ + } + + /* Enable UART instance interrupt in PLIC. */ + PLIC_EnableIRQ(plic_num); +} + +static void +disable_irq +( + const uart_instance_t * this_uart +) +{ + PLIC_IRQn_Type plic_num = 0; + + if (&g_uart_0 == this_uart ) + { + plic_num = UART_0_PLIC_IRQHandler; + } + else + { + ASSERT(0); /*Alternative case has been considered*/ + } + + /* Disable UART instance interrupt in PLIC. */ + PLIC_DisableIRQ(plic_num); +} + diff --git a/bench/bsp/drivers/uart/uart.h b/bench/bsp/drivers/uart/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..433d0653a67880febe245d00e34e9cb9bf5afd2e --- /dev/null +++ b/bench/bsp/drivers/uart/uart.h @@ -0,0 +1,935 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: Driver header for UART Ip of the CVA6 platform +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + +#ifndef __UART_H_ +#define __UART_H_ 1 + +#include <stddef.h> +#include <stdint.h> + + + +/***************************************************************************//** + Baud rates + ========== + The following definitions are used to specify standard baud rates as a + parameter to the UART_init() function. + + | Constant | Description | + |----------------------|------------------| + | UART_110_BAUD | 110 baud rate | + | UART_300_BAUD | 300 baud rate | + | UART_600_BAUD | 600 baud rate | + | UART_1200_BAUD | 1200 baud rate | + | UART_2400_BAUD | 2400 baud rate | + | UART_4800_BAUD | 4800 baud rate | + | UART_9600_BAUD | 9600 baud rate | + | UART_19200_BAUD | 19200 baud rate | + | UART_38400_BAUD | 38400 baud rate | + | UART_57600_BAUD | 57600 baud rate | + | UART_115200_BAUD | 115200 baud rate | + | UART_230400_BAUD | 230400 baud rate | + | UART_460800_BAUD | 460800 baud rate | + | UART_921600_BAUD | 921600 baud rate | + + */ +#define UART_110_BAUD 110U +#define UART_300_BAUD 300U +#define UART_600_BAUD 600U +#define UART_1200_BAUD 1200U +#define UART_2400_BAUD 2400U +#define UART_4800_BAUD 4800U +#define UART_9600_BAUD 9600U +#define UART_19200_BAUD 19200U +#define UART_38400_BAUD 38400U +#define UART_57600_BAUD 57600U +#define UART_115200_BAUD 115200U +#define UART_230400_BAUD 230400U +#define UART_460800_BAUD 460800U +#define UART_921600_BAUD 921600U + +/***************************************************************************//** + Data Bits Length + ================ + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |----------------------|----------------------------| + | UART_DATA_5_BITS | 5 bits of data transmitted | + | UART_DATA_6_BITS | 6 bits of data transmitted | + | UART_DATA_7_BITS | 7 bits of data transmitted | + | UART_DATA_8_BITS | 8 bits of data transmitted | + + */ +#define UART_DATA_5_BITS ((uint8_t) 0x00) +#define UART_DATA_6_BITS ((uint8_t) 0x01) +#define UART_DATA_7_BITS ((uint8_t) 0x02) +#define UART_DATA_8_BITS ((uint8_t) 0x03) + +/***************************************************************************//** + Parity + ====== + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |-------------------------|--------------------------| + | UART_NO_PARITY | No parity | + | UART_ODD_PARITY | Odd Parity | + | UART_EVEN_PARITY | Even parity | + | UART_STICK_PARITY_0 | Stick parity bit to zero | + | UART_STICK_PARITY_1 | Stick parity bit to one | + */ +#define UART_NO_PARITY ((uint8_t) 0x00) +#define UART_ODD_PARITY ((uint8_t) 0x08) +#define UART_EVEN_PARITY ((uint8_t) 0x18) +#define UART_STICK_PARITY_0 ((uint8_t) 0x38) +#define UART_STICK_PARITY_1 ((uint8_t) 0x28) + +/***************************************************************************//** + Number of Stop Bits + =================== + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |---------------------------|--------------------------| + | UART_ONE_STOP_BIT | One stop bit | + | UART_ONEHALF_STOP_BIT | One and a half stop bits | + | UART_TWO_STOP_BITS | Two stop bits | + + */ +#define UART_ONE_STOP_BIT ((uint8_t) 0x00) +#define UART_ONEHALF_STOP_BIT ((uint8_t) 0x04) +#define UART_TWO_STOP_BITS ((uint8_t) 0x04) + +/***************************************************************************//** + Receiver Error Status + ===================== + The following defines are used to determine the UART receiver error type. + These bit mask constants are used with the return value of the + UART_get_rx_status() function to find out if any errors occurred while + receiving data. + + + | Constant | Description | + |------------------------|--------------------------------------------| + | UART_NO_ERROR | No error bit mask (0x00) | + | UART_OVERUN_ERROR | Overrun error bit mask (0x02) | + | UART_PARITY_ERROR | Parity error bit mask (0x04) | + | UART_FRAMING_ERROR | Framing error bit mask (0x08) | + | UART_BREAK_ERROR | Break error bit mask (0x10) | + | UART_FIFO_ERROR | FIFO error bit mask (0x80) | + | UART_INVALID_PARAM | Invalid function parameter bit mask (0xFF) | + */ +#define UART_INVALID_PARAM ((uint8_t)0xFF) +#define UART_NO_ERROR ((uint8_t)0x00 ) +#define UART_OVERUN_ERROR ((uint8_t)0x02) +#define UART_PARITY_ERROR ((uint8_t)0x04) +#define UART_FRAMING_ERROR ((uint8_t)0x08) +#define UART_BREAK_ERROR ((uint8_t)0x10) +#define UART_FIFO_ERROR ((uint8_t)0x80) + + +/******************************************************************************* + * Receiver error status mask. + */ +#define STATUS_ERROR_MASK ( UART_OVERUN_ERROR | UART_PARITY_ERROR | \ + UART_FRAMING_ERROR | UART_BREAK_ERROR | \ + UART_FIFO_ERROR) + +/***************************************************************************//** + Transmitter Status + ================== + The following definitions are used to determine the UART transmitter status. + These bit mask constants are used with the return value of the + UART_get_tx_status() function to find out the status of the transmitter. + + | Constant | Description | + |------------------|----------------------------------------------------| + | UART_TX_BUSY | Transmitter busy (0x00) | + | UART_THRE | Transmitter holding register empty bit mask (0x20) | + | UART_TEMT | Transmitter empty bit mask (0x40) | + + */ +#define UART_TX_BUSY ((uint8_t) 0x00) +#define UART_THRE ((uint8_t) 0x20) +#define UART_TEMT ((uint8_t) 0x40) + +/***************************************************************************//** + Modem Status + ============ + The following defines are used to determine the modem status. These bit + mask constants are used with the return value of the + UART_get_modem_status() function to find out the modem status of + the UART. + + | Constant | Description | + |---------------|-------------------------------------------------| + | UART_DCTS | Delta clear to send bit mask (0x01) | + | UART_DDSR | Delta data set ready bit mask (0x02) | + | UART_TERI | Trailing edge of ring indicator bit mask (0x04) | + | UART_DDCD | Delta data carrier detect bit mask (0x08) | + | UART_CTS | Clear to send bit mask (0x10) | + | UART_DSR | Data set ready bit mask (0x20) | + | UART_RI | Ring indicator bit mask (0x40) | + | UART_DCD | Data carrier detect bit mask (0x80) | + */ +#define UART_DCTS ((uint8_t) 0x01) +#define UART_DDSR ((uint8_t) 0x02) +#define UART_TERI ((uint8_t) 0x04) +#define UART_DDCD ((uint8_t) 0x08) +#define UART_CTS ((uint8_t) 0x10) +#define UART_DSR ((uint8_t) 0x20) +#define UART_RI ((uint8_t) 0x40) +#define UART_DCD ((uint8_t) 0x80) + +/***************************************************************************//** + This typedef specifies the irq_mask parameter for the UART_enable_irq() + and UART_disable_irq() functions. The driver defines a set of bit masks + that are used to build the value of the irq_mask parameter. A bitwise OR of + these bit masks is used to enable or disable multipleUART interrupts. + */ +typedef uint16_t uart_irq_t; + +/***************************************************************************//** + UART Interrupts + ===================== + The following defines specify the interrupt masks to enable and disable + UART interrupts. They are used to build the value of the irq_mask parameter + for the UART_enable_irq() and UART_disable_irq() functions. A bitwise + OR of these constants is used to enable or disable multiple interrupts. + + + | Constant | Description | + |--------------------|---------------------------------------------------------------| + | UART_RBF_IRQ | Receive Data Available Interrupt bit mask (0x001) | + | UART_TBE_IRQ | Transmitter Holding Register Empty interrupt bit mask (0x002) | + | UART_LS_IRQ | Receiver Line Status interrupt bit mask (0x004) | + | UART_MS_IRQ | Modem Status interrupt bit mask (0x008) | + + */ +#define UART_RBF_IRQ 0x001 +#define UART_TBE_IRQ 0x002 +#define UART_LS_IRQ 0x004 +#define UART_MS_IRQ 0x008 +//#define UART_RTO_IRQ 0x010 +//#define UART_NACK_IRQ 0x020 +//#define UART_PIDPE_IRQ 0x040 +//#define UART_LINB_IRQ 0x080 +//#define UART_LINS_IRQ 0x100 +#define UART_INVALID_IRQ UINT16_MAX + +/***************************************************************************//** + This enumeration specifies the receiver FIFO trigger level. This is the number + of bytes that must be received before the UART generates a receive data + available interrupt. It provides the allowed values for the + UART_set_rx_handler() function trigger_level parameter. + */ +typedef enum { + UART_FIFO_SINGLE_BYTE = 0x00, + UART_FIFO_FOUR_BYTES = 0x40, + UART_FIFO_EIGHT_BYTES = 0x80, + UART_FIFO_FOURTEEN_BYTES = 0xC0, + UART_FIFO_INVALID_TRIG_LEVEL + +} uart_rx_trig_level_t; + + + + +/***************************************************************************//** + UART instance type. + This is type definition for UART instance. You need to create and + maintain a record of this type. This holds all data regarding the UART + instance + */ +typedef struct uart_instance uart_instance_t; + +/***************************************************************************//** + Interrupt handler prototype. + This typedef specifies the function prototype for UART interrupt handlers. + All interrupt handlers registered with the UART driver must be of this type. + The interrupt handlers are registered with the driver through the + UART_set_rx_handler(), UART_set_tx_handler(), + UART_set_rxstatus_handler(), and UART_set_modemstatus_handler() + functions. + The this_uart parameter is a pointer to either g_uart0 or g_uart1 to + identify the UART to associate with the handler function. + */ +typedef void (*uart_irq_handler_t)( uart_instance_t * this_uart ); + + +/******************************************************************************* + Register Bit definitions + */ + +/* Line Control register bit definitions */ +#define SB 6u /* Set break */ +#define DLAB 7u /* Divisor latch access bit */ + +/* Line Control register bit masks */ +#define SB_MASK (0x01u << SB) /* Set break */ +#define DLAB_MASK (0x01u << DLAB) /* Divisor latch access bit */ + +/* FIFO Control register bit definitions */ +#define ENABLE_FIFO 0u /* Enable FIFO */ +#define CLEAR_RX_FIFO 1u /* Clear receiver FIFO */ +#define CLEAR_TX_FIFO 2u /* Clear transmitter FIFO */ +#define DMA_MODE 3u /* DMA mode */ +#define FIFO64_ENABLE 5u /* FIFO64 enable */ +//#define RDYMODE 3u /* Mode 0 or Mode 1 for TXRDY and RXRDY */ +#define FIFO_RX_TRIGGER 6u /* FIFO RX trigger */ + +/* FIFO Control register bit MASKS */ +#define RXRDY_TXRDYN_EN_MASK (0x01u << 0u) /* Enable TXRDY and RXRDY signals */ +#define CLEAR_RX_FIFO_MASK (0x01u << 1u) /* Clear receiver FIFO */ +#define CLEAR_TX_FIFO_MASK (0x01u << 2u) /* Clear transmitter FIFO */ +#define DMA_MODE_MASK (0x01u << 3u) /* DMA mode */ +#define FIFO64_ENABLE_MASK (0x01u << 5u) /* FIFO64 enable */ +//#define RDYMODE_MASK (0x01u << 3u) /* Mode 0 or Mode 1 for TXRDY and RXRDY */ + +#define FIFO_RX_TRIGGER_LEVEL_4_MASK (0x01u << 6u) +#define FIFO_RX_TRIGGER_LEVEL_8_MASK (0x02u << 6u) +#define FIFO_RX_TRIGGER_LEVEL_14_MASK (0x03u << 6u) + +#define FIFO64_RX_TRIGGER_LEVEL_16_MASK (0x01u << 6u) +#define FIFO64_RX_TRIGGER_LEVEL_32_MASK (0x02u << 6u) +#define FIFO64_RX_TRIGGER_LEVEL_56_MASK (0x03u << 6u) + +/* Modem Control register bit definitions */ +//#define LOOP 4u /* Local loopback */ +//#define RLOOP 5u /* Remote loopback */ +//#define ECHO 6u /* Automatic echo */ + +/* Modem Control register bit MASKS */ +//#define LOOP_MASK (0x01u << 4u) /* Local loopback */ +//#define RLOOP_MASK (0x01u << 5u) /* Remote loopback & Automatic echo*/ +//#define ECHO_MASK (0x01u << 6u) /* Automatic echo */ + +/* Line Status register bit definitions */ +#define DR 0u /* Data ready */ +#define THRE 5u /* Transmitter holding register empty */ +#define TEMT 6u /* Transmitter empty */ + +/* Line Status register bit MASKS */ +#define DR_MASK (0x01u << 0u) /* Data ready */ +#define THRE_MASK (0x01u << 5u) /* Transmitter holding register empty */ +#define TEMT_MASK (0x01u << 6u) /* Transmitter empty */ + +/* Interrupt Enable register bit definitions */ +#define ERBFI 0u /* Enable receiver buffer full interrupt */ +#define ETBEI 1u /* Enable transmitter buffer empty interrupt */ +#define ELSI 2u /* Enable line status interrupt */ +#define EDSSI 3u /* Enable modem status interrupt */ + +/* Interrupt Enable register bit MASKS */ +#define ERBFI_MASK (0x01u << 0u) /* Enable receiver buffer full interrupt */ +#define ETBEI_MASK (0x01u << 1u) /* Enable transmitter buffer empty interrupt */ +#define ELSI_MASK (0x01u << 2u) /* Enable line status interrupt */ +#define EDSSI_MASK (0x01u << 3u) /* Enable modem status interrupt */ + +/* Multimode register 0 bit definitions */ +#define ELIN 3u /* Enable LIN header detection */ +#define ETTG 5u /* Enable transmitter time guard */ +#define ERTO 6u /* Enable receiver time-out */ +#define EFBR 7u /* Enable fractional baud rate mode */ + +/* Multimode register 0 bit MASKS */ +#define ELIN_MASK (0x01u << 3u) /* Enable LIN header detection */ +#define ETTG_MASK (0x01u << 5u) /* Enable transmitter time guard */ +#define ERTO_MASK (0x01u << 6u) /* Enable receiver time-out */ +#define EFBR_MASK (0x01u << 7u) /* Enable fractional baud rate mode */ + +/* Multimode register 1 bit definitions */ +#define E_MSB_RX 0u /* MSB / LSB first for receiver */ +#define E_MSB_TX 1u /* MSB / LSB first for transmitter */ +#define EIRD 2u /* Enable IrDA modem */ +#define EIRX 3u /* Input polarity for IrDA modem */ +#define EITX 4u /* Output polarity for IrDA modem */ +#define EITP 5u /* Output pulse width for IrDA modem */ + +/* Multimode register 1 bit MASKS */ +#define E_MSB_RX_MASK (0x01u << 0u) /* MSB / LSB first for receiver */ +#define E_MSB_TX_MASK (0x01u << 1u) /* MSB / LSB first for transmitter */ +#define EIRD_MASK (0x01u << 2u) /* Enable IrDA modem */ +#define EIRX_MASK (0x01u << 3u) /* Input polarity for IrDA modem */ +#define EITX_MASK (0x01u << 4u) /* Output polarity for IrDA modem */ +#define EITP_MASK (0x01u << 5u) /* Output pulse width for IrDA modem */ + +/* Multimode register 2 bit definitions */ +//#define EERR 0u /* Enable ERR / NACK during stop time */ +//#define EAFM 1u /* Enable 9-bit address flag mode */ +//#define EAFC 2u /* Enable address flag clear */ +//#define ESWM 3u /* Enable single wire half-duplex mode */ + +/* Multimode register 2 bit MASKS */ +//#define EERR_MASK (0x01u << 0u) /* Enable ERR / NACK during stop time */ +//#define EAFM_MASK (0x01u << 1u) /* Enable 9-bit address flag mode */ +//#define EAFC_MASK (0x01u << 2u) /* Enable address flag clear */ +//#define ESWM_MASK (0x01u << 3u) /* Enable single wire half-duplex mode */ + +/* Multimode Interrupt Enable register and + Multimode Interrupt Identification register definitions */ +//#define ERTOI 0u /* Enable receiver timeout interrupt */ +//#define ENACKI 1u /* Enable NACK / ERR interrupt */ +//#define EPID_PEI 2u /* Enable PID parity error interrupt */ +//#define ELINBI 3u /* Enable LIN break interrupt */ +//#define ELINSI 4u /* Enable LIN sync detection interrupt */ + +/* Multimode Interrupt Enable register and + Multimode Interrupt Identification register MASKS */ +//#define ERTOI_MASK (0x01u << 0u) /* Enable receiver timeout interrupt */ +//#define ENACKI_MASK (0x01u << 1u) /* Enable NACK / ERR interrupt */ +//#define EPID_PEI_MASK (0x01u << 2u) /* Enable PID parity error interrupt */ +//#define ELINBI_MASK (0x01u << 3u) /* Enable LIN break interrupt */ +//#define ELINSI_MASK (0x01u << 4u) /* Enable LIN sync detection interrupt */ + +typedef struct +{ + union + { + volatile const uint8_t RBR; + volatile uint8_t THR; + volatile uint8_t DLL; + uint32_t RESERVED0; + }; + + union + { + volatile uint8_t DLM; + volatile uint8_t IER; + uint32_t RESERVED1; + }; + + union + { + volatile uint8_t IIR; + volatile uint8_t FCR; + uint32_t RESERVED2; + }; + + volatile uint8_t LCR; + uint8_t RESERVED3[3]; + + volatile uint8_t MCR; + uint8_t RESERVED4[3]; + + volatile const uint8_t LSR; + uint8_t RESERVED5[3]; + + volatile const uint8_t MSR; + uint8_t RESERVED6[3]; + + volatile uint8_t SR; + uint8_t RESERVED7[7]; + +} UART_TypeDef; + + +/***************************************************************************//** + uart_instance. + There is one instance of this structure for each instance of the + microprocessor subsystem's UARTs. Instances of this structure are used to + identify a specific UART. A pointer to an initialized instance of the + uart_instance_t structure is passed as the first parameter to + UART driver functions to identify which UART should perform the + requested operation. + */ +struct uart_instance{ + /* CMSIS related defines identifying the UART hardware. */ + UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */ + uint32_t baudrate; /*!< Operating baud rate. */ + uint8_t lineconfig; /*!< Line configuration parameters. */ + uint8_t status; /*!< Sticky line status. */ + + /* transmit related info (used with interrupt driven transmit): */ + const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */ + uint32_t tx_buff_size; /*!< Transmit buffer size. */ + uint32_t tx_idx; /*!< Index within transmit buffer of next byte to transmit.*/ + + /* line status interrupt handler:*/ + uart_irq_handler_t linests_handler; /*!< Pointer to user registered line status handler. */ + /* receive interrupt handler:*/ + uart_irq_handler_t rx_handler; /*!< Pointer to user registered receiver handler. */ + /* transmit interrupt handler:*/ + uart_irq_handler_t tx_handler; /*!< Pointer to user registered transmit handler. */ + /* modem status interrupt handler:*/ + uart_irq_handler_t modemsts_handler; /*!< Pointer to user registered modem status handler. */ + + + +}; + +extern uart_instance_t g_uart_0; + +static void default_tx_handler(uart_instance_t * this_uart); +static void enable_irq(const uart_instance_t * this_uart); +static void disable_irq(const uart_instance_t * this_uart); + +static void config_baud_divisors +( + uart_instance_t * this_uart, + uint32_t baudrate +); + +/***************************************************************************//** + The UART_init() function initializes and configures the + UART with the configuration passed as a parameter. The configuration + parameters are the baud_rate which is used to generate the baud value and the + line_config which is used to specify the line configuration (bit length, + stop bits and parity). + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates using the following defines: + - UART_110_BAUD + - UART_300_BAUD + - UART_600_BAUD + - UART_1200_BAUD + - UART_2400_BAUD + - UART_4800_BAUD + - UART_9600_BAUD + - UART_19200_BAUD + - UART_38400_BAUD + - UART_57600_BAUD + - UART_115200_BAUD + - UART_230400_BAUD + - UART_460800_BAUD + - UART_921600_BAUD + + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. + + This is a bitwise OR of one value from each of the following groups of + allowed values: + + One of the following to specify the transmit/receive data bit length: + - UART_DATA_5_BITS + - UART_DATA_6_BITS, + - UART_DATA_7_BITS + - UART_DATA_8_BITS + + One of the following to specify the parity setting: + - UART_NO_PARITY + - UART_EVEN_PARITY + - UART_ODD_PARITY + - UART_STICK_PARITY_0 + - UART_STICK_PARITY_1 + + One of the following to specify the number of stop bits: + - UART_ONE_STOP_BIT + - UART_ONEHALF_STOP_BIT + - UART_TWO_STOP_BITS + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + return(0); + } + @endcode + */ +void +UART_init +( + uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +); + +/***************************************************************************//** + The function UART_polled_tx() is used to transmit data. It transfers the + contents of the transmitter data buffer, passed as a function parameter, into + the UART's hardware transmitter FIFO. It returns when the full content of the + transmit data buffer has been transferred to the UART's transmit FIFO. It is + safe to release or reuse the memory used as the transmitter data buffer once + this function returns. + Note: This function reads the UART's line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the UART_get_tx_status() + function if you need to know when the transmitter is empty. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data to + be transmitted. + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data to + be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t message[12] = "Hello World"; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + SS_UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + UART_polled_tx(&g_uart0_lo, message, sizeof(message)); + + return(0); + } + @endcode + */ +void +UART_polled_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The function UART_polled_tx_string() is used to transmit a NULL ('\0') + terminated string. It transfers the text string, from the buffer starting at + the address pointed to by p_sz_string into the UART's hardware transmitter + FIFO. It returns when the complete string has been transferred to the UART's + transmit FIFO. It is safe to release or reuse the memory used as the string + buffer once this function returns. + Note: This function reads the UART's line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the UART_get_tx_status() + function if you need to know when the transmitter is empty. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param p_sz_string + The p_sz_string parameter is a pointer to a buffer containing the NULL + ('\0') terminated string to be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t message[12] = "Hello World"; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_polled_tx_string(&g_uart0_lo, message); + + return(0); + } + @endcode + */ +void +UART_polled_tx_string +( + uart_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + The function UART_irq_tx() is used to initiate an interrupt-driven + transmit. It returns immediately after making a note of the transmit buffer + location and enabling transmit interrupts both at the UART and the PolarFire + SoC Core Complex PLIC level. This function takes a pointer via the pbuff + parameter to a memory buffer containing the data to transmit. The memory + buffer specified through this pointer must remain allocated and contain the + data to transmit until the transmit completion has been detected through calls + to function UART_tx_complete(). The actual transmission over the serial + connection is still in progress until calls to the UART_tx_complete() + function indicate transmit completion. + Note: The UART_irq_tx() function enables both the transmit holding + register empty (THRE) interrupt in the UART and the UART instance + interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. + Note: The UART_irq_tx() function assigns an internal default transmit + interrupt handler function to the UART's THRE interrupt. This interrupt + handler overrides any custom interrupt handler that you may have previously + registered using the UART_set_tx_handler() function. + Note: The UART_irq_tx() function's default transmit interrupt + handler disables the UART's THRE interrupt when all of the data has + been transferred to the UART's transmit FIFO. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data + to be transmitted. + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data + to be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t tx_buff[10] = "abcdefghi"; + + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_irq_tx(&g_uart0_lo, tx_buff, sizeof(tx_buff)); + + while(0 == UART_tx_complete(&g_uart0_lo)) + { + ; + } + return(0); + } + @endcode + */ +void +UART_irq_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The UART_tx_complete() function is used to find out if the + interrupt-driven transmit previously initiated through a call to + UART_irq_tx() is complete. This is typically used to find out when it is + safe to reuse or release the memory buffer holding transmit data. + Note: The transfer of all of the data from the memory buffer to the UART's + transmit FIFO and the actual transmission over the serial connection are both + complete when a call to the UART_tx_complete() function indicates transmit + completion. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @return + This function return a non-zero value if transmit has completed, otherwise + it returns zero. + Example: + See the UART_irq_tx() function for an example that uses the + UART_tx_complete() function. + */ +int8_t +UART_tx_complete +( + uart_instance_t * this_uart +); + +/***************************************************************************//** + The UART_get_rx() function reads the content of the UART receiver's FIFO + and stores it in the receive buffer that is passed via the rx_buff function + parameter. It copies either the full contents of the FIFO into the receive + buffer, or just enough data from the FIFO to fill the receive buffer, + dependent upon the size of the receive buffer passed by the buff_size + parameter. The UART_get_rx() function returns the number of bytes copied + into the receive buffer .This function is non-blocking and will return 0 + immediately if no data has been received. + Note: The UART_get_rx() function reads and accumulates the receiver + status of the UART instance before reading each byte from the receiver's + data register/FIFO. This allows the driver to maintain a sticky record of any + receiver errors that occur as the UART receives each data byte; receiver + errors would otherwise be lost after each read from the receiver's data + register. A call to the UART_get_rx_status() function returns any receiver + errors accumulated during the execution of the UART_get_rx() function. + Note: If you need to read the error status for each byte received, set + the buff_size to 1 and read the receive line error status for each byte + using the UART_get_rx_status() function. + The UART_get_rx() function can be used in polled mode, where it is called + at regular intervals to find out if any data has been received, or in + interrupt driven-mode, where it is called as part of a receive handler that is + called by the driver as a result of data being received. + Note: In interrupt driven mode you should call the UART_get_rx() + function as part of the receive handler function that you register with + the UART driver through a call to UART_set_rx_handler(). + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param rx_buff + The rx_buff parameter is a pointer to a buffer where the received + data is copied. + @param buff_size + The buff_size parameter specifies the size of the receive buffer in bytes. + @return + This function returns the number of bytes that were copied into the + rx_buff buffer. It returns 0 if no data has been received. + Polled mode example: + @code + int main( void ) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + while(1) + { + rx_size = UART_get_rx(&g_uart0_lo, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + process_rx_data(rx_buff, rx_size); + } + task_a(); + task_b(); + } + return 0; + } + @endcode + Interrupt driven example: + @code + int main( void ) + { + UART_init(&g_uart1, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_set_rx_handler(&g_uart1, + uart1_rx_handler, + UART_FIFO_SINGLE_BYTE); + + while(1) + { + task_a(); + task_b(); + } + return 0; + } + void uart1_rx_handler(uart_instance_t * this_uart) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + rx_size = UART_get_rx(this_uart, rx_buff, sizeof(rx_buff)); + process_rx_data(rx_buff, rx_size); + } + @endcode + */ +size_t +UART_get_rx +( + uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +); + +/***************************************************************************//** + The UART_set_rx_handler() function is used to register a receive handler + function that is called by the driver when a UART receive data available (RDA) + interrupt occurs. You must create and register the receive handler function + to suit your application and it must include a call to the UART_get_rx() + function to actually read the received data. + Note: The UART_set_rx_handler() function enables both the RDA + interrupt in the UART instance. It also enables the corresponding + UART instance interrupt in the PolarFire SoC Core Complex PLIC as part + of its implementation. + Note: You can disable the RDA interrupt when required by calling the + UART_disable_irq() function. This is your choice and is dependent upon + your application. + + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param handler + The handler parameter is a pointer to a receive interrupt handler function + provided by your application that will be called as a result of a UART RDA + interrupt. This handler function must be of type uart_irq_handler_t. + @param trigger_level + The trigger_level parameter is the receive FIFO trigger level. This + specifies the number of bytes that must be received before the UART + triggers an RDA interrupt. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + #define RX_BUFF_SIZE 64 + uint8_t g_rx_buff[RX_BUFF_SIZE]; + void uart0_rx_handler(uart_instance_t * this_uart) + { + UART_get_rx(this_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff)); + } + int main(void) + { + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_set_rx_handler(&g_uart0_lo, + uart0_rx_handler, + UART_FIFO_SINGLE_BYTE); + + while(1) + { + ; + } + return(0); + } + @endcode + */ +void +UART_set_rx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler, + uart_rx_trig_level_t trigger_level +); + + +#endif /*__UART_H_*/ + diff --git a/bench/bsp/hal/crt0.S b/bench/bsp/hal/crt0.S new file mode 100644 index 0000000000000000000000000000000000000000..b4ab3ca5690c4395089b01b5788c75a712a9a15e --- /dev/null +++ b/bench/bsp/hal/crt0.S @@ -0,0 +1,75 @@ +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + * Copyright (c) 2019 ETH Zürich and University of Bologna + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the FreeBSD License. This program is distributed in the hope that + * it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + * including the implied warranties of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. A copy of this license is available at + * http://www.opensource.org/licenses. + */ +/* Make sure the vector table gets linked into the binary. */ +.global vector_table + +/* Entry point for bare metal programs */ +.section .text.start +.global _start +.type _start, @function + +_start: +/* initialize global pointer */ +.option push +.option norelax +1: auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) +.option pop + + + + +/* initialize stack pointer */ + la sp, __stack_end + +/* set vector table address */ + la a0, __vector_start + ori a0, a0, 1 /*vector mode = vectored */ + csrw mtvec, a0 + +/* clear the bss segment */ + la a0, _edata + la a2, _end + sub a2, a2, a0 + li a1, 0 + call memset + +/* new-style constructors and destructors */ + la a0, __libc_fini_array + call atexit + call __libc_init_array + +/* call main */ +// lw a0, 0(sp) /* a0 = argc */ +// addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */ +// li a2, 0 /* a2 = envp = NULL */ +// Initialize these variables to 0. Cannot use argc or argv +// since the stack is not initialized + li a0, 0 + li a1, 0 + li a2, 0 + + call main + tail exit + +.size _start, .-_start + +.global _init +.type _init, @function +.global _fini +.type _fini, @function +_init: +_fini: + /* These don't have to do anything since we use init_array/fini_array. Prevent + missing symbol error */ + ret +.size _init, .-_init +.size _fini, .-_fini diff --git a/bench/bsp/hal/encoding.h b/bench/bsp/hal/encoding.h new file mode 100644 index 0000000000000000000000000000000000000000..06e4ca975b80abfd9bf34657dc5300ba8356a35f --- /dev/null +++ b/bench/bsp/hal/encoding.h @@ -0,0 +1,251 @@ + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define MCAUSE32_CAUSE 0x7FFFFFFF +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFF +#define MCAUSE32_INT 0x80000000 +#define MCAUSE64_INT 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1U<<19) +#define MCONTROL_TIMING (1U<<18) +#define MCONTROL_ACTION (0x3fU<<12) +#define MCONTROL_CHAIN (1U<<11) +#define MCONTROL_MATCH (0xfU<<7) +#define MCONTROL_M (1U<<6) +#define MCONTROL_H (1U<<5) +#define MCONTROL_S (1U<<4) +#define MCONTROL_U (1U<<3) +#define MCONTROL_EXECUTE (1U<<2) +#define MCONTROL_STORE (1U<<1) +#define MCONTROL_LOAD (1U<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1U << IRQ_S_SOFT) +#define MIP_HSIP (1U << IRQ_H_SOFT) +#define MIP_MSIP (1U << IRQ_M_SOFT) +#define MIP_STIP (1U << IRQ_S_TIMER) +#define MIP_HTIP (1U << IRQ_H_TIMER) +#define MIP_MTIP (1U << IRQ_M_TIMER) +#define MIP_SEIP (1U << IRQ_S_EXT) +#define MIP_HEIP (1U << IRQ_H_EXT) +#define MIP_MEIP (1U << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define SPTBR32_MODE 0x80000000 +#define SPTBR32_ASID 0x7FC00000 +#define SPTBR32_PPN 0x003FFFFF +#define SPTBR64_MODE 0xF000000000000000 +#define SPTBR64_ASID 0x0FFFF00000000000 +#define SPTBR64_PPN 0x00000FFFFFFFFFFF + +#define SPTBR_MODE_OFF 0 +#define SPTBR_MODE_SV32 1 +#define SPTBR_MODE_SV39 8 +#define SPTBR_MODE_SV48 9 +#define SPTBR_MODE_SV57 10 +#define SPTBR_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +# define SPTBR_MODE SPTBR64_MODE +# define MCAUSE_INT MCAUSE64_INT //ML added- should we be using later encoding.h? +# define MCAUSE_CAUSE MCAUSE64_CAUSE //ML added- should we be using later encoding.h? +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define SPTBR_MODE SPTBR32_MODE +# define MCAUSE_INT MCAUSE32_INT //ML added- should we be using later encoding.h? +# define MCAUSE_CAUSE MCAUSE32_CAUSE //ML added- should we be using later encoding.h? +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_reg(reg) ({ unsigned long __tmp; \ + asm volatile ("mv %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#if 0 +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + asm volatile ("csrw " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) + +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) +#endif + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif //__GNUC__ + +#endif //__ASSEMBLER__ + +#endif //__riscv + +#endif // RISCV_CSR_ENCODING_H + diff --git a/bench/bsp/hal/hal_assert.h b/bench/bsp/hal/hal_assert.h new file mode 100644 index 0000000000000000000000000000000000000000..a72872836663051ebd3efae73d2fe4dfacd5f984 --- /dev/null +++ b/bench/bsp/hal/hal_assert.h @@ -0,0 +1,19 @@ + +#ifndef HAL_ASSERT_HEADER +#define HAL_ASSERT_HEADER + + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ + +#define ASSERT(CHECK) + + +#define HAL_ASSERT(CHECK) + + + + +#endif /* HAL_ASSERT_HEADER */ diff --git a/bench/bsp/hal/handlers.S b/bench/bsp/hal/handlers.S new file mode 100644 index 0000000000000000000000000000000000000000..ebd676f7defb0ba1b6eee45def54ccd4044569a3 --- /dev/null +++ b/bench/bsp/hal/handlers.S @@ -0,0 +1,130 @@ +/* +* Copyright 2019 ETH Zürich and University of Bologna +* +* 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. +*/ + +/* Exception codes */ +#define EXCEPTION_ILLEGAL_INSN 2 +#define EXCEPTION_BREAKPOINT 3 +#define EXCEPTION_ECALL_M 11 + +.section .text.handlers +.global __no_irq_handler +.global sw_irq_handler +.global verification_irq_handler + +/* exception handling */ +__no_irq_handler: + la a0, no_exception_handler_msg + jal ra, puts + j __no_irq_handler + +sw_irq_handler: + /* While we are still using puts in handlers, save all caller saved + regs. Eventually, some of these saves could be deferred. */ + addi sp,sp,-64 + sw ra, 0(sp) + sw a0, 4(sp) + sw a1, 8(sp) + sw a2, 12(sp) + sw a3, 16(sp) + sw a4, 20(sp) + sw a5, 24(sp) + sw a6, 28(sp) + sw a7, 32(sp) + sw t0, 36(sp) + sw t1, 40(sp) + sw t2, 44(sp) + sw t3, 48(sp) + sw t4, 52(sp) + sw t5, 56(sp) + sw t6, 60(sp) + csrr t0, mcause + li t1, EXCEPTION_ILLEGAL_INSN + beq t0, t1, handle_illegal_insn + li t1, EXCEPTION_ECALL_M + beq t0, t1, handle_ecall + li t1, EXCEPTION_BREAKPOINT + beq t0, t1, handle_ebreak + j handle_unknown + +handle_ecall: + jal ra, handle_syscall + j end_handler_incr_mepc + +handle_ebreak: + /* TODO support debug handling requirements. */ + la a0, ebreak_msg + jal ra, puts + j end_handler_incr_mepc + +handle_illegal_insn: + la a0, illegal_insn_msg + jal ra, puts + j end_handler_incr_mepc + +handle_unknown: + la a0, unknown_msg + jal ra, puts + /* We don't know what interrupt/exception is being handled, so don't + increment mepc. */ + j end_handler_ret + +end_handler_incr_mepc: + csrr t0, mepc + lb t1, 0(t0) + li a0, 0x3 + and t1, t1, a0 + /* Increment mepc by 2 or 4 depending on whether the instruction at mepc + is compressed or not. */ + bne t1, a0, end_handler_incr_mepc2 + addi t0, t0, 2 +end_handler_incr_mepc2: + addi t0, t0, 2 + csrw mepc, t0 +end_handler_ret: + lw ra, 0(sp) + lw a0, 4(sp) + lw a1, 8(sp) + lw a2, 12(sp) + lw a3, 16(sp) + lw a4, 20(sp) + lw a5, 24(sp) + lw a6, 28(sp) + lw a7, 32(sp) + lw t0, 36(sp) + lw t1, 40(sp) + lw t2, 44(sp) + lw t3, 48(sp) + lw t4, 52(sp) + lw t5, 56(sp) + lw t6, 60(sp) + addi sp,sp,64 + mret +/* this interrupt can be generated for verification purposes, random or when the + PC is equal to a given value*/ +verification_irq_handler: + mret + +.section .rodata +illegal_insn_msg: + .string "illegal instruction exception handler entered\n" +ecall_msg: + .string "ecall exception handler entered\n" +ebreak_msg: + .string "ebreak exception handler entered\n" +unknown_msg: + .string "unknown exception handler entered\n" +no_exception_handler_msg: + .string "no exception handler installed\n" diff --git a/bench/bsp/hal/plic.h b/bench/bsp/hal/plic.h new file mode 100644 index 0000000000000000000000000000000000000000..93747f019d497b845a415e7ab2273e98707d7b1b --- /dev/null +++ b/bench/bsp/hal/plic.h @@ -0,0 +1,365 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MPFS HAL Embedded Software + * + */ +/******************************************************************************* + * + * @author Microchip-FPGA Embedded Systems Solutions + * + * Definitions and functions associated with PLIC interrupts. + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: Definitions and functions associated with PLIC interrupts +// for the CVA6 platform +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + +#ifndef MSS_PLIC_H +#define MSS_PLIC_H + +#include <stdint.h> +#include "encoding.h" + +#include "hal_assert.h" + +/* + *Return value from External IRQ handler. This will be used to disable the + *Return External interrupt. + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + + + +/***************************************************************************//** + * PLIC source Interrupt numbers: + */ + +typedef enum +{ + NoInterrupt_IRQHandler = 0, + UART_0_PLIC_IRQHandler = 1, + QSPI_0_PLIC_IRQHandler = 2, + ETH_0_PLIC_IRQHandler = 3, + External_4_IRQHandler = 4, + External_5_IRQHandler = 5, + External_6_IRQHandler = 6, + External_7_IRQHandler = 7, + External_8_IRQHandler = 8, + External_9_IRQHandler = 9, + External_10_IRQHandler = 10, + External_11_IRQHandler = 11, + External_12_IRQHandler = 12, + External_13_IRQHandler = 13, + External_14_IRQHandler = 14, + External_15_IRQHandler = 15, + External_16_IRQHandler = 16, + External_17_IRQHandler = 17, + External_18_IRQHandler = 18, + External_19_IRQHandler = 19, + External_20_IRQHandler = 20, + External_21_IRQHandler = 21, + External_22_IRQHandler = 22, + External_23_IRQHandler = 23, + External_24_IRQHandler = 24, + External_25_IRQHandler = 25, + External_26_IRQHandler = 26, + External_27_IRQHandler = 27, + External_28_IRQHandler = 28, + External_29_IRQHandler = 29, + External_30_IRQHandler = 30 +} PLIC_IRQn_Type; + + +#define MAX_PLIC_INT External_30_IRQHandler + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[(0x1000/4)-2]; +} IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[31U]; +} Target_Enables_Type; + + +#define PLIC_SET_UP_REGISTERS 2U +#define PLIC_NUM_SOURCES 30U +#define PLIC_NUM_PRIORITIES 7U +#define NUM_CLAIM_REGS 2U + + + +typedef struct +{ + + volatile uint32_t RESERVED0; + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[PLIC_NUM_SOURCES]; + volatile uint32_t RESERVED1[(0x1000/4) - (PLIC_NUM_SOURCES + 1)]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[PLIC_SET_UP_REGISTERS]; + volatile uint32_t RESERVED2[(0x1000/4) - PLIC_SET_UP_REGISTERS]; + + /*-------------------- Target enables --------------------*/ + //volatile Target_Enables_Type TARGET_ENABLES[PLIC_SET_UP_REGISTERS]; + //volatile uint32_t RESERVED3[(0x200000-0x2000) - PLIC_SET_UP_REGISTERS]; + + /*-----------------Target Mode Enables--------------------*/ + volatile uint32_t HART0_MMODE_ENA[PLIC_SET_UP_REGISTERS]; + volatile uint32_t RESERVED3a[(0x80/4) - PLIC_SET_UP_REGISTERS]; + + volatile uint32_t HART0_SMODE_ENA[PLIC_SET_UP_REGISTERS]; + volatile uint32_t RESERVED3[(0x80/4) - PLIC_SET_UP_REGISTERS]; + + volatile uint32_t RESERVED4[(0x200000-0x2000)/4 - PLIC_SET_UP_REGISTERS]; + + /*--- Target Priority threshold and claim/complete---------*/ + IRQ_Target_Type TARGET[NUM_CLAIM_REGS]; + + + +} PLIC_Type; + + + + +#define TARGET_OFFSET_HART0_M 0U +#define TARGET_OFFSET_HART0_S 1U + +/***************************************************************************//** + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x0C000000UL + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*-------------------------------------------------------------------------*//** + * The function PLIC_init() initializes the PLIC controller and enables the + * global external interrupt bit. + */ + +/*-----------------Hart Mode Enables--------------------*/ + +static inline void PLIC_init(void) +{ + uint32_t inc; + uint64_t hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) + { + PLIC->HART0_MMODE_ENA[inc] = 0U; + PLIC->HART0_SMODE_ENA[inc] = 0U; + } + + PLIC->TARGET[TARGET_OFFSET_HART0_M].PRIORITY_THRESHOLD = 0U; + /* Disable supervisor level */ + PLIC->TARGET[TARGET_OFFSET_HART0_S].PRIORITY_THRESHOLD = 7U; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + + +/***************************************************************************//** + * The function PLIC_EnableIRQ() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void PLIC_EnableIRQ(PLIC_IRQn_Type IRQn) +{ + uint64_t hart_id = read_csr(mhartid); + + uint32_t current; + + switch(hart_id) + { + case 0: + current = PLIC->HART0_MMODE_ENA[IRQn / 32U]; + current |= (uint32_t)1 << (IRQn % 32U); + PLIC->HART0_MMODE_ENA[IRQn / 32U] = current; + break; + default: + break; + } +} + +/***************************************************************************//** + * The function PLIC_DisableIRQ() disables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt + * handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return + * value EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void PLIC_DisableIRQ(PLIC_IRQn_Type IRQn) +{ + uint32_t current; + uint64_t hart_id = read_csr(mhartid); + + switch(hart_id) + { + case 0: + current = PLIC->HART0_MMODE_ENA[IRQn / 32U]; + current &= ~((uint32_t)1 << (IRQn % 32U)); + PLIC->HART0_MMODE_ENA[IRQn / 32U] = current; + break; + default: + break; + } +} + +/***************************************************************************//** + * The function PLIC_SetPriority() sets the priority for the external interrupt + * for the interrupt number indicated by the parameter IRQn. + */ +static inline void PLIC_SetPriority(PLIC_IRQn_Type IRQn, uint32_t priority) +{ + if((IRQn > NoInterrupt_IRQHandler) && (IRQn < PLIC_NUM_SOURCES)) + { + PLIC->SOURCE_PRIORITY[IRQn-1] = priority; + } +} + +/***************************************************************************//** + * The function PLIC_GetPriority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t PLIC_GetPriority(PLIC_IRQn_Type IRQn) +{ + uint32_t ret_val = 0U; + + if((IRQn > NoInterrupt_IRQHandler) && (IRQn < PLIC_NUM_SOURCES)) + { + ret_val = PLIC->SOURCE_PRIORITY[IRQn-1]; + } + + return(ret_val); +} + + +/*static inline uint32_t PLIC_pending(PLIC_IRQn_Type IRQn) +{ + return (PLIC->PENDING_ARRAY[IRQn/32U] & (0x01U<<(IRQn%32U))); +}*/ + +/***************************************************************************//** + * The function PLIC_ClaimIRQ() claims the interrupt from the PLIC controller. + */ +static inline uint32_t PLIC_ClaimIRQ(void) +{ + unsigned long hart_id = read_csr(mhartid); + + return PLIC->TARGET[hart_id].CLAIM_COMPLETE; +} + +/***************************************************************************//** + * The function PLIC_CompleteIRQ() indicates to the PLIC controller the + * interrupt is processed and claim is complete. + */ +static inline void PLIC_CompleteIRQ(uint32_t source) +{ + unsigned long hart_id = read_csr(mhartid); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = source; +} + +/***************************************************************************//** + * + * The function PLIC_SetPriority_Threshold() sets the threshold for a particular + * hart. The default threshold on reset is 0. + * The PFSoC Core Complex supports setting of an interrupt priority threshold + * via the threshold register. The threshold is a WARL field, where the PFSoC + * Core Complex supports a maximum threshold of 7. + * The PFSoC Core Complex will mask all PLIC interrupts of a priority less than + * or equal to threshold. For example, a threshold value of zero permits all + * interrupts with non-zero priority, whereas a value of 7 masks all + * interrupts. + */ +static inline void PLIC_SetPriority_Threshold(uint32_t threshold) +{ + uint64_t hart_id = read_csr(mhartid); + //const unsigned long lookup[5U] = {0U, 1U, 3U, 5U, 7U}; + + //ASSERT(threshold <= 7); + + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = threshold; +} + +/***************************************************************************//** + * PLIC_ClearPendingIRQ(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void PLIC_ClearPendingIRQ(void) +{ + volatile uint32_t int_num = PLIC_ClaimIRQ(); + volatile int32_t wait_possible_int; + + while ( int_num != NoInterrupt_IRQHandler) + { + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + PLIC_CompleteIRQ(int_num); + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + int_num = PLIC_ClaimIRQ(); /* obtain interrupt, auto clears */ + } +} + +/***************************************************************************//** + * This function is only called from one hart on startup + */ +static inline void PLIC_init_on_reset(void) +{ + uint32_t inc; + + /* default all priorities so effectively disabled */ + for(inc = 0U; inc < PLIC_NUM_SOURCES; ++inc) + { + /* priority must be greater than threshold to be enabled, so setting to + * 7 disables */ + PLIC->SOURCE_PRIORITY[inc] = 0U; + } + + for(inc = 0U; inc < NUM_CLAIM_REGS; ++inc) + { + PLIC->TARGET[inc].PRIORITY_THRESHOLD = 7U; + } + + /* and clear all the enables */ + for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) + { + PLIC->HART0_MMODE_ENA[inc] = 0U; + PLIC->HART0_SMODE_ENA[inc] = 0U; + } + + /* clear any pending interrupts- in case already there */ + PLIC_ClearPendingIRQ(); +} + + +#endif /* MSS_PLIC_H */ + diff --git a/bench/bsp/hal/riscv_hal_stubs.c b/bench/bsp/hal/riscv_hal_stubs.c new file mode 100755 index 0000000000000000000000000000000000000000..4f5ace513c6b9c4cb041f12ad25a4dd917e21530 --- /dev/null +++ b/bench/bsp/hal/riscv_hal_stubs.c @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MPFS HAL Embedded Software + * + */ + +/******************************************************************************* + * + * @author Microchip-FPGA Embedded Systems Solutions + * @brief MPFS MSS Interrupt Function stubs. + * + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: The functions below will only be linked with the application +// code if the user does not provide an implementation for these +// functions. These functions are defined with weak linking so that +// they can be overridden by a function with same prototype in the +// user's application code. +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + + + +#include <unistd.h> + + +__attribute__((weak)) uint8_t NoInterrupt_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t UART_0_PLIC_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t QSPI_0_PLIC_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t ETH_0_PLIC_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0); +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0); +} + + diff --git a/bench/bsp/hal/syscalls.c b/bench/bsp/hal/syscalls.c new file mode 100644 index 0000000000000000000000000000000000000000..9f73838f37f6856b10f42b2cf11edcbc590d8d57 --- /dev/null +++ b/bench/bsp/hal/syscalls.c @@ -0,0 +1,438 @@ +/* An extremely minimalist syscalls.c for newlib + * Based on riscv newlib libgloss/riscv/sys_*.c + * + * Copyright (c) 2020 Thales. + * Copyright 2019 Clifford Wolf + * Copyright 2019 ETH Zürich and University of Bologna + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + +#include <sys/stat.h> +#include <sys/timeb.h> +#include <sys/times.h> +#include <sys/utime.h> +#include <newlib.h> +#include <unistd.h> +#include <errno.h> +#include <machine/syscall.h> +#include <assert.h> +#undef errno +extern int errno; + +/* write to this reg for outputting strings */ +#define STDOUT_REG 0x10000000 +/* write test result of program to this reg */ +#define RESULT_REG 0x20000000 +/* write exit value of program to this reg */ +#define EXIT_REG 0x80040000 + +#define STDOUT_FILENO 1 + +/* It turns out that older newlib versions use different symbol names which goes + * against newlib recommendations. Anyway this is fixed in later version. + */ +#if __NEWLIB__ <= 2 && __NEWLIB_MINOR__ <= 5 +#define _sbrk sbrk +#define _write write +#define _close close +#define _lseek lseek +#define _read read +#define _fstat fstat +#define _isatty isatty +#endif + +/************************************************************************************/ +/********************** STDIO_THRU_UART ********************************/ +/************************************************************************************/ +#ifdef STDIO_THRU_UART +#include "uart.h" + +#ifndef STDIO_BAUD_RATE +#define STDIO_BAUD_RATE UART_115200_BAUD +#endif + +static uart_instance_t * const gp_my_uart = &g_uart_0; + +/*------------------------------------------------------------------------------ + * Global flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +#endif /* STDIO_THRU_UART */ +/***********************************************************************************/ +/********************** END STDIO_THRU_UART ********************************/ +/************************************************************************************/ + + + +/* Upstream newlib now defines this in libgloss/riscv/internal_syscall.h. */ +long +__syscall_error(long a0) +{ + errno = -a0; + return -1; +} + +void unimplemented_syscall() +{ + const char *p = "Unimplemented system call called!\n"; + while (*p) + *(volatile int *)STDOUT_REG = *(p++); +} + +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + errno = ENOSYS; + return -1; +} + +int _access(const char *file, int mode) +{ + errno = ENOSYS; + return -1; +} + +int _chdir(const char *path) +{ + errno = ENOSYS; + return -1; +} + +int _chmod(const char *path, mode_t mode) +{ + errno = ENOSYS; + return -1; +} + +int _chown(const char *path, uid_t owner, gid_t group) +{ + errno = ENOSYS; + return -1; +} + +int _close(int file) +{ + return -1; +} + +int _execve(const char *name, char *const argv[], char *const env[]) +{ + errno = ENOMEM; + return -1; +} + +void _exit(int exit_status) +{ + *(volatile int *)EXIT_REG = exit_status; + asm volatile("wfi"); + /* _exit should not return */ + while (1) {}; +} + +int _faccessat(int dirfd, const char *file, int mode, int flags) +{ + errno = ENOSYS; + return -1; +} + +int _fork(void) +{ + errno = EAGAIN; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; + // errno = -ENOSYS; + // return -1; +} + +int _fstatat(int dirfd, const char *file, struct stat *st, int flags) +{ + errno = ENOSYS; + return -1; +} + +int _ftime(struct timeb *tp) +{ + errno = ENOSYS; + return -1; +} + +char *_getcwd(char *buf, size_t size) +{ + errno = -ENOSYS; + return NULL; +} + +int _getpid() +{ + return 1; +} + +int _gettimeofday(struct timeval *tp, void *tzp) +{ + errno = -ENOSYS; + return -1; +} + +int _isatty(int file) +{ + return (file == STDOUT_FILENO); +} + +int _kill(int pid, int sig) +{ + errno = EINVAL; + return -1; +} + +int _link(const char *old_name, const char *new_name) +{ + errno = EMLINK; + return -1; +} + +off_t _lseek(int file, off_t ptr, int dir) +{ + return 0; +} + +int _lstat(const char *file, struct stat *st) +{ + errno = ENOSYS; + return -1; +} + +int _open(const char *name, int flags, int mode) +{ + return -1; +} + +int _openat(int dirfd, const char *name, int flags, int mode) +{ + errno = ENOSYS; + return -1; +} + +ssize_t _read(int file, void *ptr, size_t len) +{ + return 0; +} + +int _stat(const char *file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; + // errno = ENOSYS; + // return -1; +} + +long _sysconf(int name) +{ + + return -1; +} + +clock_t _times(struct tms *buf) +{ + return -1; +} + +int _unlink(const char *name) +{ + errno = ENOENT; + return -1; +} + +int _utime(const char *path, const struct utimbuf *times) +{ + errno = ENOSYS; + return -1; +} + +int _wait(int *status) +{ + errno = ECHILD; + return -1; +} + +ssize_t _write(int file, const void *ptr, size_t len) +{ + +#ifdef STDIO_THRU_UART + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + + if(!g_stdio_uart_init_done) + { + UART_init(gp_my_uart, + STDIO_BAUD_RATE, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_polled_tx(gp_my_uart, (uint8_t *)ptr, len); + + return len; + + +#else /* STDIO_THRU_UART */ + + const char *cptr = (char *)ptr; + if (file != STDOUT_FILENO) + { + errno = ENOSYS; + return -1; + } + + const void *eptr = cptr + len; + while (cptr != eptr) + *(volatile int *)STDOUT_REG = *cptr++; + return len; +#endif /* STDIO_THRU_UART */ + +} + +extern char __heap_start[]; +extern char __heap_end[]; +static char *brk = __heap_start; + +int _brk(void *addr) +{ + brk = addr; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *old_brk = brk; + register long sp asm("sp"); + + char *new_brk = brk += incr; + if (new_brk < (char *) sp && new_brk < __heap_end) + { + brk = new_brk; + + return old_brk; + } + else + { + errno = ENOMEM; + return (void *) -1; + } +} + +void handle_syscall (long a0, + long a1, + long a2, + long a3, + __attribute__((unused)) long a4, + __attribute__((unused)) long a5, + __attribute__((unused)) long a6, + long a7) { + #ifdef __riscv_32e + register long syscall_id asm("t0"); + #else + long syscall_id = a7; + #endif + + switch (syscall_id) { + case SYS_exit: + _exit (a0); + break; + case SYS_read: + _read (a0, (void *) a1, a2); + break; + case SYS_write: + _write (a0, (const void *) a1, a2); + break; + case SYS_getpid: + _getpid (); + break; + case SYS_kill: + _kill (a0, a1); + break; + case SYS_open: + _open ((const char *) a0, a1, a2); + break; + case SYS_openat: + _openat (a0, (const char *) a1, a2, a3); + break; + case SYS_close: + _close (a0); + break; + case SYS_lseek: + _lseek (a0, a1, a2); + break; + case SYS_brk: + _brk ((void *) a0); + break; + case SYS_link: + _link ((const char *) a0, (const char *) a1); + break; + case SYS_unlink: + _unlink ((const char *) a0); + break; + case SYS_chdir: + _chdir ((const char *) a0); + break; + case SYS_getcwd: + _getcwd ((char *) a0, a1); + break; + case SYS_stat: + _stat ((const char *) a0, (struct stat *) a1); + break; + case SYS_fstat: + _fstat (a0, (struct stat *) a1); + break; + case SYS_lstat: + _lstat ((const char *) a0, (struct stat *) a1); + break; + case SYS_fstatat: + _fstatat (a0, (const char *) a1, (struct stat *) a2, a3); + break; + case SYS_access: + _access ((const char *) a0, a1); + break; + case SYS_faccessat: + _faccessat (a0, (const char *) a1, a2, a3); + break; + case SYS_gettimeofday: + _gettimeofday ((struct timeval *) a0, (void *) a1); + break; + case SYS_times: + _times ((struct tms *) a0); + break; + default: + unimplemented_syscall (); + break; + } +} diff --git a/bench/bsp/hal/vectors.S b/bench/bsp/hal/vectors.S new file mode 100644 index 0000000000000000000000000000000000000000..53280060b28dde8f4857efe0627485d194de54bd --- /dev/null +++ b/bench/bsp/hal/vectors.S @@ -0,0 +1,64 @@ +/* +* Copyright (c) 2020 Thales. +* Copyright 2019 ETH Zürich and University of Bologna +* +* 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. +*/ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: interrupt vector table +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + +.section .vectors, "ax" +.option norvc +.global vector_table + +vector_table: + j sw_irq_handler + j UART_0_PLIC_IRQHandler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j __no_irq_handler + j verification_irq_handler diff --git a/bench/utils/bin2mem.py b/bench/utils/bin2mem.py new file mode 100755 index 0000000000000000000000000000000000000000..a8700696897d9b23c1a6f5b7c4dd542876a7b060 --- /dev/null +++ b/bench/utils/bin2mem.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# Copyright (c) 2020 Thales. +# +# Copyright and related rights are 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 +# https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law +# or agreed to in writing, software, hardware and materials distributed under +# this 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. +# +# Author: Sebastien Jacq - sjthales on github.com +# +# Additional contributions by: +# +# +# script Name: bin2mem +# Project Name: CVA6 softcore +# Language: Python +# +# Description: Script to generate mem data file for simulation from binary +# application file. +# +# =========================================================================== # +# Revisions : +# Date Version Author Description +# 2020-10-06 0.1 S.Jacq Created +# =========================================================================== # + +import sys +import math +import binascii + +############################################################################### +# Start of file +############################################################################### +if(len(sys.argv) < 2): + print "Usage bin2mem.py FILENAME" + quit() + +filename = sys.argv[1].strip('.bin') + ".mem" + +mem_file = open(filename, 'wb') + +with open(sys.argv[1], "rb") as f: + bytes_read = f.read(8) + while bytes_read: + bytes_read_inv = bytes_read[::-1] + mem_file.write("%s\n" %binascii.hexlify(bytes_read_inv) ) + bytes_read = f.read(8) + +############################################################################### +# close all files +############################################################################### + +mem_file.close() + +