summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Manuel Merino Torres <[email protected]>2026-05-13 13:46:54 +0200
committerGitHub <[email protected]>2026-05-13 07:46:54 -0400
commit42adda44573b7c0062138818749437e6baf1044f (patch)
treefe420dacadc84908c91ea46ef5148a493f36a015
parent3c4d20285fe7aad3f04e90665b764db00a8b41ab (diff)
Added a riscv32 for the OpenHW CVA6 (#511)
-rw-r--r--cmake/riscv32-unknown-elf.cmake7
-rw-r--r--cmake/riscv32_gnu.cmake8
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/board.c42
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/build_libthreadx.sh6
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/csr.h360
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/demo_threadx.c393
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/entry.s58
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.c35
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.h24
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/link.lds49
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/plic.c72
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/plic.h49
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/trap.c66
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/tx_initialize_low_level.S163
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/uart.c893
-rw-r--r--ports/risc-v32/gnu/example_build/cva6_ariane/uart.h961
16 files changed, 3183 insertions, 3 deletions
diff --git a/cmake/riscv32-unknown-elf.cmake b/cmake/riscv32-unknown-elf.cmake
index cfd9f7ea..d21e729c 100644
--- a/cmake/riscv32-unknown-elf.cmake
+++ b/cmake/riscv32-unknown-elf.cmake
@@ -17,7 +17,12 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(CMAKE_C_FLAGS "${CFLAGS}" CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS "${CXXFLAGS}" CACHE INTERNAL "cxx compiler flags")
-set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__ -D__riscv_float_abi_single" CACHE INTERNAL "asm compiler flags")
+if(DEFINED SOFT_FLOAT)
+ set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__" CACHE INTERNAL "asm compiler flags")
+else()
+ set(CMAKE_ASM_FLAGS "${ASFLAGS} -D__ASSEMBLER__ -D__riscv_float_abi_single" CACHE INTERNAL "asm compiler flags")
+endif()
+
set(CMAKE_EXE_LINKER_FLAGS "${LDFLAGS}" CACHE INTERNAL "exe link flags")
SET(CMAKE_C_FLAGS_DEBUG "-Og -g -ggdb3" CACHE INTERNAL "c debug compiler flags")
diff --git a/cmake/riscv32_gnu.cmake b/cmake/riscv32_gnu.cmake
index 617b1276..ec8f9857 100644
--- a/cmake/riscv32_gnu.cmake
+++ b/cmake/riscv32_gnu.cmake
@@ -1,10 +1,14 @@
# Name of the target
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR risc-v32)
-
set(THREADX_ARCH "risc-v32")
set(THREADX_TOOLCHAIN "gnu")
-set(ARCH_FLAGS "-g -march=rv32gc -mabi=ilp32d -mcmodel=medany")
+if(DEFINED SOFT_FLOAT)
+ set(ARCH_FLAGS "-g -march=rv32ima_zicsr -mabi=ilp32 -mcmodel=medany")
+ set(CACHE{SOFT_FLOAT} FORCE 1)
+else()
+ set(ARCH_FLAGS "-g -march=rv32gc -mabi=ilp32d -mcmodel=medany")
+endif()
set(CFLAGS "${ARCH_FLAGS}")
set(ASFLAGS "${ARCH_FLAGS}")
set(LDFLAGS "${ARCH_FLAGS}")
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/board.c b/ports/risc-v32/gnu/example_build/cva6_ariane/board.c
new file mode 100644
index 00000000..b1c7e5c5
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/board.c
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#include "plic.h"
+#include "hwtimer.h"
+#include "uart.h"
+#include <stdint.h>
+#include <stddef.h>
+
+void *memset(const void *des, int c,size_t n)
+{
+ if((des == NULL) || n <=0)
+ return (void*)des;
+ char* t = (char*)des;
+ int i;
+ for(i=0;i<n;i++)
+ t[i]=c;
+ return t;
+}
+
+
+int board_init(void)
+{
+ int ret;
+ ret = plic_init();
+ if(ret)
+ return ret;
+ ret = uart_init();
+ if(ret)
+ return ret;
+ ret = hwtimer_init();
+ if(ret)
+ return ret;
+ return 0;
+}
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/build_libthreadx.sh b/ports/risc-v32/gnu/example_build/cva6_ariane/build_libthreadx.sh
new file mode 100644
index 00000000..53fd3492
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/build_libthreadx.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+pushd ../../../../../
+cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/riscv32_gnu.cmake -DSOFT_FLOAT=1 .
+cmake --build ./build/
+popd
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/csr.h b/ports/risc-v32/gnu/example_build/cva6_ariane/csr.h
new file mode 100644
index 00000000..1bffcf39
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/csr.h
@@ -0,0 +1,360 @@
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+
+#ifndef RISCV_CSR_H
+#define RISCV_CSR_H
+
+
+// Machine Status Register, mstatus
+#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
+#define MSTATUS_MPP_M (3L << 11)
+#define MSTATUS_MPP_S (1L << 11)
+#define MSTATUS_MPP_U (0L << 11)
+#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable.
+#define MSTATUS_MPIE (1L << 7)
+#define MSTATUS_FS (1L << 13)
+
+// Machine-mode Interrupt Enable
+#define MIE_MTIE (1L << 7)
+#define MIE_MSIE (1L << 3)
+#define MIE_MEIE (1L << 11)
+#define MIE_STIE (1L << 5) // supervisor timer
+#define MIE_SSIE (1L << 1)
+#define MIE_SEIE (1L << 9)
+
+// Supervisor Status Register, sstatus
+#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
+#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
+#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
+#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
+#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
+#define SSTATUS_SPIE (1L << 5)
+#define SSTATUS_UPIE (1L << 4)
+
+// Supervisor Interrupt Enable
+#define SIE_SEIE (1L << 9) // external
+#define SIE_STIE (1L << 5) // timer
+#define SIE_SSIE (1L << 1) // software
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+static inline uint32_t riscv_get_core()
+{
+ uint32_t x;
+ asm volatile("csrr %0, mhartid" : "=r" (x) );
+ return x;
+}
+
+static inline uint64_t riscv_get_mstatus()
+{
+ uint32_t x;
+ uint32_t xh;
+ asm volatile("csrr %0, mstatus" : "=r" (x) );
+ asm volatile("csrr %0, mstatush" : "=r" (xh) );
+ return ((uint64_t)(x)) + ((uint64_t)(xh)) << 32;
+}
+
+static inline void riscv_writ_mstatus(uint64_t x)
+{
+ asm volatile("csrw mstatus, %0" : : "r" ((uint32_t)x));
+ asm volatile("csrw mstatush, %0" : : "r" ((uint32_t)(x >> 32)));
+}
+
+// machine exception program counter, holds the
+// instruction address to which a return from
+// exception will go.
+static inline void riscv_writ_mepc(uint32_t x)
+{
+ asm volatile("csrw mepc, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_sstatus()
+{
+ uint32_t x;
+ asm volatile("csrr %0, sstatus" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_sstatus(uint32_t x)
+{
+ asm volatile("csrw sstatus, %0" : : "r" (x));
+}
+
+// Supervisor Interrupt Pending
+static inline uint32_t riscv_get_sip()
+{
+ uint32_t x;
+ asm volatile("csrr %0, sip" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_sip(uint32_t x)
+{
+ asm volatile("csrw sip, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_sie()
+{
+ uint32_t x;
+ asm volatile("csrr %0, sie" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_sie(uint32_t x)
+{
+ asm volatile("csrw sie, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_mie()
+{
+ uint32_t x;
+ asm volatile("csrr %0, mie" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_mie(uint32_t x)
+{
+ asm volatile("csrw mie, %0" : : "r" (x));
+}
+
+// supervisor exception program counter, holds the
+// instruction address to which a return from
+// exception will go.
+static inline void riscv_writ_sepc(uint32_t x)
+{
+ asm volatile("csrw sepc, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_sepc()
+{
+ uint32_t x;
+ asm volatile("csrr %0, sepc" : "=r" (x) );
+ return x;
+}
+
+// Machine Exception Delegation
+static inline uint32_t riscv_get_medeleg()
+{
+ uint32_t x;
+ asm volatile("csrr %0, medeleg" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_medeleg(uint32_t x)
+{
+ asm volatile("csrw medeleg, %0" : : "r" (x));
+}
+
+// Machine Interrupt Delegation
+static inline uint32_t riscv_get_mideleg()
+{
+ uint32_t x;
+ asm volatile("csrr %0, mideleg" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_mideleg(uint32_t x)
+{
+ asm volatile("csrw mideleg, %0" : : "r" (x));
+}
+
+// Supervisor Trap-Vector Base Address
+// low two bits are mode.
+static inline void riscv_writ_stvec(uint32_t x)
+{
+ asm volatile("csrw stvec, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_stvec()
+{
+ uint32_t x;
+ asm volatile("csrr %0, stvec" : "=r" (x) );
+ return x;
+}
+
+static inline uint32_t riscv_get_stimecmp()
+{
+ uint32_t x;
+ asm volatile("csrr %0, 0x14d" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_stimecmp(uint32_t x)
+{
+ asm volatile("csrw 0x14d, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_menvcfg()
+{
+ uint32_t x;
+ asm volatile("csrr %0, 0x30a" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_menvcfg(uint32_t x)
+{
+ asm volatile("csrw 0x30a, %0" : : "r" (x));
+}
+
+static inline void riscv_writ_pmpcfg0(uint32_t x)
+{
+ asm volatile("csrw pmpcfg0, %0" : : "r" (x));
+}
+
+static inline void riscv_writ_pmpaddr0(uint32_t x)
+{
+ asm volatile("csrw pmpaddr0, %0" : : "r" (x));
+}
+
+static inline void riscv_writ_satp(uint32_t x)
+{
+ asm volatile("csrw satp, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_satp()
+{
+ uint32_t x;
+ asm volatile("csrr %0, satp" : "=r" (x) );
+ return x;
+}
+
+static inline uint32_t riscv_get_scause()
+{
+ uint32_t x;
+ asm volatile("csrr %0, scause" : "=r" (x) );
+ return x;
+}
+
+static inline uint32_t riscv_get_stval()
+{
+ uint32_t x;
+ asm volatile("csrr %0, stval" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_mcounteren(uint32_t x)
+{
+ asm volatile("csrw mcounteren, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_mcounteren()
+{
+ uint32_t x;
+ asm volatile("csrr %0, mcounteren" : "=r" (x) );
+ return x;
+}
+
+// machine-mode cycle counter
+static inline uint64_t riscv_get_time()
+{
+ uint32_t x;
+ uint32_t xh;
+ asm volatile("csrr %0, time" : "=r" (x) );
+ asm volatile("csrr %0, timeh" : "=r" (xh) );
+ return ((uint64_t)(x)) + ((uint64_t)(xh)) << 32;
+}
+
+static inline void riscv_sintr_on()
+{
+ uint32_t sstatus = riscv_get_sstatus();
+ sstatus |= SSTATUS_SIE;
+ riscv_writ_sstatus(sstatus);
+}
+
+static inline void riscv_sintr_off()
+{
+ uint32_t sstatus = riscv_get_sstatus();
+ sstatus &= (~SSTATUS_SIE);
+ riscv_writ_sstatus(sstatus);
+}
+
+static inline int riscv_sintr_get()
+{
+ uint32_t x = riscv_get_sstatus();
+ return (x & SSTATUS_SIE) != 0;
+}
+
+static inline void riscv_sintr_restore(int x)
+{
+ if(x)
+ riscv_sintr_on();
+ else
+ riscv_sintr_off();
+}
+
+static inline void riscv_mintr_on()
+{
+ uint32_t mstatus = riscv_get_mstatus();
+ mstatus |= MSTATUS_MIE;
+ riscv_writ_mstatus(mstatus);
+}
+
+static inline void riscv_mintr_off()
+{
+ uint32_t mstatus = riscv_get_mstatus();
+ mstatus &= (~MSTATUS_MIE);
+ riscv_writ_mstatus(mstatus);
+}
+
+static inline int riscv_mintr_get()
+{
+ uint32_t x = riscv_get_mstatus();
+ return (x & MSTATUS_MIE) != 0;
+}
+
+static inline void riscv_mintr_restore(int x)
+{
+ if(x)
+ riscv_mintr_on();
+ else
+ riscv_mintr_off();
+}
+
+static inline uint32_t riscv_get_sp()
+{
+ uint32_t x;
+ asm volatile("mv %0, sp" : "=r" (x) );
+ return x;
+}
+
+// read and write tp, the thread pointer, which xv6 uses to hold
+// this core's hartid (core number), the index into cpus[].
+static inline uint32_t riscv_get_tp()
+{
+ uint32_t x;
+ asm volatile("mv %0, tp" : "=r" (x) );
+ return x;
+}
+
+static inline void riscv_writ_tp(uint32_t x)
+{
+ asm volatile("mv tp, %0" : : "r" (x));
+}
+
+static inline uint32_t riscv_get_ra()
+{
+ uint32_t x;
+ asm volatile("mv %0, ra" : "=r" (x) );
+ return x;
+}
+
+// flush the TLB.
+static inline void sfence_vma()
+{
+ // the zero, zero means flush all TLB entries.
+ asm volatile("sfence.vma zero, zero");
+}
+
+#endif // __ASSEMBLER__
+
+#endif
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/demo_threadx.c b/ports/risc-v32/gnu/example_build/cva6_ariane/demo_threadx.c
new file mode 100644
index 00000000..f21dbb26
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/demo_threadx.c
@@ -0,0 +1,393 @@
+/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight
+ threads of different priorities, using a message queue, semaphore, mutex, event flags group,
+ byte pool, and block pool. */
+
+#include "tx_api.h"
+#include "uart.h"
+
+#define DEMO_STACK_SIZE 1024
+#define DEMO_BYTE_POOL_SIZE 9120
+#define DEMO_BLOCK_POOL_SIZE 100
+#define DEMO_QUEUE_SIZE 100
+
+char *_to_str(ULONG val)
+{
+ static char buf[11]; /* 10 digits max + '\0' */
+ char *p = buf + sizeof(buf) - 1;
+
+ *p = '\0';
+ do {
+ *--p = '0' + (val % 10);
+ val /= 10;
+ } while (val);
+
+ return p;
+}
+
+/* Define the ThreadX object control blocks... */
+
+TX_THREAD thread_0;
+TX_THREAD thread_1;
+TX_THREAD thread_2;
+TX_THREAD thread_3;
+TX_THREAD thread_4;
+TX_THREAD thread_5;
+TX_THREAD thread_6;
+TX_THREAD thread_7;
+TX_QUEUE queue_0;
+TX_SEMAPHORE semaphore_0;
+TX_MUTEX mutex_0;
+TX_EVENT_FLAGS_GROUP event_flags_0;
+TX_BYTE_POOL byte_pool_0;
+TX_BLOCK_POOL block_pool_0;
+
+
+/* Define the counters used in the demo application... */
+
+ULONG thread_0_counter;
+ULONG thread_1_counter;
+ULONG thread_1_messages_sent;
+ULONG thread_2_counter;
+ULONG thread_2_messages_received;
+ULONG thread_3_counter;
+ULONG thread_4_counter;
+ULONG thread_5_counter;
+ULONG thread_6_counter;
+ULONG thread_7_counter;
+
+
+/* Define thread prototypes. */
+
+void thread_0_entry(ULONG thread_input);
+void thread_1_entry(ULONG thread_input);
+void thread_2_entry(ULONG thread_input);
+void thread_3_and_4_entry(ULONG thread_input);
+void thread_5_entry(ULONG thread_input);
+void thread_6_and_7_entry(ULONG thread_input);
+
+
+/* Define main entry point. */
+
+int main()
+{
+
+ /* Enter the ThreadX kernel. */
+ tx_kernel_enter();
+}
+
+
+/* Define what the initial system looks like. */
+
+void tx_application_define(void *first_unused_memory)
+{
+ CHAR *pointer = TX_NULL;
+
+ /* Create a byte memory pool from which to allocate the thread stacks. */
+ tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
+
+ /* Put system definition stuff in here, e.g. thread creates and other assorted
+ create information. */
+
+ /* Allocate the stack for thread 0. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ /* Create the main thread. */
+ tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
+ pointer, DEMO_STACK_SIZE,
+ 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+
+ /* Allocate the stack for thread 1. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ /* Create threads 1 and 2. These threads pass information through a ThreadX
+ message queue. It is also interesting to note that these threads have a time
+ slice. */
+ tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
+ pointer, DEMO_STACK_SIZE,
+ 16, 16, 4, TX_AUTO_START);
+
+ /* Allocate the stack for thread 2. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
+ pointer, DEMO_STACK_SIZE,
+ 16, 16, 4, TX_AUTO_START);
+
+ /* Allocate the stack for thread 3. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
+ An interesting thing here is that both threads share the same instruction area. */
+ tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
+ pointer, DEMO_STACK_SIZE,
+ 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+ /* Allocate the stack for thread 4. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
+ pointer, DEMO_STACK_SIZE,
+ 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+ /* Allocate the stack for thread 5. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ /* Create thread 5. This thread simply pends on an event flag which will be set
+ by thread_0. */
+ tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
+ pointer, DEMO_STACK_SIZE,
+ 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+ /* Allocate the stack for thread 6. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
+ tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
+ pointer, DEMO_STACK_SIZE,
+ 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+ /* Allocate the stack for thread 7. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
+
+ tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
+ pointer, DEMO_STACK_SIZE,
+ 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
+
+ /* Allocate the message queue. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
+
+ /* Create the message queue shared by threads 1 and 2. */
+ tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
+
+ /* Create the semaphore used by threads 3 and 4. */
+ tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
+
+ /* Create the event flags group used by threads 1 and 5. */
+ tx_event_flags_create(&event_flags_0, "event flags 0");
+
+ /* Create the mutex used by thread 6 and 7 without priority inheritance. */
+ tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
+
+ /* Allocate the memory for a small block pool. */
+ tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
+
+ /* Create a block memory pool to allocate a message buffer from. */
+ tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
+
+ /* Allocate a block and release the block memory. */
+ tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
+
+ /* Release the block back to the pool. */
+ tx_block_release(pointer);
+}
+
+
+
+/* Define the test threads. */
+
+void thread_0_entry(ULONG thread_input)
+{
+
+UINT status;
+
+
+ /* This thread simply sits in while-forever-sleep loop. */
+ while(1)
+ {
+ puts("[Thread] : thread_0_entry is here!");
+
+ /* Increment the thread counter. */
+ thread_0_counter++;
+
+ /* Sleep for 10 ticks. */
+ tx_thread_sleep(10);
+
+ /* Set event flag 0 to wakeup thread 5. */
+ status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+ }
+}
+
+
+void thread_1_entry(ULONG thread_input)
+{
+
+UINT status;
+
+ /* This thread simply sends messages to a queue shared by thread 2. */
+ while(1)
+ {
+ puts("[Thread] : thread_1_entry is here!");
+ /* Increment the thread counter. */
+ thread_1_counter++;
+
+ /* Send message to queue 0. */
+ status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
+
+ /* Check completion status. */
+ if (status != TX_SUCCESS) {
+ puts("[Thread 1] ERROR: Failed to send message!");
+ break;
+ }
+
+ /* Increment the message sent. */
+ thread_1_messages_sent++;
+ }
+}
+
+
+
+void thread_2_entry(ULONG thread_input)
+{
+
+ULONG received_message;
+UINT status;
+
+ /* This thread retrieves messages placed on the queue by thread 1. */
+ while(1)
+ {
+ puts("[Thread] : thread_2_entry is here!");
+ /* Increment the thread counter. */
+ thread_2_counter++;
+
+ /* Retrieve a message from the queue. */
+ status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
+
+ /* Check completion status and make sure the message is what we
+ expected. */
+ if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)){
+ puts("[Thread 2] ERROR: Failed to receive message ! Expected # ");
+ uart_puts(_to_str(thread_2_messages_received));
+ puts(", but got # ");
+ uart_puts(_to_str(received_message));
+ break;
+ }
+
+ /* Otherwise, all is okay. Increment the received message count. */
+ thread_2_messages_received++;
+ }
+}
+
+
+void thread_3_and_4_entry(ULONG thread_input)
+{
+
+UINT status;
+
+
+ /* This function is executed from thread 3 and thread 4. As the loop
+ below shows, these function compete for ownership of semaphore_0. */
+ while(1)
+ {
+ puts("[Thread] : thread_3_and_4_entry is here!");
+
+
+ /* Increment the thread counter. */
+ if (thread_input == 3)
+ thread_3_counter++;
+ else
+ thread_4_counter++;
+
+ /* Get the semaphore with suspension. */
+ status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+
+ /* Sleep for 2 ticks to hold the semaphore. */
+ tx_thread_sleep(2);
+
+ /* Release the semaphore. */
+ status = tx_semaphore_put(&semaphore_0);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+ }
+}
+
+
+void thread_5_entry(ULONG thread_input)
+{
+
+UINT status;
+ULONG actual_flags;
+
+
+ /* This thread simply waits for an event in a forever loop. */
+ while(1)
+ {
+ puts("[Thread] : thread_5_entry is here!");
+
+ /* Increment the thread counter. */
+ thread_5_counter++;
+
+ /* Wait for event flag 0. */
+ status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
+ &actual_flags, TX_WAIT_FOREVER);
+
+ /* Check status. */
+ if ((status != TX_SUCCESS) || (actual_flags != 0x1))
+ break;
+ }
+}
+
+
+void thread_6_and_7_entry(ULONG thread_input)
+{
+
+UINT status;
+
+
+ /* This function is executed from thread 6 and thread 7. As the loop
+ below shows, these function compete for ownership of mutex_0. */
+ while(1)
+ {
+ puts("[Thread] : thread_6_and_7_entry is here!");
+
+ /* Increment the thread counter. */
+ if (thread_input == 6)
+ thread_6_counter++;
+ else
+ thread_7_counter++;
+
+ /* Get the mutex with suspension. */
+ status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+
+ /* Get the mutex again with suspension. This shows
+ that an owning thread may retrieve the mutex it
+ owns multiple times. */
+ status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+
+ /* Sleep for 2 ticks to hold the mutex. */
+ tx_thread_sleep(2);
+
+ /* Release the mutex. */
+ status = tx_mutex_put(&mutex_0);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+
+ /* Release the mutex again. This will actually
+ release ownership since it was obtained twice. */
+ status = tx_mutex_put(&mutex_0);
+
+ /* Check status. */
+ if (status != TX_SUCCESS)
+ break;
+ }
+}
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/entry.s b/ports/risc-v32/gnu/example_build/cva6_ariane/entry.s
new file mode 100644
index 00000000..9b202ca1
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/entry.s
@@ -0,0 +1,58 @@
+
+.section .text
+.align 4
+.global _start
+.extern main
+.extern _sysstack_start
+.extern _bss_start
+.extern _bss_end
+_start:
+ csrr t0, mhartid
+ bne t0, zero, 1f
+ li x1, 0
+ li x2, 0
+ li x3, 0
+ li x4, 0
+ li x5, 0
+ li x6, 0
+ li x7, 0
+ li x8, 0
+ li x9, 0
+ li x10, 0
+ li x11, 0
+ li x12, 0
+ li x13, 0
+ li x14, 0
+ li x15, 0
+ li x16, 0
+ li x17, 0
+ li x18, 0
+ li x19, 0
+ li x20, 0
+ li x21, 0
+ li x22, 0
+ li x23, 0
+ li x24, 0
+ li x25, 0
+ li x26, 0
+ li x27, 0
+ li x28, 0
+ li x29, 0
+ li x30, 0
+ li x31, 0
+ la t0, _sysstack_start
+ li t1, 0x1000
+ add sp, t0, t1
+ la t0, _bss_start
+ la t1, _bss_end
+_bss_clean_start:
+ bgeu t0, t1, _bss_clean_end
+ sb zero, 0(t0)
+ addi t0, t0, 1
+ j _bss_clean_start
+_bss_clean_end:
+ call main
+1:
+ /* todo smp */
+ wfi
+ j 1b
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.c b/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.c
new file mode 100644
index 00000000..b5335cf3
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.c
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#include "tx_port.h"
+#include "csr.h"
+#include "hwtimer.h"
+
+#define CLINT (0x02000000L)
+#define CLINT_TIME (CLINT+0xBFF8)
+#define CLINT_TIMECMP(hart_id) (CLINT+0x4000+8*(hart_id))
+
+
+int hwtimer_init(void)
+{
+ int hart = riscv_get_core();
+ uint64_t time = *((uint64_t*)CLINT_TIME);
+ *((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
+ return 0;
+}
+
+int hwtimer_handler(void)
+{
+ int hart = riscv_get_core();
+ uint64_t time = *((uint64_t*)CLINT_TIME);
+ *((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER;
+ return 0;
+}
+
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.h b/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.h
new file mode 100644
index 00000000..9e4a066d
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/hwtimer.h
@@ -0,0 +1,24 @@
+
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#ifndef RISCV_HWTIMER_H
+#define RISCV_HWTIMER_H
+
+#include <stdint.h>
+
+#define TICKNUM_PER_SECOND 50000000
+#define TICKNUM_PER_TIMER (TICKNUM_PER_SECOND / 100)
+
+int hwtimer_init(void);
+
+int hwtimer_handler(void);
+
+#endif
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/link.lds b/ports/risc-v32/gnu/example_build/cva6_ariane/link.lds
new file mode 100644
index 00000000..619080e7
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/link.lds
@@ -0,0 +1,49 @@
+OUTPUT_ARCH( "riscv" )
+ENTRY( _start )
+
+SECTIONS
+{
+ /*
+ * ensure that entry.S / _entry is at 0x80000000,
+ * where arianes's -kernel jumps.
+ */
+ . = 0x80000000;
+
+ .text : {
+ *(.text .text.*)
+ . = ALIGN(0x1000);
+ PROVIDE(etext = .);
+ }
+
+ .rodata : {
+ . = ALIGN(16);
+ *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
+ . = ALIGN(16);
+ *(.rodata .rodata.*)
+ }
+
+ .data : {
+ . = ALIGN(16);
+ *(.sdata .sdata.*) /* do not need to distinguish this from .data */
+ . = ALIGN(16);
+ *(.data .data.*)
+ }
+
+ .bss : {
+ . = ALIGN(16);
+ _bss_start = .;
+ *(.sbss .sbss.*) /* do not need to distinguish this from .bss */
+ . = ALIGN(16);
+ *(.bss .bss.*)
+ _bss_end = .;
+ }
+
+ .stack : {
+ . = ALIGN(4096);
+ _sysstack_start = .;
+ . += 0x1000;
+ _sysstack_end = .;
+ }
+
+ PROVIDE(_end = .);
+}
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/plic.c b/ports/risc-v32/gnu/example_build/cva6_ariane/plic.c
new file mode 100644
index 00000000..01e5c71a
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/plic.c
@@ -0,0 +1,72 @@
+#include "plic.h"
+#include <stddef.h>
+irq_callback callbacks[MAX_CALLBACK_NUM];
+
+void plic_irq_enable(int irqno)
+{
+ int hart = riscv_get_core();
+ *(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) | (1 << irqno));
+ return;
+}
+
+void plic_irq_disable(int irqno)
+{
+ int hart = riscv_get_core();
+ *(uint32_t*)PLIC_MENABLE(hart) = (*(uint32_t*)PLIC_MENABLE(hart) & (~(1 << irqno)));
+ return;
+}
+
+void plic_prio_set(int irqno, int prio)
+{
+ PLIC_SET_PRIO(irqno, prio);
+}
+
+int plic_prio_get(int irqno)
+{
+ return PLIC_GET_PRIO(irqno);
+}
+
+int plic_register_callback(int irqno, irq_callback callback)
+{
+ if(!(irqno >=0 && irqno < MAX_CALLBACK_NUM))
+ return -1;
+ callbacks[irqno] = callback;
+ return 0;
+}
+
+int plic_unregister_callback(int irqno)
+{
+ return plic_register_callback(irqno, NULL);
+}
+
+int plic_init(void)
+{
+ for(int i=0;i<MAX_CALLBACK_NUM;i++)
+ {
+ callbacks[i] = NULL;
+ }
+ return 0;
+}
+
+int plic_claim(void)
+{
+ int hart = riscv_get_core();
+ return (*(uint32_t*)PLIC_MCLAIM(hart));
+}
+
+void plic_complete(int irqno)
+{
+ int hart = riscv_get_core();
+ *(uint32_t*)(PLIC_MCOMPLETE(hart)) = (uint32_t)irqno;
+ return;
+}
+
+int plic_irq_intr(void)
+{
+ int ret = -1;
+ int irqno = plic_claim();
+ if(callbacks[irqno] != NULL)
+ ret = (callbacks[irqno])(irqno);
+ plic_complete(irqno);
+ return ret;
+}
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/plic.h b/ports/risc-v32/gnu/example_build/cva6_ariane/plic.h
new file mode 100644
index 00000000..bfffaec7
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/plic.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#ifndef RISCV_PLIC_H
+#define RISCV_PLIC_H
+
+#include "csr.h"
+#include <stdint.h>
+
+#define PLIC 0x0C000000L
+#define PLIC_PRIORITY (PLIC + 0x0)
+#define PLIC_PENDING (PLIC + 0x1000)
+#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
+#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
+#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
+#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
+#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
+#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
+#define PLIC_MCOMPLETE(hart) (PLIC + 0x200004 + (hart)*0x2000)
+#define PLIC_SCOMPLETE(hart) (PLIC + 0x201004 + (hart)*0x2000)
+
+
+#define PLIC_GET_PRIO(irqno) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4))
+#define PLIC_SET_PRIO(irqno, prio) (*(uint32_t *)(PLIC_PRIORITY + (irqno)*4) = (prio))
+
+#define MAX_CALLBACK_NUM 128
+typedef int (*irq_callback)(int irqno);
+
+void plic_irq_enable(int irqno);
+void plic_irq_disable(int irqno);
+int plic_prio_get(int irqno);
+void plic_prio_set(int irqno, int prio);
+int plic_register_callback(int irqno, irq_callback callback);
+int plic_unregister_callback(int irqno);
+int plic_init(void);
+int plic_claim(void);
+void plic_complete(int irqno);
+
+int plic_irq_intr(void);
+
+#endif
+
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/trap.c b/ports/risc-v32/gnu/example_build/cva6_ariane/trap.c
new file mode 100644
index 00000000..3d2467fb
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/trap.c
@@ -0,0 +1,66 @@
+#include "csr.h"
+#include <stdint.h>
+#include "uart.h"
+#include "hwtimer.h"
+#include "plic.h"
+#include <tx_port.h>
+#include <tx_api.h>
+
+#define OS_IS_INTERUPT(mcause) (mcause & 0x80000000u)
+#define OS_IS_EXCEPTION(mcause) (~(OS_IS_INTERUPT))
+#define OS_IS_TICK_INT(mcause) (mcause == 0x80000007u)
+#define OS_IS_SOFT_INT(mcause) (mcause == 0x80000003u)
+#define OS_IS_EXT_INT(mcause) (mcause == 0x8000000bu)
+#define OS_IS_TRAP_USER(mcause) (mcause == 0x0000000bu)
+extern void _tx_timer_interrupt(void);
+
+extern int uart_putc(int ch);
+
+static void print_hex(uintptr_t val)
+{
+ char digits[] = "0123456789ABCDEF";
+ uart_putc('0');
+ uart_putc('x');
+ for(int i = (sizeof(uintptr_t)*2) - 1; i >= 0; i--) {
+ int d = (val >> (i*4)) & 0xF;
+ uart_putc(digits[d]);
+ }
+ uart_putc('\n');
+}
+
+void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval)
+{
+ if(OS_IS_INTERUPT(mcause))
+ {
+ if(OS_IS_TICK_INT(mcause))
+ {
+ hwtimer_handler();
+ _tx_timer_interrupt();
+ }
+ else if(OS_IS_EXT_INT(mcause))
+ {
+ int ret = plic_irq_intr();
+ if(ret)
+ {
+ puts("[INTERRUPT]: handler irq error!");
+ while(1) ;
+ }
+ }
+ else
+ {
+ puts("[INTERRUPT]: now can't deal with the interrupt!");
+ while(1) ;
+ }
+ }
+ else
+ {
+ puts("[EXCEPTION] : Unkown Error!!");
+ puts("mcause:");
+ print_hex(mcause);
+ puts("mepc:");
+ print_hex(mepc);
+ puts("mtval:");
+ print_hex(mtval);
+ while(1) ;
+ }
+}
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/tx_initialize_low_level.S b/ports/risc-v32/gnu/example_build/cva6_ariane/tx_initialize_low_level.S
new file mode 100644
index 00000000..16910f76
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/tx_initialize_low_level.S
@@ -0,0 +1,163 @@
+/***************************************************************************
+ * Copyright (c) 2026 Quintauris
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#include "csr.h"
+#include "tx_port.h"
+
+ .section .text
+ .align 4
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* trap_entry RISC-V32/GNU */
+/* 6.4.x */
+/* AUTHOR */
+/* */
+/* Francisco Merino, Quintauris */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function is responsible for riscv processor trap handle */
+/* It will do the contex save and call c trap_handler and do contex */
+/* load */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* None */
+/* */
+/* CALLS */
+/* */
+/* trap_handler */
+/* */
+/* CALLED BY */
+/* */
+/* hardware exception */
+/* */
+/**************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** Initialize */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+ .global trap_entry
+ .extern trap_handler
+ .extern _tx_thread_context_restore
+ trap_entry:
+#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
+ addi sp, sp, -65*4 // Allocate space for all registers - with floating point enabled
+#else
+ addi sp, sp, -32*4 // Allocate space for all registers - without floating point enabled
+#endif
+
+ sw x1, 28*4(sp) // Store RA, 28*4(because call will override ra [ra is a calle register in riscv])
+
+ call _tx_thread_context_save
+
+ csrr a0, mcause
+ csrr a1, mepc
+ csrr a2, mtval
+ addi sp, sp, -4
+ sw ra, 0(sp)
+ call trap_handler
+ lw ra, 0(sp)
+ addi sp, sp, 4
+ call _tx_thread_context_restore
+ // it will nerver return
+_err:
+ wfi
+ j _err
+ .section .text
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _tx_initialize_low_level RISC-V32/GNU */
+/* 6.4.x */
+/* AUTHOR */
+/* */
+/* Francisco Merino, Quintauris */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function is responsible for any low-level processor */
+/* initialization, including setting up interrupt vectors, setting */
+/* up a periodic timer interrupt source, saving the system stack */
+/* pointer for use in ISR processing later, and finding the first */
+/* available RAM memory address for tx_application_define. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* None */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _tx_initialize_kernel_enter ThreadX entry function */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 11-03-2026 Francisco Merino Adapted for RV32 from RV64 port */
+/* */
+/**************************************************************************/
+/* VOID _tx_initialize_low_level(VOID)
+{ */
+ .global _tx_initialize_low_level
+ .weak _tx_initialize_low_level
+ .extern _end
+ .extern board_init
+_tx_initialize_low_level:
+
+ .section .text
+
+ la t0, _tx_thread_system_stack_ptr
+ sw sp, 0(t0) // Save system stack pointer
+
+ la t0, _end // Pickup first free address
+ la t1, _tx_initialize_unused_memory
+ sw t0, 0(t1) // Save unused memory address
+ li t0, MSTATUS_MIE
+ csrrc zero, mstatus, t0 // clear MSTATUS_MIE bit
+ li t0, (MSTATUS_MPP_M | MSTATUS_MPIE )
+ csrrs zero, mstatus, t0 // set MSTATUS_MPP, MPIE bit
+ li t0, (MIE_MTIE | MIE_MSIE | MIE_MEIE)
+ csrrs zero, mie, t0 // set mie
+#ifdef __riscv_flen
+ li t0, MSTATUS_FS
+ csrrs zero, mstatus, t0 // set MSTATUS_FS bit to open f/d isa in riscv
+ fscsr x0
+#endif
+ addi sp, sp, -4
+ sw ra, 0(sp)
+ call board_init
+ lw ra, 0(sp)
+ addi sp, sp, 4
+ la t0, trap_entry
+ csrw mtvec, t0
+ ret
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/uart.c b/ports/risc-v32/gnu/example_build/cva6_ariane/uart.c
new file mode 100644
index 00000000..c92c67e6
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/uart.c
@@ -0,0 +1,893 @@
+/*******************************************************************************
+ * 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
+// Anjali Gedam - anjaliigedam 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
+// 2021-07-12 0.2 Anjali G modification for the CVA6 FPGA
+// =========================================================================== //
+
+
+#include "uart.h"
+
+//#include "../plic/plic.h"
+//#include "../hw_platform.h"
+#define FPGA_UART_0_FREQUENCY 50000000
+#define FPGA_UART_0_BASE (UART_TypeDef *)0x10000000
+#define STDIO_BAUD_RATE UART_115200_BAUD
+
+/*******************************************************************************
+ * 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
+
+
+//#define PLIC_DEMO 1
+// Source/portable/GCC/RISC-V/portASM.S:290:freertos_risc_v_application_interrupt_handler (weak function : User application can add there own override)
+
+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);
+ //printf("UART_get_rx() called buff_size = %d\n", buff_size);
+
+ if ((rx_buff != (uint8_t*)0) && (buff_size > 0u))
+ {
+ status = this_uart->hw_reg->LSR;
+ this_uart->status |= status;
+ //printf("UART_get_rx() LSR status = %d\n", 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;
+ //printf("1 UART_get_rx() LSR status = %d\n", status);
+ this_uart->status |= status;
+ //printf("2 UART_get_rx() LSR status = %d\n", 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);
+#ifdef PLIC_DEMO
+ PLIC_init();
+#endif
+
+ if ((handler != INVALID_IRQ_HANDLER) &&
+ (trigger_level < UART_FIFO_INVALID_TRIG_LEVEL))
+ {
+ //printf("UART DEBUG1\n");
+ 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;
+ //printf("UART Enable IRQ\n");
+ 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);
+
+ //printf("UART_get_rx_status = %d", status);
+ //printf("UART_get_rx_LSR = %d", this_uart->hw_reg->LSR);
+
+
+ /* 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;
+ //printf("UART_get_modem_status = %d", status);
+
+ 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;
+ /* Note that we may need to set this as 64 bits for high frequencies */
+ uint32_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 __attribute__ ((unused))
+uart_isr
+(
+ uart_instance_t * this_uart
+)
+{
+ //printf("uart_isr called\n");
+ 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);
+ }
+ }
+ break;
+
+ 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 __attribute__ ((unused))
+enable_irq
+(
+ const uart_instance_t * this_uart
+)
+{
+
+#ifdef PLIC_DEMO
+ PLIC_IRQn_Type plic_num = 0;
+#endif
+
+ if (&g_uart_0 == this_uart )
+ {
+ //printf("enable_irq() UART assign plic_num = %d\n",plic_num);
+#ifdef PLIC_DEMO
+ plic_num = UART_0_PLIC_IRQHandler;
+#endif
+
+ }
+ else
+ {
+ //printf("ASSERT(0) called\n");
+ //ASSERT(0); /*Alternative case has been considered*/
+ }
+
+#ifdef PLIC_DEMO
+ /* Enable UART instance interrupt in PLIC. */
+ PLIC_EnableIRQ(plic_num);
+#endif
+}
+
+static void __attribute__ ((unused))
+disable_irq
+(
+ const uart_instance_t * this_uart
+)
+{
+#ifdef PLIC_DEMO
+ PLIC_IRQn_Type plic_num = 0;
+#endif
+
+ if (&g_uart_0 == this_uart )
+ {
+#ifdef PLIC_DEMO
+ plic_num = UART_0_PLIC_IRQHandler;
+#endif
+ }
+ else
+ {
+ //ASSERT(0); /*Alternative case has been considered*/
+ }
+
+ /* Disable UART instance interrupt in PLIC. */
+#ifdef PLIC_DEMO
+ PLIC_DisableIRQ(plic_num);
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////
+
+static uart_instance_t * const gp_my_uart = &g_uart_0;
+
+int uart_init(void)
+{
+ UART_init(gp_my_uart, STDIO_BAUD_RATE, ( UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT ) );
+
+ return 0;
+}
+
+int uart_putc(int ch)
+{
+ UART_polled_tx(gp_my_uart, (const uint8_t *)&ch, 1);
+}
+
+int uart_puts(const char* str)
+{
+ UART_polled_tx_string(gp_my_uart, str);
+} \ No newline at end of file
diff --git a/ports/risc-v32/gnu/example_build/cva6_ariane/uart.h b/ports/risc-v32/gnu/example_build/cva6_ariane/uart.h
new file mode 100644
index 00000000..0a835727
--- /dev/null
+++ b/ports/risc-v32/gnu/example_build/cva6_ariane/uart.h
@@ -0,0 +1,961 @@
+/***************************************************************************
+ * Copyright (c) 2024 Microsoft Corporation
+ * Copyright (c) 2026 Eclipse ThreadX contributors
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT.
+ *
+ * SPDX-License-Identifier: MIT
+ **************************************************************************/
+
+#ifndef RISCV_UART_H
+#define RISCV_UART_H
+
+#define UART0 0x10000000L
+#define UART0_IRQ 10
+
+#define puts(str) uart_puts(str"\n\r")
+int uart_init(void);
+int uart_putc(int ch);
+int uart_puts(const char* str);
+#endif
+
+
+/*******************************************************************************
+ * 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
+// Anjali Gedam - anjaliigedam 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
+// 2021-07-12 0.2 Anjali G modification for the CVA6 FPGA
+// =========================================================================== //
+
+#ifndef __UART1_H_
+#define __UART1_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_ariane
+(
+ 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_*/
+