initial commit

This commit is contained in:
2026-01-27 20:45:47 +01:00
commit 1e5eb44ca9
53 changed files with 11048 additions and 0 deletions

6
port/moonlight/README.md Normal file
View File

@@ -0,0 +1,6 @@
## Generation of register files
```
pip install --extra-index-url https://git.minres.com/api/packages/Tools/pypi/simple peakrdl-mnrs
mnrs_gen --firmware -o port/moonlight EthMac.rdl
```

39
port/moonlight/aclint.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef _DEVICES_ACLINT_H
#define _DEVICES_ACLINT_H
#include "gen/aclint.h"
#include <stdint.h>
static void set_aclint_mtime(volatile aclint_t* reg, uint64_t value) {
set_aclint_mtime_hi(reg, (uint32_t)(value >> 32));
set_aclint_mtime_lo(reg, (uint32_t)value);
}
static uint64_t get_aclint_mtime(volatile aclint_t* reg) {
#if(__riscv_xlen == 64)
// this assume little endianness
volatile uint64_t* mtime = (volatile uint64_t*)(uint64_t)(&reg->MTIME_LO);
return *mtime;
#else
uint32_t mtimeh_val;
uint32_t mtimel_val;
do {
mtimeh_val = get_aclint_mtime_hi(reg);
mtimel_val = get_aclint_mtime_lo(reg);
} while(mtimeh_val != get_aclint_mtime_hi(reg));
return (uint64_t)((((uint64_t)mtimeh_val) << 32) | mtimel_val);
#endif
}
static void set_aclint_mtimecmp(volatile aclint_t* reg, uint64_t value) {
set_aclint_mtimecmp0lo(reg, (uint32_t)0xFFFFFFFF);
set_aclint_mtimecmp0hi(reg, (uint32_t)(value >> 32));
set_aclint_mtimecmp0lo(reg, (uint32_t)value);
}
static uint64_t get_aclint_mtimecmp(volatile aclint_t* reg) {
uint64_t value = ((uint64_t)get_aclint_mtimecmp0hi(reg) << 32) | (uint64_t)get_aclint_mtimecmp0lo(reg);
return value;
}
#endif /* _DEVICES_ACLINT_H */

39
port/moonlight/board.c Normal file
View File

@@ -0,0 +1,39 @@
#include "hwtimer.h"
#include "csr.h"
#include "platform.h"
#include "uart.h"
#include <stdio.h>
#include <stdarg.h>
// needed by picolibc/port.c
int uart_putc(int ch) {
int intr_enable = riscv_mintr_get();
riscv_mintr_off();
uart_write(uart, ch);
riscv_mintr_restore(intr_enable);
return 1;
}
int uart_getc(void) {
int intr_enable = riscv_mintr_get();
riscv_mintr_off();
int ch = uart_read(uart);
riscv_mintr_restore(intr_enable);
return ch;
}
int uart_init(void) {
puts("[UART0] : Uart Init Done, this is Test output!");
return 0;
};
int board_init(void) {
int ret;
ret = uart_init();
if(ret)
return ret;
ret = hwtimer_init();
if(ret)
return ret;
return 0;
}

101
port/moonlight/bootup.c Normal file
View File

@@ -0,0 +1,101 @@
/*
Simple C++ startup routine to setup CRT
SPDX-License-Identifier: Unlicense
(https://five-embeddev.com/ | http://www.shincbm.com/)
*/
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
// Generic C function pointer.
typedef void(*function_t)(void) ;
// These symbols are defined by the linker script.
// See linker.lds
EXTERN_C uint8_t __bss_start;
EXTERN_C uint8_t __bss_end;
EXTERN_C const uint8_t __data_source;
EXTERN_C uint8_t __data_start;
EXTERN_C uint8_t __data_end;
EXTERN_C function_t __init_array_start;
EXTERN_C function_t __init_array_end;
EXTERN_C function_t __fini_array_start;
EXTERN_C function_t __fini_array_end;
// This function will be placed by the linker script according to the section
// Raw function 'called' by the CPU with no runtime.
EXTERN_C void _start(void) __attribute__ ((naked,section(".text.init")));
// Entry and exit points as C functions.
EXTERN_C void _initialize(void) __attribute__ ((noreturn,section(".init")));
EXTERN_C void _exit(int exit_code) __attribute__ ((noreturn,noinline,weak));
// Standard entry point, no arguments.
extern int main(void);
// The linker script will place this in the reset entry point.
// It will be 'called' with no stack or C runtime configuration.
// NOTE - this only supports a single hart.
// tp will not be initialized
void _start(void) {
// Setup SP and GP
// The locations are defined in the linker script
__asm__ volatile (
".option push;"
// The 'norelax' option is critical here.
// Without 'norelax' the global pointer will
// be loaded relative to the global pointer!
".option norelax;"
"la gp, __global_pointer$;"
".option pop;"
"la sp, _sp;"
"jal zero, _initialize;"
: /* output: none %0 */
: /* input: none */
: /* clobbers: none */);
// This point will not be executed, _initialize() will be called with no return.
}
// At this point we have a stack and global poiner, but no access to global variables.
void _initialize(void) {
// Init memory regions
// Clear the .bss section (global variables with no initial values)
memset((void*) &__bss_start,
0,
(&__bss_end - &__bss_start));
// Initialize the .data section (global variables with initial values)
memcpy((void*)&__data_start,
(const void*)&__data_source,
(&__data_end - &__data_end));
// Call constructors
for (const function_t* entry=&__init_array_start;
entry < &__init_array_end;
++entry) {
(*entry)();
}
int rc = main();
// Call destructors
for (const function_t* entry=&__fini_array_start;
entry < &__fini_array_end;
++entry) {
(*entry)();
}
_exit(rc);
}
// This should never be called. Busy loop with the CPU in idle state.
void _exit(int exit_code) {
(void)exit_code;
// Halt
while (1) {
__asm__ volatile ("wfi");
}
}

View File

@@ -0,0 +1,79 @@
#include <stdint.h>
#include <stdio.h>
#include "riscv-traps.h"
#include "riscv-csr.h"
// Expect this to increment one time per second - inside exception handler, after each return of MTI handler.
static volatile uint64_t ecall_count = 0;
void exception(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval) {
switch(mcause) {
case RISCV_EXCP_INSTRUCTION_ADDRESS_MISALIGNED: {
puts("[EXCEPTION] : Instruction address misaligned\n");
break;
}
case RISCV_EXCP_INSTRUCTION_ACCESS_FAULT: {
puts("[EXCEPTION] : Instruction access fault\n");
break;
}
case RISCV_EXCP_ILLEGAL_INSTRUCTION: {
puts("[EXCEPTION] : Illegal Instruction\n");
break;
}
case RISCV_EXCP_BREAKPOINT: {
puts("[EXCEPTION] : Breakpoint\n");
break;
}
case RISCV_EXCP_LOAD_ADDRESS_MISALIGNED: {
puts("[EXCEPTION] : Load address misaligned");
printf("[EXCEPTION] : PC: 0x%x\n", mepc);
printf("[EXCEPTION] : Addr: 0x%x\n", mtval);
break;
}
case RISCV_EXCP_LOAD_ACCESS_FAULT: {
puts("[EXCEPTION] : Load access fault\n");
break;
}
case RISCV_EXCP_STORE_AMO_ADDRESS_MISALIGNED: {
puts("[EXCEPTION] : Store/AMO address misaligned");
printf("[EXCEPTION] : PC: 0x%x\n", mepc);
printf("[EXCEPTION] : Addr: 0x%x\n", mtval);
break;
}
case RISCV_EXCP_STORE_AMO_ACCESS_FAULT: {
puts("[EXCEPTION] : Store/AMO access fault\n");
break;
}
case RISCV_EXCP_ENVIRONMENT_CALL_FROM_U_MODE: {
puts("[EXCEPTION] : Environment call from U-mode\n");
break;
}
case RISCV_EXCP_ENVIRONMENT_CALL_FROM_S_MODE: {
puts("[EXCEPTION] : Environment call from S-mode\n");
break;
}
case RISCV_EXCP_ENVIRONMENT_CALL_FROM_M_MODE: {
puts("[EXCEPTION] : Environment call from M-mode\n");
ecall_count++;
csr_write_mepc(mepc+4);
break;
}
case RISCV_EXCP_INSTRUCTION_PAGE_FAULT: {
puts("[EXCEPTION] : Instruction page fault\n");
break;
}
case RISCV_EXCP_LOAD_PAGE_FAULT: {
puts("[EXCEPTION] : Load page fault\n");
break;
}
case RISCV_EXCP_STORE_AMO_PAGE_FAULT: {
puts("[EXCEPTION] : Store/AMO page fault\n");
break;
}
default: {
printf("[EXCEPTION] : Unknown trap cause: %lu\n", mcause);
}
}
while(1)
;
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2023 - 2024 MINRES Technologies GmbH
*
* SPDX-License-Identifier: Apache-2.0
*
* Generated at 2024-08-02 08:46:07 UTC
* by peakrdl_mnrs version 1.2.7
*/
#ifndef _BSP_ACLINT_H
#define _BSP_ACLINT_H
#include <stdint.h>
typedef struct {
volatile uint32_t MSIP[4096];
struct {
volatile uint32_t LO;
volatile uint32_t HI;
} MTIMECMP[4095];
volatile uint32_t MTIME_LO;
volatile uint32_t MTIME_HI;
} aclint_t;
#define ACLINT_MSIP_OFFS 0
#define ACLINT_MSIP_MASK 0x1
#define ACLINT_MSIP(V) ((V & ACLINT_MSIP0_MASK) << ACLINT_MSIP0_OFFS)
#define ACLINT_MTIMECMPLO_OFFS 0
#define ACLINT_MTIMECMPLO_MASK 0xffffffff
#define ACLINT_MTIMECMPLO(V) ((V & ACLINT_MTIMECMP0LO_MASK) << ACLINT_MTIMECMP0LO_OFFS)
#define ACLINT_MTIMECMPHI_OFFS 0
#define ACLINT_MTIMECMPHI_MASK 0xffffffff
#define ACLINT_MTIMECMPHI(V) ((V & ACLINT_MTIMECMP0HI_MASK) << ACLINT_MTIMECMP0HI_OFFS)
#define ACLINT_MTIME_LO_OFFS 0
#define ACLINT_MTIME_LO_MASK 0xffffffff
#define ACLINT_MTIME_LO(V) ((V & ACLINT_MTIME_LO_MASK) << ACLINT_MTIME_LO_OFFS)
#define ACLINT_MTIME_HI_OFFS 0
#define ACLINT_MTIME_HI_MASK 0xffffffff
#define ACLINT_MTIME_HI(V) ((V & ACLINT_MTIME_HI_MASK) << ACLINT_MTIME_HI_OFFS)
// ACLINT_MSIP0
static inline uint32_t get_aclint_msip0(volatile aclint_t* reg) { return reg->MSIP[0]; }
static inline void set_aclint_msip0(volatile aclint_t* reg, uint32_t value) { reg->MSIP[0] = value; }
static inline uint32_t get_aclint_msip0_msip(volatile aclint_t* reg) { return (reg->MSIP[0] >> 0) & 0x1; }
static inline void set_aclint_msip0_msip(volatile aclint_t* reg, uint8_t value) {
reg->MSIP[0] = (reg->MSIP[0] & ~(0x1U << 0)) | (value << 0);
}
// ACLINT_MSIP
static inline uint32_t get_aclint_msip(volatile aclint_t* reg, unsigned idx) { return reg->MSIP[idx]; }
static inline void set_aclint_msip(volatile aclint_t* reg, unsigned idx, uint32_t value) { reg->MSIP[idx] = value; }
static inline uint32_t get_aclint_msip_msip(volatile aclint_t* reg, unsigned idx) { return (reg->MSIP[idx] >> 0) & 0x1; }
static inline void set_aclint_msip_msip(volatile aclint_t* reg, unsigned idx, uint8_t value) {
reg->MSIP[idx] = (reg->MSIP[idx] & ~(0x1U << 0)) | (value << 0);
}
// ACLINT_MTIMECMP0LO
static inline uint32_t get_aclint_mtimecmp0lo(volatile aclint_t* reg) { return (reg->MTIMECMP[0].LO >> 0) & 0xffffffff; }
static inline void set_aclint_mtimecmp0lo(volatile aclint_t* reg, uint32_t value) {
reg->MTIMECMP[0].LO = (reg->MTIMECMP[0].LO & ~(0xffffffffU << 0)) | (value << 0);
}
// ACLINT_MTIMECMPxLO
static inline uint32_t get_aclint_mtimecmplo(volatile aclint_t* reg, unsigned idx) { return (reg->MTIMECMP[idx].LO >> 0) & 0xffffffff; }
static inline void set_aclint_mtimecmplo(volatile aclint_t* reg, unsigned idx, uint32_t value) {
reg->MTIMECMP[idx].LO = (reg->MTIMECMP[idx].LO & ~(0xffffffffU << 0)) | (value << 0);
}
// ACLINT_MTIMECMP0HI
static inline uint32_t get_aclint_mtimecmp0hi(volatile aclint_t* reg) { return (reg->MTIMECMP[0].HI >> 0) & 0xffffffff; }
static inline void set_aclint_mtimecmp0hi(volatile aclint_t* reg, uint32_t value) {
reg->MTIMECMP[0].HI = (reg->MTIMECMP[0].HI & ~(0xffffffffU << 0)) | (value << 0);
}
// ACLINT_MTIMECMPxHI
static inline uint32_t get_aclint_mtimecmphi(volatile aclint_t* reg, unsigned idx) { return (reg->MTIMECMP[idx].HI >> 0) & 0xffffffff; }
static inline void set_aclint_mtimecmphi(volatile aclint_t* reg, unsigned idx, uint32_t value) {
reg->MTIMECMP[idx].HI = (reg->MTIMECMP[idx].HI & ~(0xffffffffU << 0)) | (value << 0);
}
// ACLINT_MTIME_LO
static inline uint32_t get_aclint_mtime_lo(volatile aclint_t* reg) { return (reg->MTIME_LO >> 0) & 0xffffffff; }
static inline void set_aclint_mtime_lo(volatile aclint_t* reg, uint32_t value) {
reg->MTIME_LO = (reg->MTIME_LO & ~(0xffffffffU << 0)) | (value << 0);
}
// ACLINT_MTIME_HI
static inline uint32_t get_aclint_mtime_hi(volatile aclint_t* reg) { return (reg->MTIME_HI >> 0) & 0xffffffff; }
static inline void set_aclint_mtime_hi(volatile aclint_t* reg, uint32_t value) {
reg->MTIME_HI = (reg->MTIME_HI & ~(0xffffffffU << 0)) | (value << 0);
}
#endif /* _BSP_ACLINT_H */

477
port/moonlight/gen/ethmac.h Normal file
View File

@@ -0,0 +1,477 @@
/*
* Copyright (c) 2023 - 2026 MINRES Technologies GmbH
*
* SPDX-License-Identifier: Apache-2.0
*
* Generated at 2026-01-26 15:33:03 UTC
* by peakrdl_mnrs version 1.3.1
*/
#ifndef _BSP_ETHMAC_H
#define _BSP_ETHMAC_H
#include <stdint.h>
typedef struct {
volatile uint32_t MAC_CTRL;
uint8_t fill0[12];
volatile uint32_t MAC_TX;
volatile uint32_t MAC_TX_AVAILABILITY;
uint8_t fill1[8];
volatile uint32_t MAC_RX;
uint8_t fill2[8];
volatile uint32_t MAC_RX_STATS;
volatile uint32_t MAC_INTR;
uint8_t fill3[12];
volatile uint32_t MDIO_DATA;
volatile uint32_t MDIO_STATUS;
volatile uint32_t MDIO_CONFIG;
volatile uint32_t MDIO_INTR;
uint8_t fill4[16];
volatile uint32_t MDIO_SCLK_CONFIG;
volatile uint32_t MDIO_SSGEN_SETUP;
volatile uint32_t MDIO_SSGEN_HOLD;
volatile uint32_t MDIO_SSGEN_DISABLE;
volatile uint32_t MDIO_SSGEN_ACTIVE_HIGH;
uint8_t fill5[28];
volatile uint32_t MDIO_DIRECT_WRITE;
volatile uint32_t MDIO_DIRECT_READ_WRITE;
volatile uint32_t MDIO_DIRECT_READ;
}ethmac_t;
#define ETHMAC_MAC_CTRL_TX_FLUSH_OFFS 0
#define ETHMAC_MAC_CTRL_TX_FLUSH_MASK 0x1
#define ETHMAC_MAC_CTRL_TX_FLUSH(V) ((V & ETHMAC_MAC_CTRL_TX_FLUSH_MASK) << ETHMAC_MAC_CTRL_TX_FLUSH_OFFS)
#define ETHMAC_MAC_CTRL_TX_READY_OFFS 1
#define ETHMAC_MAC_CTRL_TX_READY_MASK 0x1
#define ETHMAC_MAC_CTRL_TX_READY(V) ((V & ETHMAC_MAC_CTRL_TX_READY_MASK) << ETHMAC_MAC_CTRL_TX_READY_OFFS)
#define ETHMAC_MAC_CTRL_TX_ALIGNER_ENABLE_OFFS 2
#define ETHMAC_MAC_CTRL_TX_ALIGNER_ENABLE_MASK 0x1
#define ETHMAC_MAC_CTRL_TX_ALIGNER_ENABLE(V) ((V & ETHMAC_MAC_CTRL_TX_ALIGNER_ENABLE_MASK) << ETHMAC_MAC_CTRL_TX_ALIGNER_ENABLE_OFFS)
#define ETHMAC_MAC_CTRL_RX_FLUSH_OFFS 4
#define ETHMAC_MAC_CTRL_RX_FLUSH_MASK 0x1
#define ETHMAC_MAC_CTRL_RX_FLUSH(V) ((V & ETHMAC_MAC_CTRL_RX_FLUSH_MASK) << ETHMAC_MAC_CTRL_RX_FLUSH_OFFS)
#define ETHMAC_MAC_CTRL_RX_PENDING_OFFS 5
#define ETHMAC_MAC_CTRL_RX_PENDING_MASK 0x1
#define ETHMAC_MAC_CTRL_RX_PENDING(V) ((V & ETHMAC_MAC_CTRL_RX_PENDING_MASK) << ETHMAC_MAC_CTRL_RX_PENDING_OFFS)
#define ETHMAC_MAC_CTRL_RX_ALIGNER_ENABLE_OFFS 6
#define ETHMAC_MAC_CTRL_RX_ALIGNER_ENABLE_MASK 0x1
#define ETHMAC_MAC_CTRL_RX_ALIGNER_ENABLE(V) ((V & ETHMAC_MAC_CTRL_RX_ALIGNER_ENABLE_MASK) << ETHMAC_MAC_CTRL_RX_ALIGNER_ENABLE_OFFS)
#define ETHMAC_MAC_TX_OFFS 0
#define ETHMAC_MAC_TX_MASK 0xffffffff
#define ETHMAC_MAC_TX(V) ((V & ETHMAC_MAC_TX_MASK) << ETHMAC_MAC_TX_OFFS)
#define ETHMAC_MAC_TX_AVAILABILITY_OFFS 0
#define ETHMAC_MAC_TX_AVAILABILITY_MASK 0x7ff
#define ETHMAC_MAC_TX_AVAILABILITY(V) ((V & ETHMAC_MAC_TX_AVAILABILITY_MASK) << ETHMAC_MAC_TX_AVAILABILITY_OFFS)
#define ETHMAC_MAC_RX_OFFS 0
#define ETHMAC_MAC_RX_MASK 0xffffffff
#define ETHMAC_MAC_RX(V) ((V & ETHMAC_MAC_RX_MASK) << ETHMAC_MAC_RX_OFFS)
#define ETHMAC_MAC_RX_STATS_RX_ERRORS_OFFS 0
#define ETHMAC_MAC_RX_STATS_RX_ERRORS_MASK 0xff
#define ETHMAC_MAC_RX_STATS_RX_ERRORS(V) ((V & ETHMAC_MAC_RX_STATS_RX_ERRORS_MASK) << ETHMAC_MAC_RX_STATS_RX_ERRORS_OFFS)
#define ETHMAC_MAC_RX_STATS_RX_DROPS_OFFS 8
#define ETHMAC_MAC_RX_STATS_RX_DROPS_MASK 0xff
#define ETHMAC_MAC_RX_STATS_RX_DROPS(V) ((V & ETHMAC_MAC_RX_STATS_RX_DROPS_MASK) << ETHMAC_MAC_RX_STATS_RX_DROPS_OFFS)
#define ETHMAC_MAC_INTR_TX_FREE_INTR_ENABLE_OFFS 0
#define ETHMAC_MAC_INTR_TX_FREE_INTR_ENABLE_MASK 0x1
#define ETHMAC_MAC_INTR_TX_FREE_INTR_ENABLE(V) ((V & ETHMAC_MAC_INTR_TX_FREE_INTR_ENABLE_MASK) << ETHMAC_MAC_INTR_TX_FREE_INTR_ENABLE_OFFS)
#define ETHMAC_MAC_INTR_RX_DATA_AVAIL_INTR_ENABLE_OFFS 1
#define ETHMAC_MAC_INTR_RX_DATA_AVAIL_INTR_ENABLE_MASK 0x1
#define ETHMAC_MAC_INTR_RX_DATA_AVAIL_INTR_ENABLE(V) ((V & ETHMAC_MAC_INTR_RX_DATA_AVAIL_INTR_ENABLE_MASK) << ETHMAC_MAC_INTR_RX_DATA_AVAIL_INTR_ENABLE_OFFS)
#define ETHMAC_MDIO_DATA_DATA_OFFS 0
#define ETHMAC_MDIO_DATA_DATA_MASK 0xff
#define ETHMAC_MDIO_DATA_DATA(V) ((V & ETHMAC_MDIO_DATA_DATA_MASK) << ETHMAC_MDIO_DATA_DATA_OFFS)
#define ETHMAC_MDIO_DATA_WRITE_OFFS 8
#define ETHMAC_MDIO_DATA_WRITE_MASK 0x1
#define ETHMAC_MDIO_DATA_WRITE(V) ((V & ETHMAC_MDIO_DATA_WRITE_MASK) << ETHMAC_MDIO_DATA_WRITE_OFFS)
#define ETHMAC_MDIO_DATA_READ_OFFS 9
#define ETHMAC_MDIO_DATA_READ_MASK 0x1
#define ETHMAC_MDIO_DATA_READ(V) ((V & ETHMAC_MDIO_DATA_READ_MASK) << ETHMAC_MDIO_DATA_READ_OFFS)
#define ETHMAC_MDIO_DATA_SSGEN_OFFS 11
#define ETHMAC_MDIO_DATA_SSGEN_MASK 0x1
#define ETHMAC_MDIO_DATA_SSGEN(V) ((V & ETHMAC_MDIO_DATA_SSGEN_MASK) << ETHMAC_MDIO_DATA_SSGEN_OFFS)
#define ETHMAC_MDIO_DATA_RX_DATA_INVALID_OFFS 31
#define ETHMAC_MDIO_DATA_RX_DATA_INVALID_MASK 0x1
#define ETHMAC_MDIO_DATA_RX_DATA_INVALID(V) ((V & ETHMAC_MDIO_DATA_RX_DATA_INVALID_MASK) << ETHMAC_MDIO_DATA_RX_DATA_INVALID_OFFS)
#define ETHMAC_MDIO_STATUS_TX_FREE_OFFS 0
#define ETHMAC_MDIO_STATUS_TX_FREE_MASK 0x3f
#define ETHMAC_MDIO_STATUS_TX_FREE(V) ((V & ETHMAC_MDIO_STATUS_TX_FREE_MASK) << ETHMAC_MDIO_STATUS_TX_FREE_OFFS)
#define ETHMAC_MDIO_STATUS_RX_AVAIL_OFFS 16
#define ETHMAC_MDIO_STATUS_RX_AVAIL_MASK 0x3f
#define ETHMAC_MDIO_STATUS_RX_AVAIL(V) ((V & ETHMAC_MDIO_STATUS_RX_AVAIL_MASK) << ETHMAC_MDIO_STATUS_RX_AVAIL_OFFS)
#define ETHMAC_MDIO_CONFIG_CPOL_OFFS 0
#define ETHMAC_MDIO_CONFIG_CPOL_MASK 0x1
#define ETHMAC_MDIO_CONFIG_CPOL(V) ((V & ETHMAC_MDIO_CONFIG_CPOL_MASK) << ETHMAC_MDIO_CONFIG_CPOL_OFFS)
#define ETHMAC_MDIO_CONFIG_CPHA_OFFS 1
#define ETHMAC_MDIO_CONFIG_CPHA_MASK 0x1
#define ETHMAC_MDIO_CONFIG_CPHA(V) ((V & ETHMAC_MDIO_CONFIG_CPHA_MASK) << ETHMAC_MDIO_CONFIG_CPHA_OFFS)
#define ETHMAC_MDIO_CONFIG_MODE_OFFS 4
#define ETHMAC_MDIO_CONFIG_MODE_MASK 0x1
#define ETHMAC_MDIO_CONFIG_MODE(V) ((V & ETHMAC_MDIO_CONFIG_MODE_MASK) << ETHMAC_MDIO_CONFIG_MODE_OFFS)
#define ETHMAC_MDIO_INTR_TX_IE_OFFS 0
#define ETHMAC_MDIO_INTR_TX_IE_MASK 0x1
#define ETHMAC_MDIO_INTR_TX_IE(V) ((V & ETHMAC_MDIO_INTR_TX_IE_MASK) << ETHMAC_MDIO_INTR_TX_IE_OFFS)
#define ETHMAC_MDIO_INTR_RX_IE_OFFS 1
#define ETHMAC_MDIO_INTR_RX_IE_MASK 0x1
#define ETHMAC_MDIO_INTR_RX_IE(V) ((V & ETHMAC_MDIO_INTR_RX_IE_MASK) << ETHMAC_MDIO_INTR_RX_IE_OFFS)
#define ETHMAC_MDIO_INTR_TX_IP_OFFS 8
#define ETHMAC_MDIO_INTR_TX_IP_MASK 0x1
#define ETHMAC_MDIO_INTR_TX_IP(V) ((V & ETHMAC_MDIO_INTR_TX_IP_MASK) << ETHMAC_MDIO_INTR_TX_IP_OFFS)
#define ETHMAC_MDIO_INTR_RX_IP_OFFS 9
#define ETHMAC_MDIO_INTR_RX_IP_MASK 0x1
#define ETHMAC_MDIO_INTR_RX_IP(V) ((V & ETHMAC_MDIO_INTR_RX_IP_MASK) << ETHMAC_MDIO_INTR_RX_IP_OFFS)
#define ETHMAC_MDIO_INTR_TX_ACTIVE_OFFS 16
#define ETHMAC_MDIO_INTR_TX_ACTIVE_MASK 0x1
#define ETHMAC_MDIO_INTR_TX_ACTIVE(V) ((V & ETHMAC_MDIO_INTR_TX_ACTIVE_MASK) << ETHMAC_MDIO_INTR_TX_ACTIVE_OFFS)
#define ETHMAC_MDIO_SCLK_CONFIG_OFFS 0
#define ETHMAC_MDIO_SCLK_CONFIG_MASK 0xfff
#define ETHMAC_MDIO_SCLK_CONFIG(V) ((V & ETHMAC_MDIO_SCLK_CONFIG_MASK) << ETHMAC_MDIO_SCLK_CONFIG_OFFS)
#define ETHMAC_MDIO_SSGEN_SETUP_OFFS 0
#define ETHMAC_MDIO_SSGEN_SETUP_MASK 0xfff
#define ETHMAC_MDIO_SSGEN_SETUP(V) ((V & ETHMAC_MDIO_SSGEN_SETUP_MASK) << ETHMAC_MDIO_SSGEN_SETUP_OFFS)
#define ETHMAC_MDIO_SSGEN_HOLD_OFFS 0
#define ETHMAC_MDIO_SSGEN_HOLD_MASK 0xfff
#define ETHMAC_MDIO_SSGEN_HOLD(V) ((V & ETHMAC_MDIO_SSGEN_HOLD_MASK) << ETHMAC_MDIO_SSGEN_HOLD_OFFS)
#define ETHMAC_MDIO_SSGEN_DISABLE_OFFS 0
#define ETHMAC_MDIO_SSGEN_DISABLE_MASK 0xfff
#define ETHMAC_MDIO_SSGEN_DISABLE(V) ((V & ETHMAC_MDIO_SSGEN_DISABLE_MASK) << ETHMAC_MDIO_SSGEN_DISABLE_OFFS)
#define ETHMAC_MDIO_SSGEN_ACTIVE_HIGH_OFFS 0
#define ETHMAC_MDIO_SSGEN_ACTIVE_HIGH_MASK 0x1
#define ETHMAC_MDIO_SSGEN_ACTIVE_HIGH(V) ((V & ETHMAC_MDIO_SSGEN_ACTIVE_HIGH_MASK) << ETHMAC_MDIO_SSGEN_ACTIVE_HIGH_OFFS)
#define ETHMAC_MDIO_DIRECT_WRITE_OFFS 0
#define ETHMAC_MDIO_DIRECT_WRITE_MASK 0xff
#define ETHMAC_MDIO_DIRECT_WRITE(V) ((V & ETHMAC_MDIO_DIRECT_WRITE_MASK) << ETHMAC_MDIO_DIRECT_WRITE_OFFS)
#define ETHMAC_MDIO_DIRECT_READ_WRITE_OFFS 0
#define ETHMAC_MDIO_DIRECT_READ_WRITE_MASK 0xff
#define ETHMAC_MDIO_DIRECT_READ_WRITE(V) ((V & ETHMAC_MDIO_DIRECT_READ_WRITE_MASK) << ETHMAC_MDIO_DIRECT_READ_WRITE_OFFS)
#define ETHMAC_MDIO_DIRECT_READ_OFFS 0
#define ETHMAC_MDIO_DIRECT_READ_MASK 0xff
#define ETHMAC_MDIO_DIRECT_READ(V) ((V & ETHMAC_MDIO_DIRECT_READ_MASK) << ETHMAC_MDIO_DIRECT_READ_OFFS)
//ETHMAC_MAC_CTRL
static inline uint32_t get_ethmac_mac_ctrl(volatile ethmac_t* reg){
return reg->MAC_CTRL;
}
static inline void set_ethmac_mac_ctrl(volatile ethmac_t* reg, uint32_t value){
reg->MAC_CTRL = value;
}
static inline uint32_t get_ethmac_mac_ctrl_tx_flush(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 0) & 0x1;
}
static inline void set_ethmac_mac_ctrl_tx_flush(volatile ethmac_t* reg, uint8_t value){
reg->MAC_CTRL = (reg->MAC_CTRL & ~(0x1U << 0)) | (value << 0);
}
static inline uint32_t get_ethmac_mac_ctrl_tx_ready(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 1) & 0x1;
}
static inline uint32_t get_ethmac_mac_ctrl_tx_aligner_enable(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 2) & 0x1;
}
static inline void set_ethmac_mac_ctrl_tx_aligner_enable(volatile ethmac_t* reg, uint8_t value){
reg->MAC_CTRL = (reg->MAC_CTRL & ~(0x1U << 2)) | (value << 2);
}
static inline uint32_t get_ethmac_mac_ctrl_rx_flush(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 4) & 0x1;
}
static inline void set_ethmac_mac_ctrl_rx_flush(volatile ethmac_t* reg, uint8_t value){
reg->MAC_CTRL = (reg->MAC_CTRL & ~(0x1U << 4)) | (value << 4);
}
static inline uint32_t get_ethmac_mac_ctrl_rx_pending(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 5) & 0x1;
}
static inline uint32_t get_ethmac_mac_ctrl_rx_aligner_enable(volatile ethmac_t* reg){
return (reg->MAC_CTRL >> 6) & 0x1;
}
static inline void set_ethmac_mac_ctrl_rx_aligner_enable(volatile ethmac_t* reg, uint8_t value){
reg->MAC_CTRL = (reg->MAC_CTRL & ~(0x1U << 6)) | (value << 6);
}
//ETHMAC_MAC_TX
static inline uint32_t get_ethmac_mac_tx(volatile ethmac_t* reg){
return (reg->MAC_TX >> 0) & 0xffffffff;
}
static inline void set_ethmac_mac_tx(volatile ethmac_t* reg, uint32_t value){
reg->MAC_TX = (reg->MAC_TX & ~(0xffffffffU << 0)) | (value << 0);
}
//ETHMAC_MAC_TX_AVAILABILITY
static inline uint32_t get_ethmac_mac_tx_availability(volatile ethmac_t* reg){
return reg->MAC_TX_AVAILABILITY;
}
static inline uint32_t get_ethmac_mac_tx_availability_words_avail(volatile ethmac_t* reg){
return (reg->MAC_TX_AVAILABILITY >> 0) & 0x7ff;
}
//ETHMAC_MAC_RX
static inline uint32_t get_ethmac_mac_rx(volatile ethmac_t* reg){
return (reg->MAC_RX >> 0) & 0xffffffff;
}
//ETHMAC_MAC_RX_STATS
static inline uint32_t get_ethmac_mac_rx_stats(volatile ethmac_t* reg){
return reg->MAC_RX_STATS;
}
static inline uint32_t get_ethmac_mac_rx_stats_rx_errors(volatile ethmac_t* reg){
return (reg->MAC_RX_STATS >> 0) & 0xff;
}
static inline uint32_t get_ethmac_mac_rx_stats_rx_drops(volatile ethmac_t* reg){
return (reg->MAC_RX_STATS >> 8) & 0xff;
}
//ETHMAC_MAC_INTR
static inline uint32_t get_ethmac_mac_intr(volatile ethmac_t* reg){
return reg->MAC_INTR;
}
static inline void set_ethmac_mac_intr(volatile ethmac_t* reg, uint32_t value){
reg->MAC_INTR = value;
}
static inline uint32_t get_ethmac_mac_intr_tx_free_intr_enable(volatile ethmac_t* reg){
return (reg->MAC_INTR >> 0) & 0x1;
}
static inline void set_ethmac_mac_intr_tx_free_intr_enable(volatile ethmac_t* reg, uint8_t value){
reg->MAC_INTR = (reg->MAC_INTR & ~(0x1U << 0)) | (value << 0);
}
static inline uint32_t get_ethmac_mac_intr_rx_data_avail_intr_enable(volatile ethmac_t* reg){
return (reg->MAC_INTR >> 1) & 0x1;
}
static inline void set_ethmac_mac_intr_rx_data_avail_intr_enable(volatile ethmac_t* reg, uint8_t value){
reg->MAC_INTR = (reg->MAC_INTR & ~(0x1U << 1)) | (value << 1);
}
//ETHMAC_MDIO_DATA
static inline uint32_t get_ethmac_mdio_data(volatile ethmac_t* reg){
return reg->MDIO_DATA;
}
static inline void set_ethmac_mdio_data(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_DATA = value;
}
static inline uint32_t get_ethmac_mdio_data_data(volatile ethmac_t* reg){
return (reg->MDIO_DATA >> 0) & 0xff;
}
static inline void set_ethmac_mdio_data_data(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DATA = (reg->MDIO_DATA & ~(0xffU << 0)) | (value << 0);
}
static inline uint32_t get_ethmac_mdio_data_write(volatile ethmac_t* reg){
return (reg->MDIO_DATA >> 8) & 0x1;
}
static inline void set_ethmac_mdio_data_write(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DATA = (reg->MDIO_DATA & ~(0x1U << 8)) | (value << 8);
}
static inline uint32_t get_ethmac_mdio_data_read(volatile ethmac_t* reg){
return (reg->MDIO_DATA >> 9) & 0x1;
}
static inline void set_ethmac_mdio_data_read(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DATA = (reg->MDIO_DATA & ~(0x1U << 9)) | (value << 9);
}
static inline uint32_t get_ethmac_mdio_data_ssgen(volatile ethmac_t* reg){
return (reg->MDIO_DATA >> 11) & 0x1;
}
static inline void set_ethmac_mdio_data_ssgen(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DATA = (reg->MDIO_DATA & ~(0x1U << 11)) | (value << 11);
}
static inline uint32_t get_ethmac_mdio_data_rx_data_invalid(volatile ethmac_t* reg){
return (reg->MDIO_DATA >> 31) & 0x1;
}
//ETHMAC_MDIO_STATUS
static inline uint32_t get_ethmac_mdio_status(volatile ethmac_t* reg){
return reg->MDIO_STATUS;
}
static inline uint32_t get_ethmac_mdio_status_tx_free(volatile ethmac_t* reg){
return (reg->MDIO_STATUS >> 0) & 0x3f;
}
static inline uint32_t get_ethmac_mdio_status_rx_avail(volatile ethmac_t* reg){
return (reg->MDIO_STATUS >> 16) & 0x3f;
}
//ETHMAC_MDIO_CONFIG
static inline uint32_t get_ethmac_mdio_config(volatile ethmac_t* reg){
return reg->MDIO_CONFIG;
}
static inline void set_ethmac_mdio_config(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_CONFIG = value;
}
static inline uint32_t get_ethmac_mdio_config_cpol(volatile ethmac_t* reg){
return (reg->MDIO_CONFIG >> 0) & 0x1;
}
static inline void set_ethmac_mdio_config_cpol(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_CONFIG = (reg->MDIO_CONFIG & ~(0x1U << 0)) | (value << 0);
}
static inline uint32_t get_ethmac_mdio_config_cpha(volatile ethmac_t* reg){
return (reg->MDIO_CONFIG >> 1) & 0x1;
}
static inline void set_ethmac_mdio_config_cpha(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_CONFIG = (reg->MDIO_CONFIG & ~(0x1U << 1)) | (value << 1);
}
static inline uint32_t get_ethmac_mdio_config_mode(volatile ethmac_t* reg){
return (reg->MDIO_CONFIG >> 4) & 0x1;
}
static inline void set_ethmac_mdio_config_mode(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_CONFIG = (reg->MDIO_CONFIG & ~(0x1U << 4)) | (value << 4);
}
//ETHMAC_MDIO_INTR
static inline uint32_t get_ethmac_mdio_intr(volatile ethmac_t* reg){
return reg->MDIO_INTR;
}
static inline void set_ethmac_mdio_intr(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_INTR = value;
}
static inline uint32_t get_ethmac_mdio_intr_tx_ie(volatile ethmac_t* reg){
return (reg->MDIO_INTR >> 0) & 0x1;
}
static inline void set_ethmac_mdio_intr_tx_ie(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_INTR = (reg->MDIO_INTR & ~(0x1U << 0)) | (value << 0);
}
static inline uint32_t get_ethmac_mdio_intr_rx_ie(volatile ethmac_t* reg){
return (reg->MDIO_INTR >> 1) & 0x1;
}
static inline void set_ethmac_mdio_intr_rx_ie(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_INTR = (reg->MDIO_INTR & ~(0x1U << 1)) | (value << 1);
}
static inline uint32_t get_ethmac_mdio_intr_tx_ip(volatile ethmac_t* reg){
return (reg->MDIO_INTR >> 8) & 0x1;
}
static inline void set_ethmac_mdio_intr_tx_ip(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_INTR = (reg->MDIO_INTR & ~(0x1U << 8)) | (value << 8);
}
static inline uint32_t get_ethmac_mdio_intr_rx_ip(volatile ethmac_t* reg){
return (reg->MDIO_INTR >> 9) & 0x1;
}
static inline void set_ethmac_mdio_intr_rx_ip(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_INTR = (reg->MDIO_INTR & ~(0x1U << 9)) | (value << 9);
}
static inline uint32_t get_ethmac_mdio_intr_tx_active(volatile ethmac_t* reg){
return (reg->MDIO_INTR >> 16) & 0x1;
}
//ETHMAC_MDIO_SCLK_CONFIG
static inline uint32_t get_ethmac_mdio_sclk_config(volatile ethmac_t* reg){
return reg->MDIO_SCLK_CONFIG;
}
static inline void set_ethmac_mdio_sclk_config(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_SCLK_CONFIG = value;
}
static inline uint32_t get_ethmac_mdio_sclk_config_clk_divider(volatile ethmac_t* reg){
return (reg->MDIO_SCLK_CONFIG >> 0) & 0xfff;
}
static inline void set_ethmac_mdio_sclk_config_clk_divider(volatile ethmac_t* reg, uint16_t value){
reg->MDIO_SCLK_CONFIG = (reg->MDIO_SCLK_CONFIG & ~(0xfffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_SSGEN_SETUP
static inline uint32_t get_ethmac_mdio_ssgen_setup(volatile ethmac_t* reg){
return reg->MDIO_SSGEN_SETUP;
}
static inline void set_ethmac_mdio_ssgen_setup(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_SSGEN_SETUP = value;
}
static inline uint32_t get_ethmac_mdio_ssgen_setup_setup_cycles(volatile ethmac_t* reg){
return (reg->MDIO_SSGEN_SETUP >> 0) & 0xfff;
}
static inline void set_ethmac_mdio_ssgen_setup_setup_cycles(volatile ethmac_t* reg, uint16_t value){
reg->MDIO_SSGEN_SETUP = (reg->MDIO_SSGEN_SETUP & ~(0xfffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_SSGEN_HOLD
static inline uint32_t get_ethmac_mdio_ssgen_hold(volatile ethmac_t* reg){
return reg->MDIO_SSGEN_HOLD;
}
static inline void set_ethmac_mdio_ssgen_hold(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_SSGEN_HOLD = value;
}
static inline uint32_t get_ethmac_mdio_ssgen_hold_hold_cycles(volatile ethmac_t* reg){
return (reg->MDIO_SSGEN_HOLD >> 0) & 0xfff;
}
static inline void set_ethmac_mdio_ssgen_hold_hold_cycles(volatile ethmac_t* reg, uint16_t value){
reg->MDIO_SSGEN_HOLD = (reg->MDIO_SSGEN_HOLD & ~(0xfffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_SSGEN_DISABLE
static inline uint32_t get_ethmac_mdio_ssgen_disable(volatile ethmac_t* reg){
return reg->MDIO_SSGEN_DISABLE;
}
static inline void set_ethmac_mdio_ssgen_disable(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_SSGEN_DISABLE = value;
}
static inline uint32_t get_ethmac_mdio_ssgen_disable_disable_cycles(volatile ethmac_t* reg){
return (reg->MDIO_SSGEN_DISABLE >> 0) & 0xfff;
}
static inline void set_ethmac_mdio_ssgen_disable_disable_cycles(volatile ethmac_t* reg, uint16_t value){
reg->MDIO_SSGEN_DISABLE = (reg->MDIO_SSGEN_DISABLE & ~(0xfffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_SSGEN_ACTIVE_HIGH
static inline uint32_t get_ethmac_mdio_ssgen_active_high(volatile ethmac_t* reg){
return reg->MDIO_SSGEN_ACTIVE_HIGH;
}
static inline void set_ethmac_mdio_ssgen_active_high(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_SSGEN_ACTIVE_HIGH = value;
}
static inline uint32_t get_ethmac_mdio_ssgen_active_high_spi_cs_active_high(volatile ethmac_t* reg){
return (reg->MDIO_SSGEN_ACTIVE_HIGH >> 0) & 0x1;
}
static inline void set_ethmac_mdio_ssgen_active_high_spi_cs_active_high(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_SSGEN_ACTIVE_HIGH = (reg->MDIO_SSGEN_ACTIVE_HIGH & ~(0x1U << 0)) | (value << 0);
}
//ETHMAC_MDIO_DIRECT_WRITE
static inline void set_ethmac_mdio_direct_write(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_DIRECT_WRITE = value;
}
static inline void set_ethmac_mdio_direct_write_data(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DIRECT_WRITE = (reg->MDIO_DIRECT_WRITE & ~(0xffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_DIRECT_READ_WRITE
static inline void set_ethmac_mdio_direct_read_write(volatile ethmac_t* reg, uint32_t value){
reg->MDIO_DIRECT_READ_WRITE = value;
}
static inline void set_ethmac_mdio_direct_read_write_data(volatile ethmac_t* reg, uint8_t value){
reg->MDIO_DIRECT_READ_WRITE = (reg->MDIO_DIRECT_READ_WRITE & ~(0xffU << 0)) | (value << 0);
}
//ETHMAC_MDIO_DIRECT_READ
static inline uint32_t get_ethmac_mdio_direct_read(volatile ethmac_t* reg){
return reg->MDIO_DIRECT_READ;
}
static inline uint32_t get_ethmac_mdio_direct_read_data(volatile ethmac_t* reg){
return (reg->MDIO_DIRECT_READ >> 0) & 0xff;
}
#endif /* _BSP_ETHMAC_H */

176
port/moonlight/gen/uart.h Normal file
View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2023 - 2024 MINRES Technologies GmbH
*
* SPDX-License-Identifier: Apache-2.0
*
* Generated at 2024-08-02 08:46:07 UTC
* by peakrdl_mnrs version 1.2.7
*/
#ifndef _BSP_UART_H
#define _BSP_UART_H
#include <stdint.h>
typedef struct {
volatile uint32_t RX_TX_REG;
volatile uint32_t INT_CTRL_REG;
volatile uint32_t CLK_DIVIDER_REG;
volatile uint32_t FRAME_CONFIG_REG;
volatile uint32_t STATUS_REG;
} uart_t;
#define UART_RX_TX_REG_DATA_OFFS 0
#define UART_RX_TX_REG_DATA_MASK 0xff
#define UART_RX_TX_REG_DATA(V) ((V & UART_RX_TX_REG_DATA_MASK) << UART_RX_TX_REG_DATA_OFFS)
#define UART_RX_TX_REG_RX_AVAIL_OFFS 14
#define UART_RX_TX_REG_RX_AVAIL_MASK 0x1
#define UART_RX_TX_REG_RX_AVAIL(V) ((V & UART_RX_TX_REG_RX_AVAIL_MASK) << UART_RX_TX_REG_RX_AVAIL_OFFS)
#define UART_RX_TX_REG_TX_FREE_OFFS 15
#define UART_RX_TX_REG_TX_FREE_MASK 0x1
#define UART_RX_TX_REG_TX_FREE(V) ((V & UART_RX_TX_REG_TX_FREE_MASK) << UART_RX_TX_REG_TX_FREE_OFFS)
#define UART_RX_TX_REG_TX_EMPTY_OFFS 16
#define UART_RX_TX_REG_TX_EMPTY_MASK 0x1
#define UART_RX_TX_REG_TX_EMPTY(V) ((V & UART_RX_TX_REG_TX_EMPTY_MASK) << UART_RX_TX_REG_TX_EMPTY_OFFS)
#define UART_INT_CTRL_REG_WRITE_INTR_ENABLE_OFFS 0
#define UART_INT_CTRL_REG_WRITE_INTR_ENABLE_MASK 0x1
#define UART_INT_CTRL_REG_WRITE_INTR_ENABLE(V) ((V & UART_INT_CTRL_REG_WRITE_INTR_ENABLE_MASK) << UART_INT_CTRL_REG_WRITE_INTR_ENABLE_OFFS)
#define UART_INT_CTRL_REG_READ_INTR_ENABLE_OFFS 1
#define UART_INT_CTRL_REG_READ_INTR_ENABLE_MASK 0x1
#define UART_INT_CTRL_REG_READ_INTR_ENABLE(V) ((V & UART_INT_CTRL_REG_READ_INTR_ENABLE_MASK) << UART_INT_CTRL_REG_READ_INTR_ENABLE_OFFS)
#define UART_INT_CTRL_REG_BREAK_INTR_ENABLE_OFFS 2
#define UART_INT_CTRL_REG_BREAK_INTR_ENABLE_MASK 0x1
#define UART_INT_CTRL_REG_BREAK_INTR_ENABLE(V) ((V & UART_INT_CTRL_REG_BREAK_INTR_ENABLE_MASK) << UART_INT_CTRL_REG_BREAK_INTR_ENABLE_OFFS)
#define UART_INT_CTRL_REG_WRITE_INTR_PEND_OFFS 8
#define UART_INT_CTRL_REG_WRITE_INTR_PEND_MASK 0x1
#define UART_INT_CTRL_REG_WRITE_INTR_PEND(V) ((V & UART_INT_CTRL_REG_WRITE_INTR_PEND_MASK) << UART_INT_CTRL_REG_WRITE_INTR_PEND_OFFS)
#define UART_INT_CTRL_REG_READ_INTR_PEND_OFFS 9
#define UART_INT_CTRL_REG_READ_INTR_PEND_MASK 0x1
#define UART_INT_CTRL_REG_READ_INTR_PEND(V) ((V & UART_INT_CTRL_REG_READ_INTR_PEND_MASK) << UART_INT_CTRL_REG_READ_INTR_PEND_OFFS)
#define UART_INT_CTRL_REG_BREAK_INTR_PEND_OFFS 10
#define UART_INT_CTRL_REG_BREAK_INTR_PEND_MASK 0x1
#define UART_INT_CTRL_REG_BREAK_INTR_PEND(V) ((V & UART_INT_CTRL_REG_BREAK_INTR_PEND_MASK) << UART_INT_CTRL_REG_BREAK_INTR_PEND_OFFS)
#define UART_CLK_DIVIDER_REG_OFFS 0
#define UART_CLK_DIVIDER_REG_MASK 0xfffff
#define UART_CLK_DIVIDER_REG(V) ((V & UART_CLK_DIVIDER_REG_MASK) << UART_CLK_DIVIDER_REG_OFFS)
#define UART_FRAME_CONFIG_REG_DATA_LENGTH_OFFS 0
#define UART_FRAME_CONFIG_REG_DATA_LENGTH_MASK 0x7
#define UART_FRAME_CONFIG_REG_DATA_LENGTH(V) ((V & UART_FRAME_CONFIG_REG_DATA_LENGTH_MASK) << UART_FRAME_CONFIG_REG_DATA_LENGTH_OFFS)
#define UART_FRAME_CONFIG_REG_PARITY_OFFS 3
#define UART_FRAME_CONFIG_REG_PARITY_MASK 0x3
#define UART_FRAME_CONFIG_REG_PARITY(V) ((V & UART_FRAME_CONFIG_REG_PARITY_MASK) << UART_FRAME_CONFIG_REG_PARITY_OFFS)
#define UART_FRAME_CONFIG_REG_STOP_BIT_OFFS 5
#define UART_FRAME_CONFIG_REG_STOP_BIT_MASK 0x1
#define UART_FRAME_CONFIG_REG_STOP_BIT(V) ((V & UART_FRAME_CONFIG_REG_STOP_BIT_MASK) << UART_FRAME_CONFIG_REG_STOP_BIT_OFFS)
#define UART_STATUS_REG_READ_ERROR_OFFS 0
#define UART_STATUS_REG_READ_ERROR_MASK 0x1
#define UART_STATUS_REG_READ_ERROR(V) ((V & UART_STATUS_REG_READ_ERROR_MASK) << UART_STATUS_REG_READ_ERROR_OFFS)
#define UART_STATUS_REG_STALL_OFFS 1
#define UART_STATUS_REG_STALL_MASK 0x1
#define UART_STATUS_REG_STALL(V) ((V & UART_STATUS_REG_STALL_MASK) << UART_STATUS_REG_STALL_OFFS)
#define UART_STATUS_REG_BREAK_LINE_OFFS 8
#define UART_STATUS_REG_BREAK_LINE_MASK 0x1
#define UART_STATUS_REG_BREAK_LINE(V) ((V & UART_STATUS_REG_BREAK_LINE_MASK) << UART_STATUS_REG_BREAK_LINE_OFFS)
#define UART_STATUS_REG_BREAK_DETECTED_OFFS 9
#define UART_STATUS_REG_BREAK_DETECTED_MASK 0x1
#define UART_STATUS_REG_BREAK_DETECTED(V) ((V & UART_STATUS_REG_BREAK_DETECTED_MASK) << UART_STATUS_REG_BREAK_DETECTED_OFFS)
#define UART_STATUS_REG_SET_BREAK_OFFS 10
#define UART_STATUS_REG_SET_BREAK_MASK 0x1
#define UART_STATUS_REG_SET_BREAK(V) ((V & UART_STATUS_REG_SET_BREAK_MASK) << UART_STATUS_REG_SET_BREAK_OFFS)
#define UART_STATUS_REG_CLEAR_BREAK_OFFS 11
#define UART_STATUS_REG_CLEAR_BREAK_MASK 0x1
#define UART_STATUS_REG_CLEAR_BREAK(V) ((V & UART_STATUS_REG_CLEAR_BREAK_MASK) << UART_STATUS_REG_CLEAR_BREAK_OFFS)
// UART_RX_TX_REG
static inline uint32_t get_uart_rx_tx_reg(volatile uart_t* reg) { return reg->RX_TX_REG; }
static inline void set_uart_rx_tx_reg(volatile uart_t* reg, uint32_t value) { reg->RX_TX_REG = value; }
static inline uint32_t get_uart_rx_tx_reg_data(volatile uart_t* reg) { return (reg->RX_TX_REG >> 0) & 0xff; }
static inline void set_uart_rx_tx_reg_data(volatile uart_t* reg, uint8_t value) {
reg->RX_TX_REG = (reg->RX_TX_REG & ~(0xffU << 0)) | (value << 0);
}
static inline uint32_t get_uart_rx_tx_reg_rx_avail(volatile uart_t* reg) { return (reg->RX_TX_REG >> 14) & 0x1; }
static inline uint32_t get_uart_rx_tx_reg_tx_free(volatile uart_t* reg) { return (reg->RX_TX_REG >> 15) & 0x1; }
static inline uint32_t get_uart_rx_tx_reg_tx_empty(volatile uart_t* reg) { return (reg->RX_TX_REG >> 16) & 0x1; }
// UART_INT_CTRL_REG
static inline uint32_t get_uart_int_ctrl_reg(volatile uart_t* reg) { return reg->INT_CTRL_REG; }
static inline void set_uart_int_ctrl_reg(volatile uart_t* reg, uint32_t value) { reg->INT_CTRL_REG = value; }
static inline uint32_t get_uart_int_ctrl_reg_write_intr_enable(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 0) & 0x1; }
static inline void set_uart_int_ctrl_reg_write_intr_enable(volatile uart_t* reg, uint8_t value) {
reg->INT_CTRL_REG = (reg->INT_CTRL_REG & ~(0x1U << 0)) | (value << 0);
}
static inline uint32_t get_uart_int_ctrl_reg_read_intr_enable(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 1) & 0x1; }
static inline void set_uart_int_ctrl_reg_read_intr_enable(volatile uart_t* reg, uint8_t value) {
reg->INT_CTRL_REG = (reg->INT_CTRL_REG & ~(0x1U << 1)) | (value << 1);
}
static inline uint32_t get_uart_int_ctrl_reg_break_intr_enable(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 2) & 0x1; }
static inline void set_uart_int_ctrl_reg_break_intr_enable(volatile uart_t* reg, uint8_t value) {
reg->INT_CTRL_REG = (reg->INT_CTRL_REG & ~(0x1U << 2)) | (value << 2);
}
static inline uint32_t get_uart_int_ctrl_reg_write_intr_pend(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 8) & 0x1; }
static inline uint32_t get_uart_int_ctrl_reg_read_intr_pend(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 9) & 0x1; }
static inline uint32_t get_uart_int_ctrl_reg_break_intr_pend(volatile uart_t* reg) { return (reg->INT_CTRL_REG >> 10) & 0x1; }
// UART_CLK_DIVIDER_REG
static inline uint32_t get_uart_clk_divider_reg(volatile uart_t* reg) { return reg->CLK_DIVIDER_REG; }
static inline void set_uart_clk_divider_reg(volatile uart_t* reg, uint32_t value) { reg->CLK_DIVIDER_REG = value; }
static inline uint32_t get_uart_clk_divider_reg_clock_divider(volatile uart_t* reg) { return (reg->CLK_DIVIDER_REG >> 0) & 0xfffff; }
static inline void set_uart_clk_divider_reg_clock_divider(volatile uart_t* reg, uint32_t value) {
reg->CLK_DIVIDER_REG = (reg->CLK_DIVIDER_REG & ~(0xfffffU << 0)) | (value << 0);
}
// UART_FRAME_CONFIG_REG
static inline uint32_t get_uart_frame_config_reg(volatile uart_t* reg) { return reg->FRAME_CONFIG_REG; }
static inline void set_uart_frame_config_reg(volatile uart_t* reg, uint32_t value) { reg->FRAME_CONFIG_REG = value; }
static inline uint32_t get_uart_frame_config_reg_data_length(volatile uart_t* reg) { return (reg->FRAME_CONFIG_REG >> 0) & 0x7; }
static inline void set_uart_frame_config_reg_data_length(volatile uart_t* reg, uint8_t value) {
reg->FRAME_CONFIG_REG = (reg->FRAME_CONFIG_REG & ~(0x7U << 0)) | (value << 0);
}
static inline uint32_t get_uart_frame_config_reg_parity(volatile uart_t* reg) { return (reg->FRAME_CONFIG_REG >> 3) & 0x3; }
static inline void set_uart_frame_config_reg_parity(volatile uart_t* reg, uint8_t value) {
reg->FRAME_CONFIG_REG = (reg->FRAME_CONFIG_REG & ~(0x3U << 3)) | (value << 3);
}
static inline uint32_t get_uart_frame_config_reg_stop_bit(volatile uart_t* reg) { return (reg->FRAME_CONFIG_REG >> 5) & 0x1; }
static inline void set_uart_frame_config_reg_stop_bit(volatile uart_t* reg, uint8_t value) {
reg->FRAME_CONFIG_REG = (reg->FRAME_CONFIG_REG & ~(0x1U << 5)) | (value << 5);
}
// UART_STATUS_REG
static inline uint32_t get_uart_status_reg(volatile uart_t* reg) { return reg->STATUS_REG; }
static inline void set_uart_status_reg(volatile uart_t* reg, uint32_t value) { reg->STATUS_REG = value; }
static inline uint32_t get_uart_status_reg_read_error(volatile uart_t* reg) { return (reg->STATUS_REG >> 0) & 0x1; }
static inline uint32_t get_uart_status_reg_stall(volatile uart_t* reg) { return (reg->STATUS_REG >> 1) & 0x1; }
static inline uint32_t get_uart_status_reg_break_line(volatile uart_t* reg) { return (reg->STATUS_REG >> 8) & 0x1; }
static inline uint32_t get_uart_status_reg_break_detected(volatile uart_t* reg) { return (reg->STATUS_REG >> 9) & 0x1; }
static inline void set_uart_status_reg_break_detected(volatile uart_t* reg, uint8_t value) {
reg->STATUS_REG = (reg->STATUS_REG & ~(0x1U << 9)) | (value << 9);
}
static inline uint32_t get_uart_status_reg_set_break(volatile uart_t* reg) { return (reg->STATUS_REG >> 10) & 0x1; }
static inline void set_uart_status_reg_set_break(volatile uart_t* reg, uint8_t value) {
reg->STATUS_REG = (reg->STATUS_REG & ~(0x1U << 10)) | (value << 10);
}
static inline uint32_t get_uart_status_reg_clear_break(volatile uart_t* reg) { return (reg->STATUS_REG >> 11) & 0x1; }
static inline void set_uart_status_reg_clear_break(volatile uart_t* reg, uint8_t value) {
reg->STATUS_REG = (reg->STATUS_REG & ~(0x1U << 11)) | (value << 11);
}
#endif /* _BSP_UART_H */

32
port/moonlight/hwtimer.h Normal file
View File

@@ -0,0 +1,32 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 "platform.h"
#define TICKNUM_PER_SECOND 32768
#define TICKNUM_PER_TIMER (TICKNUM_PER_SECOND / 1000)
static inline int hwtimer_init(void) {
uint64_t time = get_aclint_mtime(aclint);
set_aclint_mtimecmp(aclint, time + TICKNUM_PER_TIMER);
return 0;
}
static inline int hwtimer_handler(void) {
uint64_t time = get_aclint_mtime(aclint);
set_aclint_mtimecmp(aclint, time + TICKNUM_PER_TIMER);
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

24
port/moonlight/platform.h Normal file
View File

@@ -0,0 +1,24 @@
#include "uart.h"
#include "gen/ethmac.h"
#include "aclint.h"
#include "riscv-csr.h"
#include "riscv-traps.h"
#define PERIPH(TYPE, ADDR) ((volatile TYPE*)(ADDR))
#define APB_BASE 0x10000000
#define uart PERIPH(uart_t, APB_BASE + 0x01000)
#define aclint PERIPH(aclint_t, APB_BASE + 0x30000)
#define ethmac0 PERIPH(ethmac_t, 0x18000000)
#define ethmac1 PERIPH(ethmac_t, 0x18001000)
#define UART0_IRQ 16
#define TIMER0_IRQ0 17
#define TIMER0_IRQ1 18
#define QSPI_IRQ 19
#define I2S_IRQ 20
#define CAM_IRQ 21
#define DMA_IRQ 22
#define GPIO_ORQ 23
#define ETH0_IRQ 24
#define ETH1_IRQ 25

3791
port/moonlight/riscv-csr.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/*
RISC-V machine interrupts.
SPDX-License-Identifier: Unlicense
https://five-embeddev.com/
*/
#ifndef RISCV_TRAPS_H
#define RISCV_TRAPS_H
enum {
RISCV_INT_MSI = 3,
RISCV_INT_MTI = 7,
RISCV_INT_MEI = 11,
RISCV_INT_SSI = 1,
RISCV_INT_STI = 5,
RISCV_INT_SEI = 9,
RISCV_INT_USI = 0,
RISCV_INT_UTI = 4,
RISCV_INT_UEI = 8,
};
enum {
RISCV_INT_POS_MSI = 3,
RISCV_INT_POS_MTI = 7,
RISCV_INT_POS_MEI = 11,
RISCV_INT_POS_SSI = 1,
RISCV_INT_POS_STI = 5,
RISCV_INT_POS_SEI = 9,
RISCV_INT_POS_USI = 0,
RISCV_INT_POS_UTI = 4,
RISCV_INT_POS_UEI = 8,
};
enum {
RISCV_INT_MASK_MSI = (1UL<<RISCV_INT_POS_MSI),
RISCV_INT_MASK_MTI = (1UL<<RISCV_INT_POS_MTI),
RISCV_INT_MASK_MEI = (1UL<<RISCV_INT_POS_MEI),
RISCV_INT_MASK_SSI = (1UL<<RISCV_INT_POS_SSI),
RISCV_INT_MASK_STI = (1UL<<RISCV_INT_POS_STI),
RISCV_INT_MASK_SEI = (1UL<<RISCV_INT_POS_SEI),
RISCV_INT_MASK_USI = (1UL<<RISCV_INT_POS_USI),
RISCV_INT_MASK_UTI = (1UL<<RISCV_INT_POS_UTI),
RISCV_INT_MASK_UEI = (1UL<<RISCV_INT_POS_UEI),
};
enum {
RISCV_EXCP_INSTRUCTION_ADDRESS_MISALIGNED=0, /* Instruction address misaligned */
RISCV_EXCP_INSTRUCTION_ACCESS_FAULT=1, /* Instruction access fault */
RISCV_EXCP_ILLEGAL_INSTRUCTION=2, /* Illegal instruction */
RISCV_EXCP_BREAKPOINT=3, /* Breakpoint */
RISCV_EXCP_LOAD_ADDRESS_MISALIGNED=4, /* Load address misaligned */
RISCV_EXCP_LOAD_ACCESS_FAULT=5, /* Load access fault */
RISCV_EXCP_STORE_AMO_ADDRESS_MISALIGNED =6, /* Store/AMO address misaligned */
RISCV_EXCP_STORE_AMO_ACCESS_FAULT=7, /* Store/AMO access fault */
RISCV_EXCP_ENVIRONMENT_CALL_FROM_U_MODE=8, /* Environment call from U-mode */
RISCV_EXCP_ENVIRONMENT_CALL_FROM_S_MODE=9, /* Environment call from S-mode */
RISCV_EXCP_RESERVED10=10, /* Reserved */
RISCV_EXCP_ENVIRONMENT_CALL_FROM_M_MODE=11, /* Environment call from M-mode */
RISCV_EXCP_INSTRUCTION_PAGE_FAULT=12, /* Instruction page fault */
RISCV_EXCP_LOAD_PAGE_FAULT=13, /* Load page fault */
RISCV_EXCP_RESERVED14=14, /* Reserved */
RISCV_EXCP_STORE_AMO_PAGE_FAULT=15, /* Store/AMO page fault */
};
#endif /* RISCV_TRAPS_H */

View File

@@ -0,0 +1,57 @@
#include "hwtimer.h"
#include <stdint.h>
#include <tx_api.h>
#include <tx_port.h>
#include <stdio.h>
#include "riscv-traps.h"
#if __riscv_xlen == 64
#define INTERRUPT_BIT 0x8000000000000000ull
#else
#define INTERRUPT_BIT 0x80000000ull
#endif
#define OS_IS_INTERRUPT(mcause) (mcause & INTERRUPT_BIT)
#define OS_IS_TICK_INT(mcause) (mcause == (0x7 | INTERRUPT_BIT))
#define OS_IS_SOFT_INT(mcause) (mcause == (0x3 | INTERRUPT_BIT))
#define OS_IS_EXT_INT(mcause) (mcause == (0xb | INTERRUPT_BIT))
extern void _tx_timer_interrupt(void);
extern uintptr_t exception(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval);
void (*irq_handler[__riscv_xlen])();
int register_irq_handler(unsigned irq_num, void (*handler)()) {
if(irq_num<__riscv_xlen){
irq_handler[irq_num] = handler;
return 1;
}
return 0;
}
void trap_handler(uintptr_t mcause, uintptr_t mepc, uintptr_t mtval) {
if(OS_IS_INTERRUPT(mcause)) {
unsigned irq_id = mcause&(__riscv_xlen-1);
switch(irq_id){
case RISCV_INT_MTI:
hwtimer_handler();
_tx_timer_interrupt();
break;
case RISCV_INT_MEI:
puts("[INTERRUPT]: handler ext irq error!\n");
while(1)
;
break;
default:
if(irq_handler[irq_id])
irq_handler[irq_id]();
else {
printf("[INTERRUPT]: Unkown Interrupt %d!!\n", mcause&0xff);
puts("[INTERRUPT]: now can't deal with the interrupt!\n");
while(1)
;
}
}
} else {
exception( mcause, mepc, mtval);
}
}

View File

@@ -0,0 +1,78 @@
/*
Baremetal main program with timer interrupt.
SPDX-License-Identifier: Unlicense
https://five-embeddev.com/
Tested with sifive-hifive-revb, but should not have any
dependencies to any particular implementation.
*/
// RISC-V CSR definitions and access classes
#include "riscv-csr.h"
#include "riscv-interrupt.h"
#include "hwtimer.h"
#include "vector_table.h"
extern void _tx_timer_interrupt(void);
// Machine mode interrupt service routine
// Global to hold current timestamp, written in MTI handler.
static volatile uint64_t timestamp = 0;
#define RISCV_MTVEC_MODE_VECTORED 1
int init_irq(void) {
// Global interrupt disable
csr_clr_bits_mstatus(MSTATUS_MIE_BIT_MASK);
csr_write_mie(0);
// Setup the IRQ handler entry point, set the mode to vectored
csr_write_mtvec((uint_xlen_t) riscv_mtvec_table | RISCV_MTVEC_MODE_VECTORED);
// Enable MIE.MTI
csr_set_bits_mie(MIE_MTI_BIT_MASK);
// Global interrupt enable
csr_set_bits_mstatus(MSTATUS_MIE_BIT_MASK);
// Setup timer for 1 second interval
hwtimer_init();
// Busy loop
do {
// Wait for timer interrupt
__asm__ volatile ("wfi");
// Try a synchronous exception.
__asm__ volatile ("ecall");
} while (1);
// Will not reach here
return 0;
}
#pragma GCC push_options
// Force the alignment for mtvec.BASE. A 'C' extension program could be aligned to to bytes.
#pragma GCC optimize ("align-functions=4")
// The 'riscv_mtvec_mti' function is added to the vector table by the vector_table.c
void riscv_mtvec_mti(void) {
hwtimer_handler();
_tx_timer_interrupt();
}
// The 'riscv_mtvec_exception' function is added to the vector table by the vector_table.c
// This function looks at the cause of the exception, if it is an 'ecall' instruction then increment a global counter.
void riscv_mtvec_exception(void) {
uint_xlen_t this_cause = csr_read_mcause();
uint_xlen_t this_pc = csr_read_mepc();
//uint_xlen_t this_value = csr_read_mtval();
switch (this_cause) {
case RISCV_EXCP_ENVIRONMENT_CALL_FROM_M_MODE:
ecall_count++;
// Make sure the return address is the instruction AFTER ecall
csr_write_mepc(this_pc+4);
break;
}
}
#pragma GCC pop_options

View File

@@ -0,0 +1,134 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_interrupt RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes the hardware timer interrupt. This */
/* processing includes incrementing the system clock and checking for */
/* time slice and/or timer expiration. If either is found, the */
/* interrupt context save/restore functions are called along with the */
/* expiration functions. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_timer_expiration_process Timer expiration processing */
/* _tx_thread_time_slice Time slice interrupted thread */
/* */
/* CALLED BY */
/* */
/* interrupt vector */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
VOID _tx_timer_interrupt(VOID)
{
/* Increment system clock. */
_tx_timer_system_clock++;
/* Test for time-slice expiration. */
if (_tx_timer_time_slice)
{
/* Decrement the time_slice. */
_tx_timer_time_slice--;
/* Check for expiration. */
if (_tx_timer_time_slice == 0)
{
/* Set the time-slice expired flag. */
_tx_timer_expired_time_slice = TX_TRUE;
}
}
/* Test for timer expiration. */
if (*_tx_timer_current_ptr)
{
/* Set expiration flag. */
_tx_timer_expired = TX_TRUE;
}
else
{
/* No timer expired, increment the timer pointer. */
_tx_timer_current_ptr++;
/* Check for wrap-around. */
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
/* Wrap to beginning of list. */
_tx_timer_current_ptr = _tx_timer_list_start;
}
}
/* See if anything has expired. */
if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
{
/* Did a timer expire? */
if (_tx_timer_expired)
{
/* Process timer expiration. */
_tx_timer_expiration_process();
}
/* Did time slice expire? */
if (_tx_timer_expired_time_slice)
{
/* Time slice interrupted thread. */
_tx_thread_time_slice();
}
}
}

25
port/moonlight/uart.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _DEVICES_UART_H
#define _DEVICES_UART_H
#include "gen/uart.h"
#include <stdint.h>
static inline uint32_t uart_get_tx_free(volatile uart_t* reg) { return get_uart_rx_tx_reg_tx_free(reg); }
static inline uint32_t uart_get_tx_empty(volatile uart_t* reg) { return get_uart_rx_tx_reg_tx_empty(reg); }
static inline uint32_t uart_get_rx_avail(volatile uart_t* reg) { return get_uart_rx_tx_reg_rx_avail(reg); }
static inline void uart_write(volatile uart_t* reg, uint8_t data) {
while(get_uart_rx_tx_reg_tx_free(reg) == 0)
;
set_uart_rx_tx_reg_data(reg, data);
}
static inline uint8_t uart_read(volatile uart_t* reg) {
uint32_t res = get_uart_rx_tx_reg_data(reg);
while((res & 0x10000) == 0)
res = get_uart_rx_tx_reg_data(reg);
return res;
}
#endif /* _DEVICES_UART_H */

View File

@@ -0,0 +1,166 @@
/*
Baremetal main program with timer interrupt.
SPDX-License-Identifier: Unlicense
https://five-embeddev.com/
Tested with sifive-hifive-revb, but should not have any
dependencies to any particular implementation.
*/
// Makes use of GCC interrupt and weak reference/alias attributes
// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
// https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html#RISC-V-Function-Attributes
// Vector table - not to be called.
void riscv_mtvec_table(void) __attribute__ ((naked, section(".text.mtvec_table") ,aligned(256)));
void riscv_stvec_table(void) __attribute__ ((naked, section(".text.stvec_table") ,aligned(256)));
void riscv_utvec_table(void) __attribute__ ((naked, section(".text.utvec_table") ,aligned(256)));
// Default "NOP" implementations
static void riscv_nop_machine(void) __attribute__ ((interrupt ("machine")) );
static void riscv_nop_supervisor(void) __attribute__ ((interrupt ("supervisor")) );
static void riscv_nop_user(void) __attribute__ ((interrupt ("user")) );
// Weak alias to the "NOP" implementations. If another function
void riscv_mtvec_exception(void) __attribute__ ((interrupt ("machine") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_msi(void) __attribute__ ((interrupt ("machine") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_mti(void) __attribute__ ((interrupt ("machine") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_mei(void) __attribute__ ((interrupt ("machine") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_ssi(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_sti(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_machine") ));
void riscv_mtvec_sei(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_machine") ));
void riscv_stvec_exception(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_supervisor") ));
void riscv_stvec_ssi(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_supervisor") ));
void riscv_stvec_sti(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_supervisor") ));
void riscv_stvec_sei(void) __attribute__ ((interrupt ("supervisor") , weak, alias("riscv_nop_supervisor") ));
void riscv_utvec_usi(void) __attribute__ ((interrupt ("user") , weak, alias("riscv_nop_user") ));
void riscv_utvec_uti(void) __attribute__ ((interrupt ("user") , weak, alias("riscv_nop_user") ));
void riscv_utvec_uei(void) __attribute__ ((interrupt ("user") , weak, alias("riscv_nop_user") ));
#ifndef VECTOR_TABLE_MTVEC_PLATFORM_INTS
void moonlight_mtvec_irq0(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq1(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq2(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq3(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq4(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq5(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq6(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq7(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq8(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq9(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq10(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq11(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq12(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq13(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq14(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
void moonlight_mtvec_irq15(void) __attribute__ ((interrupt ("machine"), weak, alias("riscv_nop_machine") ));
#endif // #ifndef VECTOR_TABLE_MTVEC_PLATFORM_INTS
#pragma GCC push_options
// Ensure the vector table is aligned.
// The bottom 4 bits of MTVEC are ignored - so align to 16 bytes
// Vector table. Do not call!
// Possible entries defined by mcause table
// http://five-embeddev.com/riscv-isa-manual/latest/machine.html#sec:mcause
//
// When vectored interrupts are enabled, interrupt cause 0, which
// corresponds to user-mode software interrupts, are vectored to the
// same location as synchronous exceptions. This ambiguity does not
// arise in practice, since user-mode software interrupts are either
// disabled or delegated to user mode.
void riscv_mtvec_table(void) {
__asm__ volatile (
".org riscv_mtvec_table + 0*4;"
"jal zero,riscv_mtvec_exception;" /* 0 */
".org riscv_mtvec_table + 1*4;"
"jal zero,riscv_mtvec_ssi;" /* 1 */
".org riscv_mtvec_table + 3*4;"
"jal zero,riscv_mtvec_msi;" /* 3 */
".org riscv_mtvec_table + 5*4;"
"jal zero,riscv_mtvec_sti;" /* 5 */
".org riscv_mtvec_table + 7*4;"
"jal zero,riscv_mtvec_mti;" /* 7 */
".org riscv_mtvec_table + 9*4;"
"jal zero,riscv_mtvec_sei;" /* 9 */
".org riscv_mtvec_table + 11*4;"
"jal zero,riscv_mtvec_mei;" /* 11 */
#ifndef VECTOR_TABLE_MTVEC_PLATFORM_INTS
".org riscv_mtvec_table + 16*4;"
"jal moonlight_mtvec_irq0;"
"jal moonlight_mtvec_irq1;"
"jal moonlight_mtvec_irq2;"
"jal moonlight_mtvec_irq3;"
"jal moonlight_mtvec_irq4;"
"jal moonlight_mtvec_irq5;"
"jal moonlight_mtvec_irq6;"
"jal moonlight_mtvec_irq7;"
"jal moonlight_mtvec_irq8;"
"jal moonlight_mtvec_irq9;"
"jal moonlight_mtvec_irq10;"
"jal moonlight_mtvec_irq11;"
"jal moonlight_mtvec_irq12;"
"jal moonlight_mtvec_irq13;"
"jal moonlight_mtvec_irq14;"
"jal moonlight_mtvec_irq15;"
#endif
: /* output: none */
: /* input : immediate */
: /* clobbers: none */
);
}
// Vector table. Do not call!
// See scause table for possible entries.
// http://five-embeddev.com/riscv-isa-manual/latest/supervisor.html#sec:scause
void riscv_stvec_table(void) {
__asm__ volatile (
".org riscv_stvec_table + 0*4;"
"jal zero,riscv_stvec_exception;" /* 0 */
".org riscv_stvec_table + 1*4;"
"jal zero,riscv_stvec_ssi;" /* 1 */
".org riscv_stvec_table + 5*4;"
"jal zero,riscv_stvec_sti;" /* 5 */
".org riscv_stvec_table + 9*4;"
"jal zero,riscv_stvec_sei;" /* 9 */
: /* output: none */
: /* input : immediate */
: /* clobbers: none */
);
}
// Vector table. Do not call!
void riscv_utvec_table(void) {
__asm__ volatile (
".org riscv_utvec_table + 0*4;"
"jal zero,riscv_utvec_usi;" /* 0 */
".org riscv_utvec_table + 4*4;"
"jal zero,riscv_utvec_uti;" /* 4 */
".org riscv_utvec_table + 8*4;"
"jal zero,riscv_utvec_uei;" /* 8 */
: /* output: none */
: /* input : immediate */
: /* clobbers: none */
);
}
// Ensure all ISR functions are aligned.
#pragma GCC optimize ("align-functions=4")
static void riscv_nop_machine(void) {
// Nop machine mode interrupt.
}
static void riscv_nop_supervisor(void) {
// Nop supervisor mode interrupt.
}
static void riscv_nop_user(void) {
// Nop user mode interrupt.
}
#pragma GCC pop_options

View File

@@ -0,0 +1,113 @@
/*
Baremetal main program with timer interrupt.
SPDX-License-Identifier: Unlicense
https://five-embeddev.com/
Tested with sifive-hifive-revb, but should not have any
dependencies to any particular implementation.
Declarations of interrupt service routine entry points.
If no implementation is defined then an alias to a default "NOP"
implementation will be linked instead.
*/
#ifndef VECTOR_TABLE_H
#define VECTOR_TABLE_H
/** Symbol for machine mode vector table - do not call
*/
void riscv_mtvec_table(void) __attribute__ ((naked));
void riscv_stvec_table(void) __attribute__ ((naked));
void riscv_utvec_table(void) __attribute__ ((naked));
/** Machine mode syncronous exception handler.
http://five-embeddev.com/riscv-isa-manual/latest/machine.html#machine-trap-vector-base-address-register-mtvec
When vectored interrupts are enabled, interrupt cause 0, which
corresponds to user-mode software interrupts, are vectored to the same
location as synchronous exceptions. This ambiguity does not arise in
practice, since user-mode software interrupts are either disabled or
delegated to user mode.
*/
void riscv_mtvec_exception(void) __attribute__ ((interrupt ("machine")) );
/** Machine mode software interrupt */
void riscv_mtvec_msi(void) __attribute__ ((interrupt ("machine") ));
/** Machine mode timer interrupt */
void riscv_mtvec_mti(void) __attribute__ ((interrupt ("machine") ));
/** Machine mode al interrupt */
void riscv_mtvec_mei(void) __attribute__ ((interrupt ("machine") ));
/** Supervisor mode software interrupt */
void riscv_mtvec_ssi(void) __attribute__ ((interrupt ("machine")) );
/** Supervisor mode timer interrupt */
void riscv_mtvec_sti(void) __attribute__ ((interrupt ("machine")) );
/** Supervisor mode al interrupt */
void riscv_mtvec_sei(void) __attribute__ ((interrupt ("machine")) );
/** Supervisor mode syncronous exception handler. */
void riscv_stvec_exception(void) __attribute__ ((interrupt ("supervisor")) );
/** Supervisor mode software interrupt */
void riscv_stvec_ssi(void) __attribute__ ((interrupt ("supervisor")) );
/** Supervisor mode timer interrupt */
void riscv_stvec_sti(void) __attribute__ ((interrupt ("supervisor")) );
/** Supervisor mode al interrupt */
void riscv_stvec_sei(void) __attribute__ ((interrupt ("supervisor")) );
/** User mode software interrupt */
void riscv_utvec_usi(void) __attribute__ ((interrupt ("user")) );
/** User mode timer interrupt */
void riscv_utvec_uti(void) __attribute__ ((interrupt ("user")) );
/** User mode al interrupt */
void riscv_utvec_uei(void) __attribute__ ((interrupt ("user")) );
#ifndef VECTOR_TABLE_MTVEC_PLATFORM_INTS
/* Platform interrupts, bits 16+ of mie, mip etc
*/
/* Platform interrupt 0, bit 16 of mip/mie */
void riscv_mtvec_platform_irq0(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 1, bit 17 of mip/mie */
void riscv_mtvec_platform_irq1(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 2, bit 18 of mip/mie */
void riscv_mtvec_platform_irq2(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 3, bit 19 of mip/mie */
void riscv_mtvec_platform_irq3(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 4, bit 20 of mip/mie */
void riscv_mtvec_platform_irq4(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 5, bit 21 of mip/mie */
void riscv_mtvec_platform_irq5(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 6, bit 22 of mip/mie */
void riscv_mtvec_platform_irq6(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 7, bit 23 of mip/mie */
void riscv_mtvec_platform_irq7(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 8, bit 24 of mip/mie */
void riscv_mtvec_platform_irq8(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 9, bit 25 of mip/mie */
void riscv_mtvec_platform_irq9(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 10, bit 26 of mip/mie */
void riscv_mtvec_platform_irq10(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 11, bit 27 of mip/mie */
void riscv_mtvec_platform_irq11(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 12, bit 28 of mip/mie */
void riscv_mtvec_platform_irq12(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 13, bit 29 of mip/mie */
void riscv_mtvec_platform_irq13(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 14, bit 30 of mip/mie */
void riscv_mtvec_platform_irq14(void) __attribute__ ((interrupt ("machine")) );
/* Platform interrupt 15, bit 31 of mip/mie */
void riscv_mtvec_platform_irq15(void) __attribute__ ((interrupt ("machine")) );
#endif // #ifndef VECTOR_TABLE_MTVEC_PLATFORM_INTS
#endif // #ifndef VECTOR_TABLE_H

41
port/picolibc/port.c Normal file
View File

@@ -0,0 +1,41 @@
#include <stdio.h>
#include <sys/types.h>
extern void uart_putc(char c);
extern int uart_getc(void);
static int
board_putc(char c, FILE *file)
{
(void) file; /* Not used in this function */
uart_putc(c); /* Defined by underlying system */
return c;
}
static int
board_getc(FILE *file)
{
unsigned char c;
(void) file; /* Not used in this function */
c = uart_getc(); /* Defined by underlying system */
return c;
}
static int
board_flush(FILE *file)
{
(void) file; /* Not used in this function */
return 0;
}
static FILE __stdio = FDEV_SETUP_STREAM(board_putc, board_getc, board_flush, _FDEV_SETUP_RW);
/*
* Picolibc requires the application to define these
* when using stdio in freestanding environments.
*/
// FILE * const stdin = NULL;
// FILE * const stdout = NULL;
// FILE * const stderr = NULL;
FILE *const stdin = &__stdio;
__strong_reference(stdin, stdout);
__strong_reference(stdin, stderr);

View File

@@ -0,0 +1,20 @@
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S
#${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S
#${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c
#${CMAKE_CURRENT_LIST_DIR}/src/platform_rand.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)

373
port/threadx/inc/csr.h Normal file
View File

@@ -0,0 +1,373 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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 CSR_H
#define 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 uint64_t riscv_get_core()
{
uint64_t x;
asm volatile("csrr %0, mhartid" : "=r" (x) );
return x;
}
static inline uint64_t riscv_get_mstatus()
{
uint64_t x;
asm volatile("csrr %0, mstatus" : "=r" (x) );
return x;
}
static inline void riscv_writ_mstatus(uint64_t x)
{
asm volatile("csrw mstatus, %0" : : "r" (x));
}
// machine exception program counter, holds the
// instruction address to which a return from
// exception will go.
static inline void riscv_writ_mepc(uint64_t x)
{
asm volatile("csrw mepc, %0" : : "r" (x));
}
static inline uint64_t riscv_get_sstatus()
{
uint64_t x;
asm volatile("csrr %0, sstatus" : "=r" (x) );
return x;
}
static inline void riscv_writ_sstatus(uint64_t x)
{
asm volatile("csrw sstatus, %0" : : "r" (x));
}
// Supervisor Interrupt Pending
static inline uint64_t riscv_get_sip()
{
uint64_t x;
asm volatile("csrr %0, sip" : "=r" (x) );
return x;
}
static inline void riscv_writ_sip(uint64_t x)
{
asm volatile("csrw sip, %0" : : "r" (x));
}
static inline uint64_t riscv_get_sie()
{
uint64_t x;
asm volatile("csrr %0, sie" : "=r" (x) );
return x;
}
static inline void riscv_writ_sie(uint64_t x)
{
asm volatile("csrw sie, %0" : : "r" (x));
}
static inline uint64_t riscv_get_mie()
{
uint64_t x;
asm volatile("csrr %0, mie" : "=r" (x) );
return x;
}
static inline void riscv_writ_mie(uint64_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(uint64_t x)
{
asm volatile("csrw sepc, %0" : : "r" (x));
}
static inline uint64_t riscv_get_sepc()
{
uint64_t x;
asm volatile("csrr %0, sepc" : "=r" (x) );
return x;
}
// Machine Exception Delegation
static inline uint64_t riscv_get_medeleg()
{
uint64_t x;
asm volatile("csrr %0, medeleg" : "=r" (x) );
return x;
}
static inline void riscv_writ_medeleg(uint64_t x)
{
asm volatile("csrw medeleg, %0" : : "r" (x));
}
// Machine Interrupt Delegation
static inline uint64_t riscv_get_mideleg()
{
uint64_t x;
asm volatile("csrr %0, mideleg" : "=r" (x) );
return x;
}
static inline void riscv_writ_mideleg(uint64_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(uint64_t x)
{
asm volatile("csrw stvec, %0" : : "r" (x));
}
static inline uint64_t riscv_get_stvec()
{
uint64_t x;
asm volatile("csrr %0, stvec" : "=r" (x) );
return x;
}
// Supervisor Timer Comparison Register
static inline uint64_t riscv_get_stimecmp()
{
uint64_t x;
// asm volatile("csrr %0, stimecmp" : "=r" (x) );
asm volatile("csrr %0, 0x14d" : "=r" (x) );
return x;
}
static inline void riscv_writ_stimecmp(uint64_t x)
{
// asm volatile("csrw stimecmp, %0" : : "r" (x));
asm volatile("csrw 0x14d, %0" : : "r" (x));
}
// Machine Environment Configuration Register
static inline uint64_t riscv_get_menvcfg()
{
uint64_t x;
// asm volatile("csrr %0, menvcfg" : "=r" (x) );
asm volatile("csrr %0, 0x30a" : "=r" (x) );
return x;
}
static inline void riscv_writ_menvcfg(uint64_t x)
{
// asm volatile("csrw menvcfg, %0" : : "r" (x));
asm volatile("csrw 0x30a, %0" : : "r" (x));
}
// Physical Memory Protection
static inline void riscv_writ_pmpcfg0(uint64_t x)
{
asm volatile("csrw pmpcfg0, %0" : : "r" (x));
}
static inline void riscv_writ_pmpaddr0(uint64_t x)
{
asm volatile("csrw pmpaddr0, %0" : : "r" (x));
}
// supervisor address translation and protection;
// holds the address of the page table.
static inline void riscv_writ_satp(uint64_t x)
{
asm volatile("csrw satp, %0" : : "r" (x));
}
static inline uint64_t riscv_get_satp()
{
uint64_t x;
asm volatile("csrr %0, satp" : "=r" (x) );
return x;
}
// Supervisor Trap Cause
static inline uint64_t riscv_get_scause()
{
uint64_t x;
asm volatile("csrr %0, scause" : "=r" (x) );
return x;
}
// Supervisor Trap Value
static inline uint64_t riscv_get_stval()
{
uint64_t x;
asm volatile("csrr %0, stval" : "=r" (x) );
return x;
}
// Machine-mode Counter-Enable
static inline void riscv_writ_mcounteren(uint64_t x)
{
asm volatile("csrw mcounteren, %0" : : "r" (x));
}
static inline uint64_t riscv_get_mcounteren()
{
uint64_t x;
asm volatile("csrr %0, mcounteren" : "=r" (x) );
return x;
}
// machine-mode cycle counter
static inline uint64_t riscv_get_time()
{
uint64_t x;
asm volatile("csrr %0, time" : "=r" (x) );
return x;
}
// enable device interrupts
static inline void riscv_sintr_on()
{
uint64_t sstatus = riscv_get_sstatus();
sstatus |= SSTATUS_SIE;
riscv_writ_sstatus(sstatus);
}
// disable device interrupts
static inline void riscv_sintr_off()
{
uint64_t sstatus = riscv_get_sstatus();
sstatus &= (~SSTATUS_SIE);
riscv_writ_sstatus(sstatus);
}
// are device interrupts enabled?
static inline int riscv_sintr_get()
{
uint64_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();
}
// enable device interrupts
static inline void riscv_mintr_on()
{
uint64_t mstatus = riscv_get_mstatus();
mstatus |= MSTATUS_MIE;
riscv_writ_mstatus(mstatus);
}
// disable device interrupts
static inline void riscv_mintr_off()
{
uint64_t mstatus = riscv_get_mstatus();
mstatus &= (~MSTATUS_MIE);
riscv_writ_mstatus(mstatus);
}
// are device interrupts enabled?
static inline int riscv_mintr_get()
{
uint64_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 uint64_t riscv_get_sp()
{
uint64_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 uint64_t riscv_get_tp()
{
uint64_t x;
asm volatile("mv %0, tp" : "=r" (x) );
return x;
}
static inline void riscv_writ_tp(uint64_t x)
{
asm volatile("mv tp, %0" : : "r" (x));
}
static inline uint64_t riscv_get_ra()
{
uint64_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

194
port/threadx/inc/nx_port.h Normal file
View File

@@ -0,0 +1,194 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2025-present 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** NetX Component */
/** */
/** Port Specific */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* nx_port.h PIC32x/Microchip */
/* 6.4.3 */
/* */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file contains data type definitions that make the NetX */
/* real-time TCP/IP function identically on a variety of different */
/* processor architectures. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-31-2022 Zhen Kong Initial PIC32x/Microchip */
/* Support Version 6.2.0 */
/* */
/**************************************************************************/
#ifndef NX_PORT_H
#define NX_PORT_H
#include "tx_port.h"
/* Determine if the optional NetX user define file should be used. */
#ifdef NX_INCLUDE_USER_DEFINE_FILE
/* Yes, include the user defines in nx_user.h. The defines in this file may
alternately be defined on the command line. */
#include "nx_user.h"
#endif
/* Default to little endian, since this is what most RISC-V targets are. */
#define NX_LITTLE_ENDIAN
/* Define various constants for the port. */
#ifndef NX_IP_PERIODIC_RATE
#define NX_IP_PERIODIC_RATE \
10 /* Default IP periodic rate of 1 second for \
ports with 1ms timer interrupts. This \
value may be defined instead at the \
command line and this value will not be \
used. */
#endif
/* Define macros that swap the endian for little endian ports. */
#ifdef NX_LITTLE_ENDIAN
#define NX_CHANGE_ULONG_ENDIAN(arg) \
{ \
ULONG _i; \
ULONG _tmp; \
_i = (UINT)arg; \
/* _i = A, B, C, D */ \
_tmp = _i ^ (((_i) >> 16) | (_i << 16)); \
/* _tmp = _i ^ (_i ROR 16) = A^C, B^D, C^A, D^B */ \
_tmp &= 0xff00ffff; \
/* _tmp = A^C, 0, C^A, D^B */ \
_i = ((_i) >> 8) | (_i << 24); \
/* _i = D, A, B, C */ \
_i = _i ^ ((_tmp) >> 8); \
/* _i = D, C, B, A */ \
arg = _i; \
}
#define NX_CHANGE_USHORT_ENDIAN(a) (a = (((a >> 8) | (a << 8)) & 0xFFFF))
#ifndef htonl
#define htonl(val) NX_CHANGE_ULONG_ENDIAN(val)
#endif /* htonl */
#ifndef ntohl
#define ntohl(val) NX_CHANGE_ULONG_ENDIAN(val)
#endif /* ntohl */
#ifndef htons
#define htons(val) NX_CHANGE_USHORT_ENDIAN(val)
#endif /*htons */
#ifndef ntohs
#define ntohs(val) NX_CHANGE_USHORT_ENDIAN(val)
#endif /*ntohs */
#else
#define NX_CHANGE_ULONG_ENDIAN(a)
#define NX_CHANGE_USHORT_ENDIAN(a)
#ifndef htons
#define htons(val) (val)
#endif /* htons */
#ifndef ntohs
#define ntohs(val) (val)
#endif /* ntohs */
#ifndef ntohl
#define ntohl(val) (val)
#endif
#ifndef htonl
#define htonl(val) (val)
#endif /* htonl */
#endif
/* Define several macros for the error checking shell in NetX. */
#ifndef TX_TIMER_PROCESS_IN_ISR
#define NX_CALLER_CHECKING_EXTERNS \
extern TX_THREAD* _tx_thread_current_ptr; \
extern TX_THREAD _tx_timer_thread; \
extern volatile ULONG TX_THREAD_GET_SYSTEM_STATE();
#define NX_THREADS_ONLY_CALLER_CHECKING \
if((TX_THREAD_GET_SYSTEM_STATE()) || (_tx_thread_current_ptr == TX_NULL) || (_tx_thread_current_ptr == &_tx_timer_thread)) \
return (NX_CALLER_ERROR);
#define NX_INIT_AND_THREADS_CALLER_CHECKING \
if(((TX_THREAD_GET_SYSTEM_STATE()) && (TX_THREAD_GET_SYSTEM_STATE() < ((ULONG)0xF0F0F0F0))) || \
(_tx_thread_current_ptr == &_tx_timer_thread)) \
return (NX_CALLER_ERROR);
#define NX_NOT_ISR_CALLER_CHECKING \
if((TX_THREAD_GET_SYSTEM_STATE()) && (TX_THREAD_GET_SYSTEM_STATE() < ((ULONG)0xF0F0F0F0))) \
return (NX_CALLER_ERROR);
#define NX_THREAD_WAIT_CALLER_CHECKING \
if((wait_option) && \
((_tx_thread_current_ptr == NX_NULL) || (TX_THREAD_GET_SYSTEM_STATE()) || (_tx_thread_current_ptr == &_tx_timer_thread))) \
return (NX_CALLER_ERROR);
#else
#define NX_CALLER_CHECKING_EXTERNS \
extern TX_THREAD* _tx_thread_current_ptr; \
extern volatile ULONG TX_THREAD_GET_SYSTEM_STATE();
#define NX_THREADS_ONLY_CALLER_CHECKING \
if((TX_THREAD_GET_SYSTEM_STATE()) || (_tx_thread_current_ptr == TX_NULL)) \
return (NX_CALLER_ERROR);
#define NX_INIT_AND_THREADS_CALLER_CHECKING \
if(((TX_THREAD_GET_SYSTEM_STATE()) && (TX_THREAD_GET_SYSTEM_STATE() < ((ULONG)0xF0F0F0F0)))) \
return (NX_CALLER_ERROR);
#define NX_NOT_ISR_CALLER_CHECKING \
if((TX_THREAD_GET_SYSTEM_STATE()) && (TX_THREAD_GET_SYSTEM_STATE() < ((ULONG)0xF0F0F0F0))) \
return (NX_CALLER_ERROR);
#define NX_THREAD_WAIT_CALLER_CHECKING \
if((wait_option) && ((_tx_thread_current_ptr == NX_NULL) || (TX_THREAD_GET_SYSTEM_STATE()))) \
return (NX_CALLER_ERROR);
#endif
/* Define the version ID of NetX. This may be utilized by the application. */
#ifdef NX_SYSTEM_INIT
CHAR _nx_version_id[] = "Copyright (c) 2024 Microsoft Corporation. * NetX Duo PIC32x/MPLAB Version 6.4.1 *";
#else
extern CHAR _nx_version_id[];
#endif
#endif

785
port/threadx/inc/nx_user.h Normal file
View File

@@ -0,0 +1,785 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2025-present 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** NetX Component */
/** */
/** User Specific */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* nx_user.h PORTABLE C */
/* 6.4.3 */
/* */
/* AUTHOR */
/* */
/* Yuxin Zhou, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file contains user defines for configuring NetX in specific */
/* ways. This file will have an effect only if the application and */
/* NetX library are built with NX_INCLUDE_USER_DEFINE_FILE defined. */
/* Note that all the defines in this file may also be made on the */
/* command line when building NetX library and application objects. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 08-02-2021 Yuxin Zhou Modified comment(s), and */
/* supported TCP/IP offload, */
/* resulting in version 6.1.8 */
/* 04-25-2022 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1.11 */
/* 10-31-2023 Tiejun Zhou Modified comment(s), */
/* supported random IP id, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
#ifndef NX_USER_H
#define NX_USER_H
#if __riscv_xlen == 64
#define NX_CRYPTO_HUGE_NUMBER_BITS 16
#else
#define NX_CRYPTO_HUGE_NUMBER_BITS 32
#endif
/* Define various build options for the NetX Duo port. The application should either make changes
here by commenting or un-commenting the conditional compilation defined OR supply the defines
though the compiler's equivalent of the -D option. */
/* Override various options with default values already assigned in nx_api.h or nx_port.h. Please
also refer to nx_port.h for descriptions on each of these options. */
/* Configuration options for Interface */
/* NX_MAX_PHYSICAL_INTERFACES defines the number physical network interfaces
present to NetX Duo IP layer. Physical interface does not include
loopback interface. By default there is at least one physical interface
in the system. */
/*
#define NX_MAX_PHYSICAL_INTERFACES 1
*/
/* Defined, this option disables NetX Duo support on the 127.0.0.1 loopback interface.
127.0.0.1 loopback interface is enabled by default. Uncomment out the follow code to disable
the loopback interface. */
/*
#define NX_DISABLE_LOOPBACK_INTERFACE
*/
/* If defined, the link driver is able to specify extra capability, such as checksum offloading features. */
/*
#define NX_ENABLE_INTERFACE_CAPABILITY
*/
/* Configuration options for IP */
/* This defines specifies the number of ThreadX timer ticks in one second. The default value is based
on ThreadX timer interrupt. */
/*
#ifdef TX_TIMER_TICKS_PER_SECOND
#define NX_IP_PERIODIC_RATE TX_TIMER_TICKS_PER_SECOND
#else
#define NX_IP_PERIODIC_RATE 100
#endif
*/
/* Defined, NX_ENABLE_IP_RAW_PACKET_FILTER allows an application to install a filter
for incoming raw packets. This feature is disabled by default. */
/*
#define NX_ENABLE_IP_RAW_PACKET_FILTER
*/
/* This define specifies the maximum number of RAW packets can be queued for receive. The default
value is 20. */
/*
#define NX_IP_RAW_MAX_QUEUE_DEPTH 20
*/
/* Defined, this option enables IP static routing feature. By default IP static routing
feature is not compiled in. */
/*
#define NX_ENABLE_IP_STATIC_ROUTING
*/
/* This define specifies the size of IP routing table. The default value is 8. */
/*
#define NX_IP_ROUTING_TABLE_SIZE 8
*/
/* Defined, this option enables random IP id. By default IP id is increased by one for each packet. */
/*
#define NX_ENABLE_IP_ID_RANDOMIZATION
*/
/* This define specifies the maximum number of multicast groups that can be joined.
The default value is 7. */
/*
#define NX_MAX_MULTICAST_GROUPS 7
*/
/* Configuration options for IPv6 */
/* Disable IPv6 processing in NetX Duo. */
/*
#define NX_DISABLE_IPV6
*/
/* Define the number of entries in IPv6 address pool. */
/*
#ifdef NX_MAX_PHYSICAL_INTERFACES
#define NX_MAX_IPV6_ADDRESSES (NX_MAX_PHYSICAL_INTERFACES * 3)
#endif
*/
/* Do not process IPv6 ICMP Redirect Messages. */
/*
#define NX_DISABLE_ICMPV6_REDIRECT_PROCESS
*/
/* Do not process IPv6 Router Advertisement Messages. */
/*
#define NX_DISABLE_ICMPV6_ROUTER_ADVERTISEMENT_PROCESS
*/
/* Do not send IPv6 Router Solicitation Messages. */
/*
#define NX_DISABLE_ICMPV6_ROUTER_SOLICITATION
*/
/* Define the max number of router solicitations a host sends until a router response
is received. If no response is received, the host concludes no router is present. */
/*
#define NX_ICMPV6_MAX_RTR_SOLICITATIONS 3
*/
/* Define the interval between which the host sends router solicitations in seconds. */
/*
#define NX_ICMPV6_RTR_SOLICITATION_INTERVAL 4
*/
/* Define the maximum delay for the initial router solicitation in seconds. */
/*
#define NX_ICMPV6_RTR_SOLICITATION_DELAY 1
*/
/* Do not send ICMPv4 Error Messages. */
/*
#define NX_DISABLE_ICMPV4_ERROR_MESSAGE
*/
/* Do not send ICMPv6 Error Messages. */
/*
#define NX_DISABLE_ICMPV6_ERROR_MESSAGE
*/
/* Disable the Duplicate Address Detection (DAD) protocol when configuring the host IP address. */
/*
#define NX_DISABLE_IPV6_DAD
*/
/* If defined, application is able to control whether or not to perform IPv6 stateless
address autoconfiguration with nxd_ipv6_stateless_address_autoconfig_enable() or
nxd_ipv6_stateless_address_autoconfig_disable() service. If defined, the system starts
with IPv6 stateless address autoconfiguration enabled. This feature is disabled by default. */
/*
#define NX_IPV6_STATELESS_AUTOCONFIG_CONTROL
*/
/* If enabled, application is able to install a callback function to get notified
when an interface IPv6 address is changed. By default this feature is disabled. */
/*
#define NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY
*/
/* Defined, this option prevents NetX Duo from removing stale (old) cache table entries
whose timeout has not expired so are otherwise still valid) to make room for new entries
when the table is full. Static and router entries are not purged. */
/*
#define NX_DISABLE_IPV6_PURGE_UNUSED_CACHE_ENTRIES
*/
/* This define enables simple IPv6 multicast group join/leave function. By default
the IPv6 multicast join/leave function is not enabled. */
/*
#define NX_ENABLE_IPV6_MULTICAST
*/
/* Defined, Minimum Path MTU Discovery feature is enabled. */
/*
#define NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
*/
/* Define wait interval in seconds to reset the path MTU for a destination
table entry after decreasing it in response to a packet too big error message.
RFC 1981 Section 5.4 states the minimum time to wait is
5 minutes and recommends 10 minutes.
*/
/*
#define NX_PATH_MTU_INCREASE_WAIT_INTERVAL 600
*/
/* Configuration options for Neighbor Discovery. */
/* Define values used for Neighbor Discovery protocol.
The default values are suggested by RFC2461, chapter 10. */
/* Define the maximum number of multicast Neighbor Solicitation packets
NetX Duo sends for a packet destination needing physical mapping
to the IP address. */
/*
#define NX_MAX_MULTICAST_SOLICIT 3
*/
/* Define the maximum number of unicast Neighbor Solicitation packets
NetX Duo sends for a cache entry whose reachable time has expired
and gone "stale". */
/*
#define NX_MAX_UNICAST_SOLICIT 3
*/
/* Define the length of time, in seconds, that a Neighbor Cache table entry
remains in the reachable state before it becomes state. */
/*
#define NX_REACHABLE_TIME 30
*/
/* Define the length of time, in milliseconds, between retransmitting
Neighbor Solicitation (NS) packets. */
/*
#define NX_RETRANS_TIMER 1000
*/
/* Define the length of time, in seconds, for a Neighbor Cache entry
to remain in the Delay state. This is the Delay first probe timer. */
/*
#define NX_DELAY_FIRST_PROBE_TIME 5
*/
/* This defines specifies the maximum number of packets that can be queued while waiting for a
Neighbor Discovery to resolve an IPv6 address. The default value is 4. */
/*
#define NX_ND_MAX_QUEUE_DEPTH 4
*/
/* Define the maximum ICMPv6 Duplicate Address Detect Transmit . */
/*
#define NX_IPV6_DAD_TRANSMITS 3
*/
/* Define the number of neighbor cache entries. */
/*
#define NX_IPV6_NEIGHBOR_CACHE_SIZE 16
*/
/* Define the size of the IPv6 destination table. */
/*
#define NX_IPV6_DESTINATION_TABLE_SIZE 8
*/
/* Define the size of the IPv6 prefix table. */
/*
#define NX_IPV6_PREFIX_LIST_TABLE_SIZE 8
*/
/* Configuration options for IPSEC */
/* This define enables IPSEC in NetX Duo. */
/*
#define NX_IPSEC_ENABLE
*/
/* Configuration options for NAT */
/* This define enables NAT process in NetX Duo. */
/*
#define NX_NAT_ENABLE
*/
/* Configuration options for IGMP */
/* Defined, IGMP v2 support is disabled. By default NetX Duo
is built with IGMPv2 enabled . By uncommenting this option,
NetX Duo reverts back to IGMPv1 only. */
/*
#define NX_DISABLE_IGMPV2
*/
/* Configuration options for ARP */
/* When defines, ARP reply is sent when address conflict occurs. */
/*
#define NX_ARP_DEFEND_BY_REPLY
*/
/* To use the ARP collision handler to check for invalid ARP messages
matching existing entries in the table (man in the middle attack),
enable this feature. */
/*
#define NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION
*/
/* This define specifies the number of seconds ARP entries remain valid. The default value of 0 disables
aging of ARP entries. */
/*
#define NX_ARP_EXPIRATION_RATE 0
*/
/* This define specifies the number of seconds between ARP retries. The default value is 10, which represents
10 seconds. */
/*
#define NX_ARP_UPDATE_RATE 10
*/
/* This define specifies the maximum number of ARP retries made without an ARP response. The default
value is 18. */
/*
#define NX_ARP_MAXIMUM_RETRIES 18
*/
/* This defines specifies the maximum number of packets that can be queued while waiting for an ARP
response. The default value is 4. */
/*
#define NX_ARP_MAX_QUEUE_DEPTH 4
*/
/* Defined, this option disables entering ARP request information in the ARP cache. */
/*
#define NX_DISABLE_ARP_AUTO_ENTRY
*/
/* Define the ARP defend interval. The default value is 10 seconds. */
/*
#define NX_ARP_DEFEND_INTERVAL 10
*/
/* Configuration options for TCP */
/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the
timer rate for the TCP delayed ACK processing. The default value is 5, which represents 200ms. */
/*
#define NX_TCP_ACK_TIMER_RATE 5
*/
/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the
fast TCP timer rate. The fast TCP timer is used to drive various TCP timers, including the delayed ACK
timer. The default value is 10, which represents 100ms. */
/*
#define NX_TCP_FAST_TIMER_RATE 10
*/
/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the
timer rate for the TCP transmit retry processing. The default value is 1, which represents 1 second. */
/*
#define NX_TCP_TRANSMIT_TIMER_RATE 1
*/
/* This define specifies how many seconds of inactivity before the keepalive timer activates. The default
value is 7200, which represents 2 hours. */
/*
#define NX_TCP_KEEPALIVE_INITIAL 7200
*/
/* This define specifies how many seconds between retries of the keepalive timer assuming the other side
of the connection is not responding. The default value is 75, which represents 75 seconds between
retries. */
/*
#define NX_TCP_KEEPALIVE_RETRY 75
*/
/* This define specifies the maximum packets that are out of order. The default value is 8. */
/*
#define NX_TCP_MAX_OUT_OF_ORDER_PACKETS 8
*/
/* This define specifies the maximum number of TCP server listen requests. The default value is 10. */
/*
#define NX_MAX_LISTEN_REQUESTS 10
*/
/* Defined, this option enables the optional TCP keepalive timer. */
/*
#define NX_ENABLE_TCP_KEEPALIVE
*/
/* Defined, this option enables the optional TCP immediate ACK response processing. */
/*
#define NX_TCP_IMMEDIATE_ACK
*/
/* This define specifies the number of TCP packets to receive before sending an ACK. */
/* The default value is 2: ack every 2 packets. */
/*
#define NX_TCP_ACK_EVERY_N_PACKETS 2
*/
/* Automatically define NX_TCP_ACK_EVERY_N_PACKETS to 1 if NX_TCP_IMMEDIATE_ACK is defined.
This is needed for backward compatibility. */
#if(defined(NX_TCP_IMMEDIATE_ACK) && !defined(NX_TCP_ACK_EVERY_N_PACKETS))
#define NX_TCP_ACK_EVERY_N_PACKETS 1
#endif
/* This define specifies how many transmit retires are allowed before the connection is deemed broken.
The default value is 10. */
/*
#define NX_TCP_MAXIMUM_RETRIES 10
*/
/* This define specifies the maximum depth of the TCP transmit queue before TCP send requests are
suspended or rejected. The default value is 20, which means that a maximum of 20 packets can be in
the transmit queue at any given time. */
/*
#define NX_TCP_MAXIMUM_TX_QUEUE 20
*/
/* This define specifies how the retransmit timeout period changes between successive retries. If this
value is 0, the initial retransmit timeout is the same as subsequent retransmit timeouts. If this
value is 1, each successive retransmit is twice as long. The default value is 0. */
/*
#define NX_TCP_RETRY_SHIFT 0
*/
/* This define specifies how many keepalive retries are allowed before the connection is deemed broken.
The default value is 10. */
/*
#define NX_TCP_KEEPALIVE_RETRIES 10
*/
/* Defined, this option enables the TCP window scaling feature. (RFC 1323). Default disabled. */
/*
#define NX_ENABLE_TCP_WINDOW_SCALING
*/
/* Defined, this option disables the reset processing during disconnect when the timeout value is
specified as NX_NO_WAIT. */
/*
#define NX_DISABLE_RESET_DISCONNECT
*/
/* If defined, the incoming SYN packet (connection request) is checked for a minimum acceptable
MSS for the host to accept the connection. The default minimum should be based on the host
application packet pool payload, socket transmit queue depth and relevant application specific parameters. */
/*
#define NX_ENABLE_TCP_MSS_CHECK
#define NX_TCP_MSS_MINIMUM 128
*/
/* If defined, NetX Duo has a notify callback for the transmit TCP socket queue decreased from
the maximum queue depth. */
/*
#define NX_ENABLE_TCP_QUEUE_DEPTH_UPDATE_NOTIFY
*/
/* Defined, feature of low watermark is enabled. */
/*
#define NX_ENABLE_LOW_WATERMARK
*/
/* Define the maximum receive queue for TCP socket. */
/*
#ifdef NX_ENABLE_LOW_WATERMARK
#define NX_TCP_MAXIMUM_RX_QUEUE 20
#endif
*/
/* Configuration options for fragmentation */
/* Defined, this option disables both IPv4 and IPv6 fragmentation and reassembly logic. */
/*
#define NX_DISABLE_FRAGMENTATION
*/
/* Defined, this option process IP fragmentation immediately. */
/*
#define NX_FRAGMENT_IMMEDIATE_ASSEMBLY
*/
/* This define specifies the maximum time of IP reassembly. The default value is 60.
By default this option is not defined. */
/*
#define NX_IP_MAX_REASSEMBLY_TIME 60
*/
/* This define specifies the maximum time of IPv4 reassembly. The default value is 15.
Note that if NX_IP_MAX_REASSEMBLY_TIME is defined, this option is automatically defined as 60.
By default this option is not defined. */
/*
#define NX_IPV4_MAX_REASSEMBLY_TIME 15
*/
/* This define specifies the maximum time of IPv6 reassembly. The default value is 60.
Note that if NX_IP_MAX_REASSEMBLY_TIME is defined, this option is automatically defined as 60.
By default this option is not defined. */
/*
#define NX_IPV6_MAX_REASSEMBLY_TIME 60
*/
/* Configuration options for checksum */
/* Defined, this option disables checksum logic on received ICMPv4 packets.
Note that if NX_DISABLE_ICMP_RX_CHECKSUM is defined, this option is
automatically defined. By default this option is not defined.*/
/*
#define NX_DISABLE_ICMPV4_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on received ICMPv6 packets.
Note that if NX_DISABLE_ICMP_RX_CHECKSUM is defined, this option is
automatically defined. By default this option is not defined.*/
/*
#define NX_DISABLE_ICMPV6_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on received ICMPv4 or ICMPv6 packets.
Note that if NX_DISABLE_ICMP_RX_CHECKSUM is defined, NX_DISABLE_ICMPV4_RX_CHECKSUM
and NX_DISABLE_ICMPV6_RX_CHECKSUM are automatically defined. */
/*
#define NX_DISABLE_ICMP_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted ICMPv4 packets.
Note that if NX_DISABLE_ICMP_TX_CHECKSUM is defined, this option is
automatically defined. By default this option is not defined.*/
/*
#define NX_DISABLE_ICMPV4_TX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted ICMPv6 packets.
Note that if NX_DISABLE_ICMP_TX_CHECKSUM is defined, this option is
automatically defined. By default this option is not defined.*/
/*
#define NX_DISABLE_ICMPV6_TX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted ICMPv4 or ICMPv6 packets.
Note that if NX_DISABLE_ICMP_TX_CHECKSUM is defined, NX_DISABLE_ICMPV4_TX_CHECKSUM
and NX_DISABLE_ICMPV6_TX_CHECKSUM are automatically defined. */
/*
#define NX_DISABLE_ICMP_TX_CHECKSUM
*/
/* Defined, this option disables checksum logic on received IP packets. This is useful if the link-layer
has reliable checksum or CRC logic. */
/*
#define NX_DISABLE_IP_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted IP packets. */
/*
#define NX_DISABLE_IP_TX_CHECKSUM
*/
/* Defined, this option disables checksum logic on received TCP packets. */
/*
#define NX_DISABLE_TCP_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted TCP packets. */
/*
#define NX_DISABLE_TCP_TX_CHECKSUM
*/
/* Defined, this option disables checksum logic on received UDP packets. */
/*
#define NX_DISABLE_UDP_RX_CHECKSUM
*/
/* Defined, this option disables checksum logic on transmitted UDP packets. Note that
IPV6 requires the UDP checksum computed for outgoing packets. If this option is
defined, the IPv6 NetX Duo host must ensure the UDP checksum is computed elsewhere
before the packet is transmitted. */
/*
#define NX_DISABLE_UDP_TX_CHECKSUM
*/
/* Configuration options for statistics. */
/* Defined, ARP information gathering is disabled. */
/*
#define NX_DISABLE_ARP_INFO
*/
/* Defined, IP information gathering is disabled. */
/*
#define NX_DISABLE_IP_INFO
*/
/* Defined, ICMP information gathering is disabled. */
/*
#define NX_DISABLE_ICMP_INFO
*/
/* Defined, IGMP information gathering is disabled. */
/*
#define NX_DISABLE_IGMP_INFO
*/
/* Defined, packet information gathering is disabled. */
/*
#define NX_DISABLE_PACKET_INFO
*/
/* Defined, RARP information gathering is disabled. */
/*
#define NX_DISABLE_RARP_INFO
*/
/* Defined, TCP information gathering is disabled. */
/*
#define NX_DISABLE_TCP_INFO
*/
/* Defined, UDP information gathering is disabled. */
/*
#define NX_DISABLE_UDP_INFO
*/
/* Configuration options for Packet Pool */
/* This define specifies the size of the physical packet header. The default value is 16 (based on
a typical 16-byte Ethernet header). */
/*
#define NX_PHYSICAL_HEADER 16
*/
/* This define specifies the size of the physical packet trailer and is typically used to reserve storage
for things like Ethernet CRCs, etc. */
/*
#define NX_PHYSICAL_TRAILER 4
*/
/* Defined, this option disables the addition size checking on received packets. */
/*
#define NX_DISABLE_RX_SIZE_CHECKING
*/
/* Defined, packet debug infromation is enabled. */
/*
#define NX_ENABLE_PACKET_DEBUG_INFO
*/
/* Defined, NX_PACKET structure is padded for alignment purpose. The default is no padding. */
/*
#define NX_PACKET_HEADER_PAD
#define NX_PACKET_HEADER_PAD_SIZE 1
*/
/* Defined, packet header and payload are aligned automatically by the value. The default value is sizeof(ULONG). */
/*
#define NX_PACKET_ALIGNMENT sizeof(ULONG)
*/
/* If defined, the packet chain feature is removed. */
/*
#define NX_DISABLE_PACKET_CHAIN
*/
/* Defined, the IP instance manages two packet pools. */
/*
#define NX_ENABLE_DUAL_PACKET_POOL
*/
/* Configuration options for Others */
/* Defined, this option bypasses the basic NetX error checking. This define is typically used
after the application is fully debugged. */
/*
#define NX_DISABLE_ERROR_CHECKING
*/
/* Defined, this option enables deferred driver packet handling. This allows the driver to place a raw
packet on the IP instance and have the driver's real processing routine called from the NetX internal
IP helper thread. */
/*
#define NX_DRIVER_DEFERRED_PROCESSING
*/
/* Defined, the source address of incoming packet is checked. The default is disabled. */
/*
#define NX_ENABLE_SOURCE_ADDRESS_CHECK
*/
/* Defined, the extended notify support is enabled. This feature adds additional callback/notify services
to NetX Duo API for notifying the application of socket events, such as TCP connection and disconnect
completion. These extended notify functions are mainly used by the BSD wrapper. The default is this
feature is disabled. */
/*
#define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT
*/
/* Defined, ASSERT is disabled. The default is enabled. */
/*
#define NX_DISABLE_ASSERT
*/
/* Define the process when assert fails. */
/*
#define NX_ASSERT_FAIL while (1) tx_thread_sleep(NX_WAIT_FOREVER);
*/
/* Defined, the IPv4 feature is disabled. */
/*
#define NX_DISABLE_IPV4
*/
/* Defined, the destination address of ICMP packet is checked. The default is disabled.
An ICMP Echo Request destined to an IP broadcast or IP multicast address will be silently discarded.
*/
/*
#define NX_ENABLE_ICMP_ADDRESS_CHECK
*/
/* Define the max string length. The default value is 1024. */
/*
#define NX_MAX_STRING_LENGTH 1024
*/
/* Defined, the TCP/IP offload feature is enabled.
NX_ENABLE_INTERFACE_CAPABILITY must be defined to enable this feature. */
/*
#define NX_ENABLE_TCPIP_OFFLOAD
*/
/* Defined, the VLAN feature is enabled.
Note: Require driver support to use APIs from this file.
A quick check in driver is to search for
NX_LINK_RAW_PACKET_SEND. VLAN APIs are not supported if not found. */
/*
#define NX_ENABLE_VLAN
*/
#ifdef __cplusplus
extern "C" {
#endif
int rand(void);
void srand(unsigned seed);
#ifdef __cplusplus
}
#endif
#define NX_RAND rand
#define NX_SRAND srand
#endif

279
port/threadx/inc/tx_port.h Normal file
View File

@@ -0,0 +1,279 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Port Specific */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* tx_port.h RISC-V64/GNU */
/* 6.2.1 */
/* */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file contains data type definitions that make the ThreadX */
/* real-time kernel function identically on a variety of different */
/* processor architectures. For example, the size or number of bits */
/* in an "int" data type vary between microprocessor architectures and */
/* even C compilers for the same microprocessor. ThreadX does not */
/* directly use native C data types. Instead, ThreadX creates its */
/* own special types that can be mapped to actual data types by this */
/* file to guarantee consistency in the interface and functionality. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
#ifndef TX_PORT_H
#define TX_PORT_H
#ifdef __ASSEMBLER__
#if __riscv_xlen == 64
#define SLL32 sllw
#define STORE sd
#define LOAD ld
#define LWU lwu
#define LOG_REGBYTES 3
#else
#define SLL32 sll
#define STORE sw
#define LOAD lw
#define LWU lw
#define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#define TX_THREAD_STACK_END_OFFSET 2*4 + 2*REGBYTES
#define TX_THREAD_TIME_SLICE_OFFSET 3*4+ 3*REGBYTES
#else /*not __ASSEMBLER__ */
/* Include for memset. */
#include <string.h>
/* include for strtoul*/
#include <stdlib.h>
/* Determine if the optional ThreadX user define file should be used. */
#ifdef TX_INCLUDE_USER_DEFINE_FILE
/* Yes, include the user defines in tx_user.h. The defines in this file may
alternately be defined on the command line. */
#include "nx_user.h"
#include "tx_user.h"
#endif
/* Define compiler library include files. */
/* Define ThreadX basic types for this port. */
#define VOID void
typedef char CHAR;
typedef unsigned char UCHAR;
typedef int INT;
typedef unsigned int UINT;
typedef int LONG;
typedef unsigned int ULONG;
typedef unsigned long long ULONG64;
typedef short SHORT;
typedef unsigned short USHORT;
#define ULONG64_DEFINED
#define ALIGN_TYPE_DEFINED
#define ALIGN_TYPE ULONG64
/* Define the priority levels for ThreadX. Legal values range
from 32 to 1024 and MUST be evenly divisible by 32. */
#ifndef TX_MAX_PRIORITIES
#define TX_MAX_PRIORITIES 32
#endif
/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during
thread creation is less than this value, the thread create call will return an error. */
#ifndef TX_MINIMUM_STACK
#define TX_MINIMUM_STACK 1024 /* Minimum stack size for this port */
#endif
/* Define the system timer thread's default stack size and priority. These are only applicable
if TX_TIMER_PROCESS_IN_ISR is not defined. */
#ifndef TX_TIMER_THREAD_STACK_SIZE
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
#endif
#ifndef TX_TIMER_THREAD_PRIORITY
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
#endif
/* Define various constants for the ThreadX RISC-V port. */
#define TX_INT_DISABLE 0x00000000 /* Disable interrupts value */
#define TX_INT_ENABLE 0x00000008 /* Enable interrupt value */
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
source constants would be:
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
*/
#ifndef TX_TRACE_TIME_SOURCE
#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time
#endif
#ifndef TX_TRACE_TIME_MASK
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
#endif
/* Define the port specific options for the _tx_build_options variable. This variable indicates
how the ThreadX library was built. */
#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0
/* Define the in-line initialization constant so that modules with in-line
initialization capabilities can prevent their initialization from being
a function call. */
#define TX_INLINE_INITIALIZATION
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
define is negated, thereby forcing the stack fill which is necessary for the stack checking
logic. */
#ifdef TX_ENABLE_STACK_CHECKING
#undef TX_DISABLE_STACK_FILLING
#endif
/* Define the TX_THREAD control block extensions for this port. The main reason
for the multiple macros is so that backward compatibility can be maintained with
existing ThreadX kernel awareness modules. */
#define TX_THREAD_EXTENSION_0
#define TX_THREAD_EXTENSION_1
#define TX_THREAD_EXTENSION_2
#define TX_THREAD_EXTENSION_3
/* Define the port extensions of the remaining ThreadX objects. */
#define TX_BLOCK_POOL_EXTENSION
#define TX_BYTE_POOL_EXTENSION
#define TX_EVENT_FLAGS_GROUP_EXTENSION
#define TX_MUTEX_EXTENSION
#define TX_QUEUE_EXTENSION
#define TX_SEMAPHORE_EXTENSION
#define TX_TIMER_EXTENSION
/* Define the user extension field of the thread control block. Nothing
additional is needed for this port so it is defined as white space. */
#ifndef TX_THREAD_USER_EXTENSION
#define TX_THREAD_USER_EXTENSION
#endif
/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete,
tx_thread_shell_entry, and tx_thread_terminate. */
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
/* Define the ThreadX object creation extensions for the remaining objects. */
#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
#define TX_QUEUE_CREATE_EXTENSION(queue_ptr)
#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
#define TX_TIMER_CREATE_EXTENSION(timer_ptr)
/* Define the ThreadX object deletion extensions for the remaining objects. */
#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
#define TX_QUEUE_DELETE_EXTENSION(queue_ptr)
#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
/* Define ThreadX interrupt lockout and restore macros for protection on
access of critical kernel information. The restore interrupt macro must
restore the interrupt posture of the running thread prior to the value
present prior to the disable macro. In most cases, the save area macro
is used to define a local function save area for the disable and restore
macros. */
#ifdef TX_DISABLE_INLINE
ULONG64 _tx_thread_interrupt_control(unsigned int new_posture);
#define TX_INTERRUPT_SAVE_AREA register ULONG64 interrupt_save;
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE);
#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save);
#else
#define TX_INTERRUPT_SAVE_AREA ULONG64 interrupt_save;
/* Atomically read mstatus into interrupt_save and clear bit 3 of mstatus. */
#define TX_DISABLE \
{ __asm__("csrrci %0, mstatus, 0x08" : "=r"(interrupt_save) :); };
/* We only care about mstatus.mie (bit 3), so mask interrupt_save and write to mstatus. */
#define TX_RESTORE \
{ \
register ULONG64 __tempmask = interrupt_save & 0x08; \
__asm__("csrrs x0, mstatus, %0 \n\t" : : "r"(__tempmask) :); \
};
#endif
/* Define the interrupt lockout macros for each ThreadX object. */
#define TX_BLOCK_POOL_DISABLE TX_DISABLE
#define TX_BYTE_POOL_DISABLE TX_DISABLE
#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE
#define TX_MUTEX_DISABLE TX_DISABLE
#define TX_QUEUE_DISABLE TX_DISABLE
#define TX_SEMAPHORE_DISABLE TX_DISABLE
/* Define the version ID of ThreadX. This may be utilized by the application. */
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] = "Copyright (c) 2024 Microsoft Corporation. * ThreadX RISC-V64/GNU Version 6.4.2 *";
#else
extern CHAR _tx_version_id[];
#endif
#endif /*not __ASSEMBLER__ */
#endif

View File

@@ -0,0 +1,163 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Jer6y , luojun@oerv.isrc.iscas.ac.cn */
/* */
/* 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 */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-25-2024 Jerry Luo */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Initialize */
/** */
/**************************************************************************/
/**************************************************************************/
.global trap_entry
.extern _tx_thread_context_restore
trap_entry:
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, -65*REGBYTES // Allocate space for all registers - with floating point enabled
#else
addi sp, sp, -32*REGBYTES // Allocate space for all registers - without floating point enabled
#endif
STORE x1, 28*REGBYTES(sp) // Store RA, 28*REGBYTES(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, -8
STORE ra, 0(sp)
call trap_handler
LOAD ra, 0(sp)
addi sp, sp, 8
call _tx_thread_context_restore
// it will nerver return
.weak trap_handler
trap_handler:
1:
j 1b
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_initialize_low_level RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* 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 */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* 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:
STORE sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer
la t0, _end // Pickup first free address
STORE t0, _tx_initialize_unused_memory, 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, -8
STORE ra, 0(sp)
call board_init
LOAD ra, 0(sp)
addi sp, sp, 8
la t0, trap_entry
csrw mtvec, t0
ret

View File

@@ -0,0 +1,382 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_restore RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function restores the interrupt context if it is processing a */
/* nested interrupt. If not, it returns to the interrupt thread if no */
/* preemption is necessary. Otherwise, if preemption is necessary or */
/* if no thread was running, the function returns to the scheduler. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_schedule Thread scheduling routine */
/* */
/* CALLED BY */
/* */
/* ISRs Interrupt Service Routines */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_thread_context_restore(VOID)
{ */
.global _tx_thread_context_restore
_tx_thread_context_restore:
/* Lockout interrupts. */
csrci mstatus, 0x08 // Disable interrupts
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
call _tx_execution_isr_exit // Call the ISR execution exit function
#endif
/* Determine if interrupts are nested. */
/* if (--_tx_thread_system_state)
{ */
la t0, _tx_thread_system_state // Pickup addr of nested interrupt count
lw t1, 0(t0) // Pickup nested interrupt count
addi t1, t1, -1 // Decrement the nested interrupt counter
sw t1, 0(t0) // Store new nested count
beqz t1, _tx_thread_not_nested_restore // If 0, not nested restore
/* Interrupts are nested. */
/* Just recover the saved registers and return to the point of
interrupt. */
/* Recover floating point registers. */
#if defined(__riscv_float_abi_single)
flw f0, 31*REGBYTES(sp) // Recover ft0
flw f1, 32*REGBYTES(sp) // Recover ft1
flw f2, 33*REGBYTES(sp) // Recover ft2
flw f3, 34*REGBYTES(sp) // Recover ft3
flw f4, 35*REGBYTES(sp) // Recover ft4
flw f5, 36*REGBYTES(sp) // Recover ft5
flw f6, 37*REGBYTES(sp) // Recover ft6
flw f7, 38*REGBYTES(sp) // Recover ft7
flw f10,41*REGBYTES(sp) // Recover fa0
flw f11,42*REGBYTES(sp) // Recover fa1
flw f12,43*REGBYTES(sp) // Recover fa2
flw f13,44*REGBYTES(sp) // Recover fa3
flw f14,45*REGBYTES(sp) // Recover fa4
flw f15,46*REGBYTES(sp) // Recover fa5
flw f16,47*REGBYTES(sp) // Recover fa6
flw f17,48*REGBYTES(sp) // Recover fa7
flw f28,59*REGBYTES(sp) // Recover ft8
flw f29,60*REGBYTES(sp) // Recover ft9
flw f30,61*REGBYTES(sp) // Recover ft10
flw f31,62*REGBYTES(sp) // Recover ft11
lw t0, 63*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#elif defined(__riscv_float_abi_double)
fld f0, 31*REGBYTES(sp) // Recover ft0
fld f1, 32*REGBYTES(sp) // Recover ft1
fld f2, 33*REGBYTES(sp) // Recover ft2
fld f3, 34*REGBYTES(sp) // Recover ft3
fld f4, 35*REGBYTES(sp) // Recover ft4
fld f5, 36*REGBYTES(sp) // Recover ft5
fld f6, 37*REGBYTES(sp) // Recover ft6
fld f7, 38*REGBYTES(sp) // Recover ft7
fld f10,41*REGBYTES(sp) // Recover fa0
fld f11,42*REGBYTES(sp) // Recover fa1
fld f12,43*REGBYTES(sp) // Recover fa2
fld f13,44*REGBYTES(sp) // Recover fa3
fld f14,45*REGBYTES(sp) // Recover fa4
fld f15,46*REGBYTES(sp) // Recover fa5
fld f16,47*REGBYTES(sp) // Recover fa6
fld f17,48*REGBYTES(sp) // Recover fa7
fld f28,59*REGBYTES(sp) // Recover ft8
fld f29,60*REGBYTES(sp) // Recover ft9
fld f30,61*REGBYTES(sp) // Recover ft10
fld f31,62*REGBYTES(sp) // Recover ft11
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#endif
/* Recover standard registers. */
/* Restore registers,
Skip global pointer because that does not change.
Also skip the saved registers since they have been restored by any function we called,
except s0 since we use it ourselves. */
LOAD t0, 30*REGBYTES(sp) // Recover mepc
csrw mepc, t0 // Setup mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA
LOAD x5, 19*REGBYTES(sp) // Recover t0
LOAD x6, 18*REGBYTES(sp) // Recover t1
LOAD x7, 17*REGBYTES(sp) // Recover t2
LOAD x8, 12*REGBYTES(sp) // Recover s0
LOAD x10, 27*REGBYTES(sp) // Recover a0
LOAD x11, 26*REGBYTES(sp) // Recover a1
LOAD x12, 25*REGBYTES(sp) // Recover a2
LOAD x13, 24*REGBYTES(sp) // Recover a3
LOAD x14, 23*REGBYTES(sp) // Recover a4
LOAD x15, 22*REGBYTES(sp) // Recover a5
LOAD x16, 21*REGBYTES(sp) // Recover a6
LOAD x17, 20*REGBYTES(sp) // Recover a7
LOAD x28, 16*REGBYTES(sp) // Recover t3
LOAD x29, 15*REGBYTES(sp) // Recover t4
LOAD x30, 14*REGBYTES(sp) // Recover t5
LOAD x31, 13*REGBYTES(sp) // Recover t6
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
#else
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
#endif
mret // Return to point of interrupt
/* } */
_tx_thread_not_nested_restore:
/* Determine if a thread was interrupted and no preemption is required. */
/* else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)
|| (_tx_thread_preempt_disable))
{ */
LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer
beqz t1, _tx_thread_idle_system_restore // If NULL, idle system restore
LOAD t2, _tx_thread_preempt_disable // Pickup preempt disable flag
bgtz t2, _tx_thread_no_preempt_restore // If set, restore interrupted thread
LOAD t2, _tx_thread_execute_ptr // Pickup thread execute pointer
bne t1, t2, _tx_thread_preempt_restore // If higher-priority thread is ready, preempt
_tx_thread_no_preempt_restore:
/* Restore interrupted thread or ISR. */
/* Pickup the saved stack pointer. */
/* SP = _tx_thread_current_ptr -> tx_thread_stack_ptr; */
LOAD sp, 2*REGBYTES(t1) // Switch back to thread's stack
/* Recover floating point registers. */
#if defined(__riscv_float_abi_single)
flw f0, 31*REGBYTES(sp) // Recover ft0
flw f1, 32*REGBYTES(sp) // Recover ft1
flw f2, 33*REGBYTES(sp) // Recover ft2
flw f3, 34*REGBYTES(sp) // Recover ft3
flw f4, 35*REGBYTES(sp) // Recover ft4
flw f5, 36*REGBYTES(sp) // Recover ft5
flw f6, 37*REGBYTES(sp) // Recover ft6
flw f7, 38*REGBYTES(sp) // Recover ft7
flw f10,41*REGBYTES(sp) // Recover fa0
flw f11,42*REGBYTES(sp) // Recover fa1
flw f12,43*REGBYTES(sp) // Recover fa2
flw f13,44*REGBYTES(sp) // Recover fa3
flw f14,45*REGBYTES(sp) // Recover fa4
flw f15,46*REGBYTES(sp) // Recover fa5
flw f16,47*REGBYTES(sp) // Recover fa6
flw f17,48*REGBYTES(sp) // Recover fa7
flw f28,59*REGBYTES(sp) // Recover ft8
flw f29,60*REGBYTES(sp) // Recover ft9
flw f30,61*REGBYTES(sp) // Recover ft10
flw f31,62*REGBYTES(sp) // Recover ft11
lw t0, 63*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#elif defined(__riscv_float_abi_double)
fld f0, 31*REGBYTES(sp) // Recover ft0
fld f1, 32*REGBYTES(sp) // Recover ft1
fld f2, 33*REGBYTES(sp) // Recover ft2
fld f3, 34*REGBYTES(sp) // Recover ft3
fld f4, 35*REGBYTES(sp) // Recover ft4
fld f5, 36*REGBYTES(sp) // Recover ft5
fld f6, 37*REGBYTES(sp) // Recover ft6
fld f7, 38*REGBYTES(sp) // Recover ft7
fld f10,41*REGBYTES(sp) // Recover fa0
fld f11,42*REGBYTES(sp) // Recover fa1
fld f12,43*REGBYTES(sp) // Recover fa2
fld f13,44*REGBYTES(sp) // Recover fa3
fld f14,45*REGBYTES(sp) // Recover fa4
fld f15,46*REGBYTES(sp) // Recover fa5
fld f16,47*REGBYTES(sp) // Recover fa6
fld f17,48*REGBYTES(sp) // Recover fa7
fld f28,59*REGBYTES(sp) // Recover ft8
fld f29,60*REGBYTES(sp) // Recover ft9
fld f30,61*REGBYTES(sp) // Recover ft10
fld f31,62*REGBYTES(sp) // Recover ft11
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#endif
/* Recover the saved context and return to the point of interrupt. */
/* Recover standard registers. */
/* Restore registers,
Skip global pointer because that does not change */
LOAD t0, 30*REGBYTES(sp) // Recover mepc
csrw mepc, t0 // Setup mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA
LOAD x5, 19*REGBYTES(sp) // Recover t0
LOAD x6, 18*REGBYTES(sp) // Recover t1
LOAD x7, 17*REGBYTES(sp) // Recover t2
LOAD x8, 12*REGBYTES(sp) // Recover s0
LOAD x10, 27*REGBYTES(sp) // Recover a0
LOAD x11, 26*REGBYTES(sp) // Recover a1
LOAD x12, 25*REGBYTES(sp) // Recover a2
LOAD x13, 24*REGBYTES(sp) // Recover a3
LOAD x14, 23*REGBYTES(sp) // Recover a4
LOAD x15, 22*REGBYTES(sp) // Recover a5
LOAD x16, 21*REGBYTES(sp) // Recover a6
LOAD x17, 20*REGBYTES(sp) // Recover a7
LOAD x28, 16*REGBYTES(sp) // Recover t3
LOAD x29, 15*REGBYTES(sp) // Recover t4
LOAD x30, 14*REGBYTES(sp) // Recover t5
LOAD x31, 13*REGBYTES(sp) // Recover t6
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
#else
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point enabled
#endif
mret // Return to point of interrupt
/* }
else
{ */
_tx_thread_preempt_restore:
/* Instead of directly activating the thread again, ensure we save the
entire stack frame by saving the remaining registers. */
LOAD t0, 2*REGBYTES(t1) // Pickup thread's stack pointer
ori t3, x0, 1 // Build interrupt stack type
STORE t3, 0(t0) // Store stack type
/* Store floating point preserved registers. */
#ifdef __riscv_float_abi_single
fsw f8, 39*REGBYTES(t0) // Store fs0
fsw f9, 40*REGBYTES(t0) // Store fs1
fsw f18, 49*REGBYTES(t0) // Store fs2
fsw f19, 50*REGBYTES(t0) // Store fs3
fsw f20, 51*REGBYTES(t0) // Store fs4
fsw f21, 52*REGBYTES(t0) // Store fs5
fsw f22, 53*REGBYTES(t0) // Store fs6
fsw f23, 54*REGBYTES(t0) // Store fs7
fsw f24, 55*REGBYTES(t0) // Store fs8
fsw f25, 56*REGBYTES(t0) // Store fs9
fsw f26, 57*REGBYTES(t0) // Store fs10
fsw f27, 58*REGBYTES(t0) // Store fs11
#elif defined(__riscv_float_abi_double)
fsd f8, 39*REGBYTES(t0) // Store fs0
fsd f9, 40*REGBYTES(t0) // Store fs1
fsd f18, 49*REGBYTES(t0) // Store fs2
fsd f19, 50*REGBYTES(t0) // Store fs3
fsd f20, 51*REGBYTES(t0) // Store fs4
fsd f21, 52*REGBYTES(t0) // Store fs5
fsd f22, 53*REGBYTES(t0) // Store fs6
fsd f23, 54*REGBYTES(t0) // Store fs7
fsd f24, 55*REGBYTES(t0) // Store fs8
fsd f25, 56*REGBYTES(t0) // Store fs9
fsd f26, 57*REGBYTES(t0) // Store fs10
fsd f27, 58*REGBYTES(t0) // Store fs11
#endif
/* Store standard preserved registers. */
STORE x9, 11*REGBYTES(t0) // Store s1
STORE x18, 10*REGBYTES(t0) // Store s2
STORE x19, 9*REGBYTES(t0) // Store s3
STORE x20, 8*REGBYTES(t0) // Store s4
STORE x21, 7*REGBYTES(t0) // Store s5
STORE x22, 6*REGBYTES(t0) // Store s6
STORE x23, 5*REGBYTES(t0) // Store s7
STORE x24, 4*REGBYTES(t0) // Store s8
STORE x25, 3*REGBYTES(t0) // Store s9
STORE x26, 2*REGBYTES(t0) // Store s10
STORE x27, 1*REGBYTES(t0) // Store s11
// Note: s0 is already stored!
/* Save the remaining time-slice and disable it. */
/* if (_tx_timer_time_slice)
{ */
la t0, _tx_timer_time_slice // Pickup time slice variable address
lw t2, 0(t0) // Pickup time slice
beqz t2, _tx_thread_dont_save_ts // If 0, skip time slice processing
/* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice
_tx_timer_time_slice = 0; */
sw t2, TX_THREAD_TIME_SLICE_OFFSET(t1) // Save current time slice
sw x0, 0(t0) // Clear global time slice
/* } */
_tx_thread_dont_save_ts:
/* Clear the current task pointer. */
/* _tx_thread_current_ptr = TX_NULL; */
/* Return to the scheduler. */
/* _tx_thread_schedule(); */
STORE x0, _tx_thread_current_ptr, t0 // Clear current thread pointer*/
/* } */
_tx_thread_idle_system_restore:
/* Just return back to the scheduler! */
j _tx_thread_schedule // Return to scheduler
/* } */

View File

@@ -0,0 +1,283 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_save RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function saves the context of an executing thread in the */
/* beginning of interrupt processing. The function also ensures that */
/* the system stack is used upon return to the calling ISR. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* ISRs */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_thread_context_save(VOID)
{ */
.global _tx_thread_context_save
_tx_thread_context_save:
/* Upon entry to this routine, it is assumed that interrupts are locked
out and the interrupt stack fame has been allocated and x1 (ra) has
been saved on the stack. */
STORE t0, 19*REGBYTES(sp) // First store t0 and t1
STORE t1, 18*REGBYTES(sp)
la t0, _tx_thread_system_state // Pickup address of system state
lw t1, 0(t0) // Pickup system state
/* Check for a nested interrupt condition. */
/* if (_tx_thread_system_state++)
{ */
beqz t1, _tx_thread_not_nested_save // If 0, first interrupt condition
addi t1, t1, 1 // Increment the interrupt counter
sw t1, 0(t0) // Store the interrupt counter
/* Nested interrupt condition.
Save the reset of the scratch registers on the stack and return to the
calling ISR. */
STORE x7, 17*REGBYTES(sp) // Store t2
STORE x8, 12*REGBYTES(sp) // Store s0
STORE x10, 27*REGBYTES(sp) // Store a0
STORE x11, 26*REGBYTES(sp) // Store a1
STORE x12, 25*REGBYTES(sp) // Store a2
STORE x13, 24*REGBYTES(sp) // Store a3
STORE x14, 23*REGBYTES(sp) // Store a4
STORE x15, 22*REGBYTES(sp) // Store a5
STORE x16, 21*REGBYTES(sp) // Store a6
STORE x17, 20*REGBYTES(sp) // Store a7
STORE x28, 16*REGBYTES(sp) // Store t3
STORE x29, 15*REGBYTES(sp) // Store t4
STORE x30, 14*REGBYTES(sp) // Store t5
STORE x31, 13*REGBYTES(sp) // Store t6
csrr t0, mepc // Load exception program counter
STORE t0, 30*REGBYTES(sp) // Save it on the stack
/* Save floating point scratch registers. */
#if defined(__riscv_float_abi_single)
fsw f0, 31*REGBYTES(sp) // Store ft0
fsw f1, 32*REGBYTES(sp) // Store ft1
fsw f2, 33*REGBYTES(sp) // Store ft2
fsw f3, 34*REGBYTES(sp) // Store ft3
fsw f4, 35*REGBYTES(sp) // Store ft4
fsw f5, 36*REGBYTES(sp) // Store ft5
fsw f6, 37*REGBYTES(sp) // Store ft6
fsw f7, 38*REGBYTES(sp) // Store ft7
fsw f10,41*REGBYTES(sp) // Store fa0
fsw f11,42*REGBYTES(sp) // Store fa1
fsw f12,43*REGBYTES(sp) // Store fa2
fsw f13,44*REGBYTES(sp) // Store fa3
fsw f14,45*REGBYTES(sp) // Store fa4
fsw f15,46*REGBYTES(sp) // Store fa5
fsw f16,47*REGBYTES(sp) // Store fa6
fsw f17,48*REGBYTES(sp) // Store fa7
fsw f28,59*REGBYTES(sp) // Store ft8
fsw f29,60*REGBYTES(sp) // Store ft9
fsw f30,61*REGBYTES(sp) // Store ft10
fsw f31,62*REGBYTES(sp) // Store ft11
csrr t0, fcsr
STORE t0, 63*REGBYTES(sp) // Store fcsr
#elif defined(__riscv_float_abi_double)
fsd f0, 31*REGBYTES(sp) // Store ft0
fsd f1, 32*REGBYTES(sp) // Store ft1
fsd f2, 33*REGBYTES(sp) // Store ft2
fsd f3, 34*REGBYTES(sp) // Store ft3
fsd f4, 35*REGBYTES(sp) // Store ft4
fsd f5, 36*REGBYTES(sp) // Store ft5
fsd f6, 37*REGBYTES(sp) // Store ft6
fsd f7, 38*REGBYTES(sp) // Store ft7
fsd f10,41*REGBYTES(sp) // Store fa0
fsd f11,42*REGBYTES(sp) // Store fa1
fsd f12,43*REGBYTES(sp) // Store fa2
fsd f13,44*REGBYTES(sp) // Store fa3
fsd f14,45*REGBYTES(sp) // Store fa4
fsd f15,46*REGBYTES(sp) // Store fa5
fsd f16,47*REGBYTES(sp) // Store fa6
fsd f17,48*REGBYTES(sp) // Store fa7
fsd f28,59*REGBYTES(sp) // Store ft8
fsd f29,60*REGBYTES(sp) // Store ft9
fsd f30,61*REGBYTES(sp) // Store ft10
fsd f31,62*REGBYTES(sp) // Store ft11
csrr t0, fcsr
STORE t0, 63*REGBYTES(sp) // Store fcsr
#endif
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
call _tx_execution_isr_enter // Call the ISR execution enter function
#endif
ret // Return to calling ISR
_tx_thread_not_nested_save:
/* } */
/* Otherwise, not nested, check to see if a thread was running. */
/* else if (_tx_thread_current_ptr)
{ */
addi t1, t1, 1 // Increment the interrupt counter
sw t1, 0(t0) // Store the interrupt counter
/* Not nested: Find the user thread that was running and load our SP */
LOAD t0, _tx_thread_current_ptr // Pickup current thread pointer
beqz t0, _tx_thread_idle_system_save // If NULL, idle system was interrupted
/* Save the standard scratch registers. */
STORE x7, 17*REGBYTES(sp) // Store t2
STORE x8, 12*REGBYTES(sp) // Store s0
STORE x10, 27*REGBYTES(sp) // Store a0
STORE x11, 26*REGBYTES(sp) // Store a1
STORE x12, 25*REGBYTES(sp) // Store a2
STORE x13, 24*REGBYTES(sp) // Store a3
STORE x14, 23*REGBYTES(sp) // Store a4
STORE x15, 22*REGBYTES(sp) // Store a5
STORE x16, 21*REGBYTES(sp) // Store a6
STORE x17, 20*REGBYTES(sp) // Store a7
STORE x28, 16*REGBYTES(sp) // Store t3
STORE x29, 15*REGBYTES(sp) // Store t4
STORE x30, 14*REGBYTES(sp) // Store t5
STORE x31, 13*REGBYTES(sp) // Store t6
csrr t0, mepc // Load exception program counter
STORE t0, 30*REGBYTES(sp) // Save it on the stack
/* Save floating point scratch registers. */
#if defined(__riscv_float_abi_single)
fsw f0, 31*REGBYTES(sp) // Store ft0
fsw f1, 32*REGBYTES(sp) // Store ft1
fsw f2, 33*REGBYTES(sp) // Store ft2
fsw f3, 34*REGBYTES(sp) // Store ft3
fsw f4, 35*REGBYTES(sp) // Store ft4
fsw f5, 36*REGBYTES(sp) // Store ft5
fsw f6, 37*REGBYTES(sp) // Store ft6
fsw f7, 38*REGBYTES(sp) // Store ft7
fsw f10,41*REGBYTES(sp) // Store fa0
fsw f11,42*REGBYTES(sp) // Store fa1
fsw f12,43*REGBYTES(sp) // Store fa2
fsw f13,44*REGBYTES(sp) // Store fa3
fsw f14,45*REGBYTES(sp) // Store fa4
fsw f15,46*REGBYTES(sp) // Store fa5
fsw f16,47*REGBYTES(sp) // Store fa6
fsw f17,48*REGBYTES(sp) // Store fa7
fsw f28,59*REGBYTES(sp) // Store ft8
fsw f29,60*REGBYTES(sp) // Store ft9
fsw f30,61*REGBYTES(sp) // Store ft10
fsw f31,62*REGBYTES(sp) // Store ft11
csrr t0, fcsr
STORE t0, 63*REGBYTES(sp) // Store fcsr
#elif defined(__riscv_float_abi_double)
fsd f0, 31*REGBYTES(sp) // Store ft0
fsd f1, 32*REGBYTES(sp) // Store ft1
fsd f2, 33*REGBYTES(sp) // Store ft2
fsd f3, 34*REGBYTES(sp) // Store ft3
fsd f4, 35*REGBYTES(sp) // Store ft4
fsd f5, 36*REGBYTES(sp) // Store ft5
fsd f6, 37*REGBYTES(sp) // Store ft6
fsd f7, 38*REGBYTES(sp) // Store ft7
fsd f10,41*REGBYTES(sp) // Store fa0
fsd f11,42*REGBYTES(sp) // Store fa1
fsd f12,43*REGBYTES(sp) // Store fa2
fsd f13,44*REGBYTES(sp) // Store fa3
fsd f14,45*REGBYTES(sp) // Store fa4
fsd f15,46*REGBYTES(sp) // Store fa5
fsd f16,47*REGBYTES(sp) // Store fa6
fsd f17,48*REGBYTES(sp) // Store fa7
fsd f28,59*REGBYTES(sp) // Store ft8
fsd f29,60*REGBYTES(sp) // Store ft9
fsd f30,61*REGBYTES(sp) // Store ft10
fsd f31,62*REGBYTES(sp) // Store ft11
csrr t0, fcsr
STORE t0, 63*REGBYTES(sp) // Store fcsr
#endif
/* Save the current stack pointer in the thread's control block. */
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; */
/* Switch to the system stack. */
/* sp = _tx_thread_system_stack_ptr; */
LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer
STORE sp, 2*REGBYTES(t1) // Save stack pointer
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
/* _tx_execution_isr_enter is called with thread stack pointer */
call _tx_execution_isr_enter // Call the ISR execution enter function
#endif
LOAD sp, _tx_thread_system_stack_ptr // Switch to system stack
ret // Return to calling ISR
/* }
else
{ */
_tx_thread_idle_system_save:
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
call _tx_execution_isr_enter // Call the ISR execution enter function
#endif
/* Interrupt occurred in the scheduling loop. */
/* }
} */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
#else
addi sp, sp, 32*REGBYTES // Recover the reserved stack space
#endif
ret // Return to calling ISR

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
RETURN_MASK = 0x000000000000000F
SET_SR_MASK = 0xFFFFFFFFFFFFFFF0
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_interrupt_control RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for changing the interrupt lockout */
/* posture of the system. */
/* */
/* INPUT */
/* */
/* new_posture New interrupt lockout posture */
/* */
/* OUTPUT */
/* */
/* old_posture Old interrupt lockout posture */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* UINT _tx_thread_interrupt_control(UINT new_posture)
{ */
.global _tx_thread_interrupt_control
_tx_thread_interrupt_control:
/* Pickup current interrupt lockout posture. */
csrr t0, mstatus
mv t1, t0 // Save original mstatus for return
/* Apply the new interrupt posture. */
li t2, SET_SR_MASK // Build set SR mask
and t0, t0, t2 // Isolate interrupt lockout bits
or t0, t0, a0 // Put new lockout bits in
csrw mstatus, t0
andi a0, t1, RETURN_MASK // Return original mstatus.
ret
/* } */

View File

@@ -0,0 +1,305 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* _tx_thread_context_restore Restore thread's context */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_thread_schedule(VOID)
{ */
.global _tx_thread_schedule
_tx_thread_schedule:
/* Enable interrupts. */
csrsi mstatus, 0x08 // Enable interrupts
/* Wait for a thread to execute. */
/* do
{ */
la t0, _tx_thread_execute_ptr // Pickup address of execute ptr
_tx_thread_schedule_loop:
LOAD t1, 0(t0) // Pickup next thread to execute
beqz t1, _tx_thread_schedule_loop // If NULL, wait for thread to execute
/* }
while(_tx_thread_execute_ptr == TX_NULL); */
/* Yes! We have a thread to execute. Lockout interrupts and
transfer control to it. */
csrci mstatus, 0x08 // Lockout interrupts
/* Setup the current thread pointer. */
/* _tx_thread_current_ptr = _tx_thread_execute_ptr; */
la t0, _tx_thread_current_ptr // Pickup current thread pointer address
STORE t1, 0(t0) // Set current thread pointer
/* Increment the run count for this thread. */
/* _tx_thread_current_ptr -> tx_thread_run_count++; */
LOAD t2, 1*REGBYTES(t1) // Pickup run count
LOAD t3, 6*REGBYTES(t1) // Pickup time slice value
addi t2, t2, 1 // Increment run count
STORE t2, 1*REGBYTES(t1) // Store new run count
/* Setup time-slice, if present. */
/* _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; */
la t2, _tx_timer_time_slice // Pickup time-slice variable address
/* Switch to the thread's stack. */
/* SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; */
LOAD sp, 2*REGBYTES(t1) // Switch to thread's stack
STORE t3, 0(t2) // Store new time-slice*/
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
call _tx_execution_thread_enter // Call the thread execution enter function
#endif
/* Determine if an interrupt frame or a synchronous task suspension frame
is present. */
LOAD t2, 0(sp) // Pickup stack type
beqz t2, _tx_thread_synch_return // If 0, solicited thread return
/* Determine if floating point registers need to be recovered. */
#if defined(__riscv_float_abi_single)
flw f0, 31*REGBYTES(sp) // Recover ft0
flw f1, 32*REGBYTES(sp) // Recover ft1
flw f2, 33*REGBYTES(sp) // Recover ft2
flw f3, 34*REGBYTES(sp) // Recover ft3
flw f4, 35*REGBYTES(sp) // Recover ft4
flw f5, 36*REGBYTES(sp) // Recover ft5
flw f6, 37*REGBYTES(sp) // Recover ft6
flw f7, 38*REGBYTES(sp) // Recover ft7
flw f8, 39*REGBYTES(sp) // Recover fs0
flw f9, 40*REGBYTES(sp) // Recover fs1
flw f10,41*REGBYTES(sp) // Recover fa0
flw f11,42*REGBYTES(sp) // Recover fa1
flw f12,43*REGBYTES(sp) // Recover fa2
flw f13,44*REGBYTES(sp) // Recover fa3
flw f14,45*REGBYTES(sp) // Recover fa4
flw f15,46*REGBYTES(sp) // Recover fa5
flw f16,47*REGBYTES(sp) // Recover fa6
flw f17,48*REGBYTES(sp) // Recover fa7
flw f18,49*REGBYTES(sp) // Recover fs2
flw f19,50*REGBYTES(sp) // Recover fs3
flw f20,51*REGBYTES(sp) // Recover fs4
flw f21,52*REGBYTES(sp) // Recover fs5
flw f22,53*REGBYTES(sp) // Recover fs6
flw f23,54*REGBYTES(sp) // Recover fs7
flw f24,55*REGBYTES(sp) // Recover fs8
flw f25,56*REGBYTES(sp) // Recover fs9
flw f26,57*REGBYTES(sp) // Recover fs10
flw f27,58*REGBYTES(sp) // Recover fs11
flw f28,59*REGBYTES(sp) // Recover ft8
flw f29,60*REGBYTES(sp) // Recover ft9
flw f30,61*REGBYTES(sp) // Recover ft10
flw f31,62*REGBYTES(sp) // Recover ft11
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#elif defined(__riscv_float_abi_double)
fld f0, 31*REGBYTES(sp) // Recover ft0
fld f1, 32*REGBYTES(sp) // Recover ft1
fld f2, 33*REGBYTES(sp) // Recover ft2
fld f3, 34*REGBYTES(sp) // Recover ft3
fld f4, 35*REGBYTES(sp) // Recover ft4
fld f5, 36*REGBYTES(sp) // Recover ft5
fld f6, 37*REGBYTES(sp) // Recover ft6
fld f7, 38*REGBYTES(sp) // Recover ft7
fld f8, 39*REGBYTES(sp) // Recover fs0
fld f9, 40*REGBYTES(sp) // Recover fs1
fld f10,41*REGBYTES(sp) // Recover fa0
fld f11,42*REGBYTES(sp) // Recover fa1
fld f12,43*REGBYTES(sp) // Recover fa2
fld f13,44*REGBYTES(sp) // Recover fa3
fld f14,45*REGBYTES(sp) // Recover fa4
fld f15,46*REGBYTES(sp) // Recover fa5
fld f16,47*REGBYTES(sp) // Recover fa6
fld f17,48*REGBYTES(sp) // Recover fa7
fld f18,49*REGBYTES(sp) // Recover fs2
fld f19,50*REGBYTES(sp) // Recover fs3
fld f20,51*REGBYTES(sp) // Recover fs4
fld f21,52*REGBYTES(sp) // Recover fs5
fld f22,53*REGBYTES(sp) // Recover fs6
fld f23,54*REGBYTES(sp) // Recover fs7
fld f24,55*REGBYTES(sp) // Recover fs8
fld f25,56*REGBYTES(sp) // Recover fs9
fld f26,57*REGBYTES(sp) // Recover fs10
fld f27,58*REGBYTES(sp) // Recover fs11
fld f28,59*REGBYTES(sp) // Recover ft8
fld f29,60*REGBYTES(sp) // Recover ft9
fld f30,61*REGBYTES(sp) // Recover ft10
fld f31,62*REGBYTES(sp) // Recover ft11
LOAD t0, 63*REGBYTES(sp) // Recover fcsr
#endif
/* Recover standard registers. */
LOAD t0, 30*REGBYTES(sp) // Recover mepc
csrw mepc, t0 // Store mepc
li t0, 0x1880 // Prepare MPIP
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
li t1, 1<<13
or t0, t1, t0
#endif
csrw mstatus, t0 // Enable MPIP
LOAD x1, 28*REGBYTES(sp) // Recover RA
LOAD x5, 19*REGBYTES(sp) // Recover t0
LOAD x6, 18*REGBYTES(sp) // Recover t1
LOAD x7, 17*REGBYTES(sp) // Recover t2
LOAD x8, 12*REGBYTES(sp) // Recover s0
LOAD x9, 11*REGBYTES(sp) // Recover s1
LOAD x10, 27*REGBYTES(sp) // Recover a0
LOAD x11, 26*REGBYTES(sp) // Recover a1
LOAD x12, 25*REGBYTES(sp) // Recover a2
LOAD x13, 24*REGBYTES(sp) // Recover a3
LOAD x14, 23*REGBYTES(sp) // Recover a4
LOAD x15, 22*REGBYTES(sp) // Recover a5
LOAD x16, 21*REGBYTES(sp) // Recover a6
LOAD x17, 20*REGBYTES(sp) // Recover a7
LOAD x18, 10*REGBYTES(sp) // Recover s2
LOAD x19, 9*REGBYTES(sp) // Recover s3
LOAD x20, 8*REGBYTES(sp) // Recover s4
LOAD x21, 7*REGBYTES(sp) // Recover s5
LOAD x22, 6*REGBYTES(sp) // Recover s6
LOAD x23, 5*REGBYTES(sp) // Recover s7
LOAD x24, 4*REGBYTES(sp) // Recover s8
LOAD x25, 3*REGBYTES(sp) // Recover s9
LOAD x26, 2*REGBYTES(sp) // Recover s10
LOAD x27, 1*REGBYTES(sp) // Recover s11
LOAD x28, 16*REGBYTES(sp) // Recover t3
LOAD x29, 15*REGBYTES(sp) // Recover t4
LOAD x30, 14*REGBYTES(sp) // Recover t5
LOAD x31, 13*REGBYTES(sp) // Recover t6
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point registers
#else
addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point registers
#endif
mret // Return to point of interrupt
_tx_thread_synch_return:
#if defined(__riscv_float_abi_single)
flw f8, 15*REGBYTES(sp) // Recover fs0
flw f9, 16*REGBYTES(sp) // Recover fs1
flw f18,17*REGBYTES(sp) // Recover fs2
flw f19,18*REGBYTES(sp) // Recover fs3
flw f20,19*REGBYTES(sp) // Recover fs4
flw f21,20*REGBYTES(sp) // Recover fs5
flw f22,21*REGBYTES(sp) // Recover fs6
flw f23,22*REGBYTES(sp) // Recover fs7
flw f24,23*REGBYTES(sp) // Recover fs8
flw f25,24*REGBYTES(sp) // Recover fs9
flw f26,25*REGBYTES(sp) // Recover fs10
flw f27,26*REGBYTES(sp) // Recover fs11
LOAD t0, 27*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#elif defined(__riscv_float_abi_double)
fld f8, 15*REGBYTES(sp) // Recover fs0
fld f9, 16*REGBYTES(sp) // Recover fs1
fld f18,17*REGBYTES(sp) // Recover fs2
fld f19,18*REGBYTES(sp) // Recover fs3
fld f20,19*REGBYTES(sp) // Recover fs4
fld f21,20*REGBYTES(sp) // Recover fs5
fld f22,21*REGBYTES(sp) // Recover fs6
fld f23,22*REGBYTES(sp) // Recover fs7
fld f24,23*REGBYTES(sp) // Recover fs8
fld f25,24*REGBYTES(sp) // Recover fs9
fld f26,25*REGBYTES(sp) // Recover fs10
fld f27,26*REGBYTES(sp) // Recover fs11
LOAD t0, 27*REGBYTES(sp) // Recover fcsr
csrw fcsr, t0 //
#endif
/* Recover standard preserved registers. */
/* Recover standard registers. */
LOAD x1, 13*REGBYTES(sp) // Recover RA
LOAD x8, 12*REGBYTES(sp) // Recover s0
LOAD x9, 11*REGBYTES(sp) // Recover s1
LOAD x18, 10*REGBYTES(sp) // Recover s2
LOAD x19, 9*REGBYTES(sp) // Recover s3
LOAD x20, 8*REGBYTES(sp) // Recover s4
LOAD x21, 7*REGBYTES(sp) // Recover s5
LOAD x22, 6*REGBYTES(sp) // Recover s6
LOAD x23, 5*REGBYTES(sp) // Recover s7
LOAD x24, 4*REGBYTES(sp) // Recover s8
LOAD x25, 3*REGBYTES(sp) // Recover s9
LOAD x26, 2*REGBYTES(sp) // Recover s10
LOAD x27, 1*REGBYTES(sp) // Recover s11
LOAD t0, 14*REGBYTES(sp) // Recover mstatus
csrw mstatus, t0 // Store mstatus, enables interrupt
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, 29*REGBYTES // Recover stack frame
#else
addi sp, sp, 16*REGBYTES // Recover stack frame
#endif
ret // Return to thread
/* } */

View File

@@ -0,0 +1,227 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_stack_build RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread control blk */
/* function_ptr Pointer to return function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{ */
.global _tx_thread_stack_build
_tx_thread_stack_build:
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the RISC-V should look like the following after it is built:
Reg Index
Stack Top: 1 0 Interrupt stack frame type
x27 1 Initial s11
x26 2 Initial s10
x25 3 Initial s9
x24 4 Initial s8
x23 5 Initial s7
x22 6 Initial s6
x21 7 Initial s5
x20 8 Initial s4
x19 9 Initial s3
x18 10 Initial s2
x9 11 Initial s1
x8 12 Initial s0
x31 13 Initial t6
x30 14 Initial t5
x29 15 Initial t4
x28 16 Initial t3
x7 17 Initial t2
x6 18 Initial t1
x5 19 Initial t0
x17 20 Initial a7
x16 21 Initial a6
x15 22 Initial a5
x14 23 Initial a4
x13 24 Initial a3
x12 25 Initial a2
x11 26 Initial a1
x10 27 Initial a0
x1 28 Initial ra
-- 29 reserved
mepc 30 Initial mepc
If floating point support:
f0 31 Inital ft0
f1 32 Inital ft1
f2 33 Inital ft2
f3 34 Inital ft3
f4 35 Inital ft4
f5 36 Inital ft5
f6 37 Inital ft6
f7 38 Inital ft7
f8 39 Inital fs0
f9 40 Inital fs1
f10 41 Inital fa0
f11 42 Inital fa1
f12 43 Inital fa2
f13 44 Inital fa3
f14 45 Inital fa4
f15 46 Inital fa5
f16 47 Inital fa6
f17 48 Inital fa7
f18 49 Inital fs2
f19 50 Inital fs3
f20 51 Inital fs4
f21 52 Inital fs5
f22 53 Inital fs6
f23 54 Inital fs7
f24 55 Inital fs8
f25 56 Inital fs9
f26 57 Inital fs10
f27 58 Inital fs11
f28 59 Inital ft8
f29 60 Inital ft9
f30 61 Inital ft10
f31 62 Inital ft11
fscr 63 Inital fscr
Stack Bottom: (higher memory address) */
LOAD t0, TX_THREAD_STACK_END_OFFSET(a0) // Pickup end of stack area
andi t0, t0, -4*REGBYTES // Ensure alignment (16-byte for RV32 & 32-byte for RV64)
/* Actually build the stack frame. */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi t0, t0, -65*REGBYTES
#else
addi t0, t0, -32*REGBYTES // Allocate space for the stack frame
#endif
li t1, 1 // Build stack type
STORE t1, 0*REGBYTES(t0) // Place stack type on the top
STORE x0, 1*REGBYTES(t0) // Initial s11
STORE x0, 2*REGBYTES(t0) // Initial s10
STORE x0, 3*REGBYTES(t0) // Initial s9
STORE x0, 4*REGBYTES(t0) // Initial s8
STORE x0, 5*REGBYTES(t0) // Initial s7
STORE x0, 6*REGBYTES(t0) // Initial s6
STORE x0, 7*REGBYTES(t0) // Initial s5
STORE x0, 8*REGBYTES(t0) // Initial s4
STORE x0, 9*REGBYTES(t0) // Initial s3
STORE x0, 10*REGBYTES(t0) // Initial s2
STORE x0, 11*REGBYTES(t0) // Initial s1
STORE x0, 12*REGBYTES(t0) // Initial s0
STORE x0, 13*REGBYTES(t0) // Initial t6
STORE x0, 14*REGBYTES(t0) // Initial t5
STORE x0, 15*REGBYTES(t0) // Initial t4
STORE x0, 16*REGBYTES(t0) // Initial t3
STORE x0, 17*REGBYTES(t0) // Initial t2
STORE x0, 18*REGBYTES(t0) // Initial t1
STORE x0, 19*REGBYTES(t0) // Initial t0
STORE x0, 20*REGBYTES(t0) // Initial a7
STORE x0, 21*REGBYTES(t0) // Initial a6
STORE x0, 22*REGBYTES(t0) // Initial a5
STORE x0, 23*REGBYTES(t0) // Initial a4
STORE x0, 24*REGBYTES(t0) // Initial a3
STORE x0, 25*REGBYTES(t0) // Initial a2
STORE x0, 26*REGBYTES(t0) // Initial a1
STORE x0, 27*REGBYTES(t0) // Initial a0
STORE x0, 28*REGBYTES(t0) // Initial ra
STORE a1, 30*REGBYTES(t0) // Initial mepc
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
STORE x0, 31*REGBYTES(t0) // Inital ft0
STORE x0, 32*REGBYTES(t0) // Inital ft1
STORE x0, 33*REGBYTES(t0) // Inital ft2
STORE x0, 34*REGBYTES(t0) // Inital ft3
STORE x0, 35*REGBYTES(t0) // Inital ft4
STORE x0, 36*REGBYTES(t0) // Inital ft5
STORE x0, 37*REGBYTES(t0) // Inital ft6
STORE x0, 38*REGBYTES(t0) // Inital ft7
STORE x0, 39*REGBYTES(t0) // Inital fs0
STORE x0, 40*REGBYTES(t0) // Inital fs1
STORE x0, 41*REGBYTES(t0) // Inital fa0
STORE x0, 42*REGBYTES(t0) // Inital fa1
STORE x0, 43*REGBYTES(t0) // Inital fa2
STORE x0, 44*REGBYTES(t0) // Inital fa3
STORE x0, 45*REGBYTES(t0) // Inital fa4
STORE x0, 46*REGBYTES(t0) // Inital fa5
STORE x0, 47*REGBYTES(t0) // Inital fa6
STORE x0, 48*REGBYTES(t0) // Inital fa7
STORE x0, 49*REGBYTES(t0) // Inital fs2
STORE x0, 50*REGBYTES(t0) // Inital fs3
STORE x0, 51*REGBYTES(t0) // Inital fs4
STORE x0, 52*REGBYTES(t0) // Inital fs5
STORE x0, 53*REGBYTES(t0) // Inital fs6
STORE x0, 54*REGBYTES(t0) // Inital fs7
STORE x0, 55*REGBYTES(t0) // Inital fs8
STORE x0, 56*REGBYTES(t0) // Inital fs9
STORE x0, 57*REGBYTES(t0) // Inital fs10
STORE x0, 58*REGBYTES(t0) // Inital fs11
STORE x0, 59*REGBYTES(t0) // Inital ft8
STORE x0, 60*REGBYTES(t0) // Inital ft9
STORE x0, 61*REGBYTES(t0) // Inital ft10
STORE x0, 62*REGBYTES(t0) // Inital ft11
csrr a1, fcsr // Read fcsr and use it for initial value for each thread
STORE a1, 63*REGBYTES(t0) // Initial fscr
STORE x0, 64*REGBYTES(t0) // Reserved word (0)
#else
STORE x0, 31*REGBYTES(t0) // Reserved word (0)
#endif
/* Setup stack pointer. */
/* thread_ptr -> tx_thread_stack_ptr = t0; */
STORE t0, 2*REGBYTES(a0) // Save stack pointer in thread's
ret // control block and return
/* } */

View File

@@ -0,0 +1,174 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* 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
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#include "tx_port.h"
.section .text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_system_return RISC-V64/GNU */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is target processor specific. It is used to transfer */
/* control from a thread back to the system. Only a minimal context */
/* is saved since the compiler assumes temp registers are going to get */
/* slicked by a function call anyway. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_schedule Thread scheduling loop */
/* */
/* CALLED BY */
/* */
/* ThreadX components */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
/* */
/**************************************************************************/
/* VOID _tx_thread_system_return(VOID)
{ */
.global _tx_thread_system_return
_tx_thread_system_return:
/* Save minimal context on the stack. */
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
addi sp, sp, -29*REGBYTES // Allocate space on the stack - with floating point enabled
#else
addi sp, sp, -16*REGBYTES // Allocate space on the stack - without floating point enabled
#endif
/* Store floating point preserved registers. */
#if defined(__riscv_float_abi_single)
fsw f8, 15*REGBYTES(sp) // Store fs0
fsw f9, 16*REGBYTES(sp) // Store fs1
fsw f18, 17*REGBYTES(sp) // Store fs2
fsw f19, 18*REGBYTES(sp) // Store fs3
fsw f20, 19*REGBYTES(sp) // Store fs4
fsw f21, 20*REGBYTES(sp) // Store fs5
fsw f22, 21*REGBYTES(sp) // Store fs6
fsw f23, 22*REGBYTES(sp) // Store fs7
fsw f24, 23*REGBYTES(sp) // Store fs8
fsw f25, 24*REGBYTES(sp) // Store fs9
fsw f26, 25*REGBYTES(sp) // Store fs10
fsw f27, 26*REGBYTES(sp) // Store fs11
csrr t0, fcsr
STORE t0, 27*REGBYTES(sp) // Store fcsr
#elif defined(__riscv_float_abi_double)
fsd f8, 15*REGBYTES(sp) // Store fs0
fsd f9, 16*REGBYTES(sp) // Store fs1
fsd f18, 17*REGBYTES(sp) // Store fs2
fsd f19, 18*REGBYTES(sp) // Store fs3
fsd f20, 19*REGBYTES(sp) // Store fs4
fsd f21, 20*REGBYTES(sp) // Store fs5
fsd f22, 21*REGBYTES(sp) // Store fs6
fsd f23, 22*REGBYTES(sp) // Store fs7
fsd f24, 23*REGBYTES(sp) // Store fs8
fsd f25, 24*REGBYTES(sp) // Store fs9
fsd f26, 25*REGBYTES(sp) // Store fs10
fsd f27, 26*REGBYTES(sp) // Store fs11
csrr t0, fcsr
STORE t0, 27*REGBYTES(sp) // Store fcsr
#endif
STORE x0, 0(sp) // Solicited stack type
STORE x1, 13*REGBYTES(sp) // Save RA
STORE x8, 12*REGBYTES(sp) // Save s0
STORE x9, 11*REGBYTES(sp) // Save s1
STORE x18, 10*REGBYTES(sp) // Save s2
STORE x19, 9*REGBYTES(sp) // Save s3
STORE x20, 8*REGBYTES(sp) // Save s4
STORE x21, 7*REGBYTES(sp) // Save s5
STORE x22, 6*REGBYTES(sp) // Save s6
STORE x23, 5*REGBYTES(sp) // Save s7
STORE x24, 4*REGBYTES(sp) // Save s8
STORE x25, 3*REGBYTES(sp) // Save s9
STORE x26, 2*REGBYTES(sp) // Save s10
STORE x27, 1*REGBYTES(sp) // Save s11
csrr t0, mstatus // Pickup mstatus
STORE t0, 14*REGBYTES(sp) // Save mstatus
/* Lockout interrupts. - will be enabled in _tx_thread_schedule */
csrci mstatus, 0xF
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
call _tx_execution_thread_exit // Call the thread execution exit function
#endif
la t0, _tx_thread_current_ptr // Pickup address of pointer
LOAD t1, 0(t0) // Pickup current thread pointer
la t2,_tx_thread_system_stack_ptr // Pickup stack pointer address
/* Save current stack and switch to system stack. */
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = SP;
SP = _tx_thread_system_stack_ptr; */
STORE sp, 2*REGBYTES(t1) // Save stack pointer
LOAD sp, 0(t2) // Switch to system stack
/* Determine if the time-slice is active. */
/* if (_tx_timer_time_slice)
{ */
la t4, _tx_timer_time_slice // Pickup time slice variable addr
lw t3, 0(t4) // Pickup time slice value
la t2, _tx_thread_schedule // Pickup address of scheduling loop
beqz t3, _tx_thread_dont_save_ts // If no time-slice, don't save it
/* Save time-slice for the thread and clear the current time-slice. */
/* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
_tx_timer_time_slice = 0; */
sw t3, TX_THREAD_TIME_SLICE_OFFSET(t1) // Save current time-slice for thread
sw x0, 0(t4) // Clear time-slice variable
/* } */
_tx_thread_dont_save_ts:
/* Clear the current thread pointer. */
/* _tx_thread_current_ptr = TX_NULL; */
STORE x0, 0(t0) // Clear current thread pointer
jr t2 // Return to thread scheduler
/* } */