Compare commits

..

3 Commits
master ... cxx

Author SHA1 Message Date
mpabi 24b76da4b0 makefile fixed, c++ stl working :) 2024-07-04 22:07:49 +00:00
mpabi 0f74c6d90f dodano extern "C" {} do stub_stdlib.c 2024-07-03 16:57:26 +00:00
mpabi 81c86f0d2d init 2024-07-03 16:14:36 +00:00
7 changed files with 699 additions and 46 deletions

View File

@ -1,11 +1,12 @@
PROJ_NAME=hello_world
DEBUG=no
BENCH=no
MULDIV=no
PROJ_NAME = hello_world
DEBUG = yes
BENCH = no
MULDIV = no
SRCS = $(wildcard src/*.c) \
$(wildcard src/*.cpp) \
$(wildcard src/*.S)
SRCS = $(wildcard src/*.c) \
$(wildcard src/*.cpp) \
$(wildcard src/*.S) \
src/stub_stdlib.c
OBJDIR = build
@ -14,41 +15,25 @@ LIBS =
LIBSINC = -L$(OBJDIR)
LDSCRIPT = ./src/linker.ld
#include ../../../resources/gcc.mk
# Set it to yes if you are using the sifive precompiled GCC pack
SIFIVE_GCC_PACK ?= yes
GCC_PACK ?= yes
ifeq ($(SIFIVE_GCC_PACK),yes)
ifeq ($(GCC_PACK),yes)
RISCV_NAME ?= riscv32-unknown-elf
RISCV_PATH ?= /home/user/riscv/opt/rv32im/
else
RISCV_NAME ?= riscv32-unknown-elf
ifeq ($(MULDIV),yes)
RISCV_PATH ?= /opt/riscv32im/
else
RISCV_PATH ?= /opt/riscv32i/
endif
endif
MABI=ilp32
MABI = ilp32
MARCH := rv32i_zicsr
ifeq ($(MULDIV),yes)
MARCH := $(MARCH)m
endif
ifeq ($(COMPRESSED),yes)
MARCH := $(MARCH)ac
endif
CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG
LDFLAGS += -march=$(MARCH) -mabi=$(MABI)
#include ../../../resources/subproject.mk
ifeq ($(DEBUG),yes)
CFLAGS += -g3 -O0
# CFLAGS += -g3 -O0
CFLAGS += -g3 -gdwarf-3 -O0 -DDEBUG
CXXFLAGS += -g3 -gdwarf-3 -O0 -DDEBUG
LDFLAGS += -g3 -gdwarf-3
endif
ifeq ($(DEBUG),no)
@ -65,30 +50,50 @@ else
RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/
endif
RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-g++
RISCV_CC = $(RISCV_PATH)/bin/$(RISCV_NAME)-gcc
CXX = $(RISCV_PATH)/bin/$(RISCV_NAME)-g++
CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing
LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage
#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug,
CFLAGS += -march=$(MARCH) \
-mabi=$(MABI) \
-DNDEBUG \
-fno-pic \
-ffreestanding \
-MD \
-fstrict-volatile-bitfields \
-fno-strict-aliasing
CXXFLAGS += -march=$(MARCH) \
-mabi=$(MABI) \
-DNDEBUG \
-fno-pic \
-ffreestanding \
-MD \
-fstrict-volatile-bitfields \
-fno-strict-aliasing \
-std=c++11
LDFLAGS += -march=$(MARCH) \
-mabi=$(MABI) \
-lc \
-lgcc \
-nostdlib \
-nostartfiles \
-mcmodel=medany \
-ffreestanding \
-Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(OBJS:..=miaou)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))
all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v
$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS)
%.hex: %.elf
$(RISCV_OBJCOPY) -O ihex $^ $@
@ -104,12 +109,11 @@ $(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
$(OBJDIR)/%.o: %.c
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(CXX) -c $(CXXFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.S
mkdir -p $(dir $@)
@ -129,6 +133,7 @@ clean:
find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm
find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm
clean-all : clean
clean-all: clean
.SECONDARY: $(OBJS)

BIN
src/latex/main.pdf Normal file

Binary file not shown.

329
src/latex/main.tex Normal file
View File

@ -0,0 +1,329 @@
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[polish]{babel}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{geometry}
\geometry{a4paper, margin=1in}
% Define custom colors for listings
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codepurple}{rgb}{0.58,0,0.82}
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
\lstdefinestyle{mystyle}{
backgroundcolor=\color{backcolour},
commentstyle=\color{red},
keywordstyle=\color{blue},
numberstyle=\tiny\color{codegray},
stringstyle=\color{codepurple},
basicstyle=\footnotesize\ttfamily,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
frame=single
}
\lstset{style=mystyle}
\begin{document}
\section*{Initialization Routine in SpinalHDL}
The initialization of the global pointer and stack pointer is not directly shown in SpinalHDL, as these are typically managed by the compiler and startup assembly code. However, SpinalHDL configures the core and its peripherals which indirectly affect these initializations.
\begin{lstlisting}[language=Scala, caption={SpinalHDL Configuration for CSR and Interrupt Setup}]
// Configuration for the CSR plugin, which includes interrupt management
val csrPluginConfig = CsrPluginConfig.small.copy(
mtvecInit = 0x00000020, // Initial value for mtvec, the trap handler base address
mieInit = 0x880, // Initial machine interrupt-enable setup
mstatusInit = 0x1808 // Machine status register initial setup
)
cpuPlugins += new CsrPlugin(csrPluginConfig)
\end{lstlisting}
\section*{Timer and External Interrupt Setup in SpinalHDL}
Configuring interrupts such as timers and UART in the Murax SoC involves setting up corresponding plugins within the VexRiscv core configuration.
\begin{lstlisting}[language=Scala, caption={Timer and UART Interrupt Setup}]
// Timer configuration to generate periodic interrupts
cpuPlugins += new TimerPlugin(
config = TimerConfig(
tickCount = 10, // Number of ticks for the timer to fire an interrupt
baseAddress = 0x10000000 // Base address for timer configuration registers
)
)
// Adding UART with interrupt capability
cpuPlugins += new UartCtrlPlugin(
uartConfig = UartCtrlMemoryMappedConfig(
txFifoDepth = 16, // Transmit FIFO depth
rxFifoDepth = 16, // Receive FIFO depth
interruptConfig = InterruptConfig(
txFull = true, // Interrupt when TX is full
rxNotEmpty = true // Interrupt when RX is not empty
)
),
baseAddress = 0x11000000
)
\end{lstlisting}
This completes the description and configuration for hardware as defined in SpinalHDL, directly related to the initialization and interrupt handling described in the assembly `boot.S` script.
\section*{SpinalHDL Configurations for Assembly Initialization}
This section provides an overview of how the Murax SoC, implemented in SpinalHDL, configures the hardware to support the software initialization routines written in assembly.
\subsection*{Processor Configuration and Interrupt Setup}
\begin{lstlisting}[language=Scala, caption={SpinalHDL Processor and Interrupt Configuration}]
// Define a VexRiscv processor with specific plugins for interrupt handling
val cpuConfig = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x80000000l, false),
new IBusSimplePlugin(
resetVector = 0x80000000l,
cmdForkOnSecondStage = true,
cmdForkPersistence = false,
prediction = STATIC,
catchAccessFault = true,
compressedGen = true
),
new DBusSimplePlugin(
catchAccessFault = true,
earlyInjection = false
),
new CsrPlugin(CsrPluginConfig.all),
new DecoderSimplePlugin(
catchIllegalInstruction = true
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = true
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false,
executeInsertion = false
),
new LightShifterPlugin,
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)
)
// Specific configuration for handling machine interrupts
cpuConfig.plugins.foreach{
case p: CsrPlugin => p.externalInterrupt := Global_ExternalInterrupt
case p: TimerPlugin => p.tick := Global_TimerTick
case _ =>
}
\end{lstlisting}
\subsection*{Memory and Peripheral Configuration}
\begin{lstlisting}[language=Scala, caption={SpinalHDL Memory and Peripheral Initialization}]
// Configuration for on-chip RAM
val onChipRamConfig = OnChipRamConfig(
ramSize = 8192, // 8 KB
ramHexFile = "path_to_hex_file.hex",
addressWidth = 32
)
// Setup the memory mapping for RAM
val ram = new Ram(
config = onChipRamConfig,
initialContent = LoadHex("path_to_hex_file.hex")
)
// Mapping RAM to the processor bus
val busConfig = new BusConfig(
master = cpu.dBus,
slaves = List(
ram -> (0x80000000l, 8192)
)
)
\end{lstlisting}
This enhanced section includes the details on how the processor configuration and memory initialization in SpinalHDL correspond to the assembly startup sequences in the `boot.S` file. This setup ensures that the hardware is appropriately configured to support the initial software routines, facilitating a seamless interaction between the processor's software and hardware components.
\section*{Introduction}
This document details the assembly and SpinalHDL configuration for the Murax SoC, providing insights into how the hardware and software are co-designed to facilitate system initialization and handling of basic functionalities like interrupts and memory management.
\section*{Initialization and Jump to crtInit}
\begin{lstlisting}[caption={Bootstrapping and Jump to Initialization}]
.global crtStart
.section .start_jump,"ax",@progbits
crtStart:
// Long jump to allow crtInit to be anywhere
// Do it always in 12 bytes
lui x2, %hi(crtInit)
addi x2, x2, %lo(crtInit)
jalr x1, x2
nop
\end{lstlisting}
This section configures an initial jump to the crtInit function, facilitating flexible placement of initialization routines in memory.
\section*{Trap Entry Routine}
\begin{lstlisting}[caption={Trap Entry Handling}]
.global trap_entry
.align 5
trap_entry:
// Store registers on the stack
sw x1, -1*4(sp)
...
sw x31, -16*4(sp)
addi sp, sp, -16*4
call irqCallback
// Restore registers from the stack
lw x1, 15*4(sp)
...
lw x31, 0*4(sp)
addi sp, sp, 16*4
mret
\end{lstlisting}
This routine handles interrupts by saving registers on the stack, executing an interrupt callback, and restoring the registers before returning from the trap.
\section*{Initialization Routine}
\begin{lstlisting}[caption={Initialization Code}]
.section .text
.global crtInit
crtInit:
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, _stack_start
// Initialize BSS section
bss_init:
la a0, _bss_start
la a1, _bss_end
bss_loop:
beq a0, a1, bss_done
sw zero, 0(a0)
add a0, a0, 4
j bss_loop
bss_done:
\end{lstlisting}
This code initializes the global pointer and stack pointer, and clears the BSS segment, which is used for zero-initialized variables.
\section*{Main Routine and Infinite Loop}
\begin{lstlisting}[caption={Main Entry and Infinite Loop}]
// Set up machine interrupt enable register
li a0, 0x880 // Enable timer + external interrupts
csrw mie, a0
li a0, 0x1808 // Enable interrupts
csrw mstatus, a0
call main
infinitLoop:
j infinitLoop
\end{lstlisting}
This final part sets up the machine interrupt system, calls the main program, and then enters an infinite loop to prevent the processor from executing beyond the program's end.
\section*{Detailed Description of crt.S}
\begin{lstlisting}[caption={crt.S Assembly Details}]
.global crtStart
.global main
.global irqCallback
.section .start_jump,"ax",@progbits
crtStart:
// Long jump to allow crtInit to be anywhere
// Always executed in 12 bytes
lui x2, %hi(crtInit)
addi x2, x2, %lo(crtInit)
jalr x1, x2
nop
.section .text
.global trap_entry
.align 5
trap_entry:
sw x1, - 1*4(sp)
...
sw x31, -16*4(sp)
addi sp,sp,-16*4
call irqCallback
lw x1 , 15*4(sp)
...
lw x31, 0*4(sp)
addi sp,sp,16*4
mret
crtInit:
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, _stack_start
bss_init:
la a0, _bss_start
la a1, _bss_end
bss_loop:
beq a0, a1, bss_done
sw zero, 0(a0)
add a0, a0, 4
j bss_loop
bss_done:
ctors_init:
la a0, _ctors_start
addi sp,sp,-4
ctors_loop:
la a1, _ctors_end
beq a0, a1, ctors_done
lw a3,0(a0)
add a0, a0, 4
sw a0, 0(sp)
jalr a3
lw a0, 0(sp)
j ctors_loop
ctors_done:
addi sp,sp,4
li a0, 0x880 // 880 enable timer + external interrupts
csrw mie, a0
li a0, 0x1808 // 1808 enable interrupts
csrw mstatus, a0
call main
infinitLoop:
j infinitLoop
\end{lstlisting}
This section provides a complete view of the `crt.S` file, detailing how initial setup, interrupt handling, BSS clearing, and infinite looping are implemented to ensure system readiness for application execution.
\end{document}

65
src/main.c-kopia Normal file
View File

@ -0,0 +1,65 @@
//#include "stddefs.h"
#include <stdint.h>
#include "murax.h"
void print(const char*str){
while(*str){
// uart_write(UART,*str);
str++;
}
}
void println(const char*str){
print(str);
// uart_write(UART,'\n');
}
void delay(uint32_t loops){
for(int i=0;i<loops;i++){
int tmp = GPIO_A->OUTPUT;
}
}
volatile int mati = 0;
class TimeR {
private:
static const Timer_Reg* ptr ;
};
//TimeR::ptr = 0xF0020040;
int main() {
GPIO_A->OUTPUT_ENABLE = 0x0000000F;
GPIO_A->OUTPUT = 0x00000001;
println("hello world arty a7 v1");
const int nleds = 4;
const int nloops = 10;
interruptCtrl_init(TIMER_INTERRUPT);
prescaler_init(TIMER_PRESCALER);
timer_init(TIMER_A);
TIMER_PRESCALER->LIMIT = 0x10;;
TIMER_A->LIMIT = 0x100;
TIMER_A->CLEARS_TICKS = 0x10002;
TIMER_INTERRUPT->PENDINGS = 0xF;
TIMER_INTERRUPT->MASKS = 0x1;
while(1){
++mati;
}
}
void irqCallback(){
static volatile int count = 0;
++count;
TIMER_INTERRUPT->PENDINGS = 1;
}

View File

@ -14,6 +14,8 @@
#include "murax.h"
#include <cstddef>
#include <initializer_list>
#include <cstdio>
void print(const char*str){
while(*str){
@ -46,6 +48,14 @@ private:
};
const Timer_Reg* TimeR::ptr = reinterpret_cast<const Timer_Reg*>(0xF0020040);
// ---
@ -64,8 +74,36 @@ int len( const char * str) {
*/
int32_t ile = 0;
int myfunc(const char *s)
{
int i = 0;
// sum up all the character codes in the string
while (*s)
i += *s++;
return i;
}
void test (std::initializer_list<int> vals) {
int buffer[50];
for (auto p = vals.begin(); p != vals.end(); ++p) {
int * i = buffer;
*i++ = *p;
// sprintf(buffer, "%d\n", *p);
// printf("%s", buffer);
}
}
int main() {
char str[10] = {1,2,3};
/// myfunc(str);
// println("hello world arty a7 v1");
@ -84,7 +122,9 @@ int main() {
// Thread 0
while( 1){
char * s = "11111111112222222222";
++ile;
++ile;
test({1,2,3,4,5});
// len (s);
}

66
src/stub_stdlib.c Normal file
View File

@ -0,0 +1,66 @@
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/stat.h>
#include <errno.h>
#undef errno
extern int errno;
void _exit(int i) {
asm volatile ("ebreak");
}
int _kill(int pid, int sig) {
asm volatile ("ebreak");
return -1;
}
int _getpid(void) {
return 1;
}
int _close(int file) {
errno = EBADF;
return -1;
}
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file) {
return 1;
}
int _lseek(int file, int ptr, int dir) {
return 0;
}
int _open(const char *name, int flags, int mode) {
errno = ENFILE;
return -1;
}
int _read(int file, char *ptr, int len) {
return 0;
}
int _write(int file, const char *ptr, int len) {
return len;
}
char *_sbrk(int delta) {
extern char _end[];
static char *end_of_data = _end;
char *ptr = end_of_data;
end_of_data += delta;
return ptr;
}
#ifdef __cplusplus
}
#endif

148
src/stub_stdlib.c-rvddt Normal file
View File

@ -0,0 +1,148 @@
#include <sys/stat.h>
#include <errno.h>
#include <errno.h>
#undef errno
extern int errno;
/**
* This will execute an ebreak instruction and assume that the
* CPU will halt or simulation environment will terminate.
*****************************************************************/
void _exit(int i)
{
asm volatile (" ebreak ");
}
/**
* It is assumed that there is exactly only process running and that
* it does not support signals. Therefore calling this is effectively
* illegal and will therefore execute an ebreak instruction.
*****************************************************************/
void _kill(int pid)
{
#if 1
asm volatile (" ebreak ");
#else
return; // arguably, this might also be acceptable
#endif
}
/**
* This returns the process ID of the runnung program.
* This library assumes that there is only process that
* can ever run.
*
* @return 1
*****************************************************************/
int _getpid(void)
{
return 1;
}
/**
* This library does not support any file I/O of any kind.
*
* @return -1 Indicating that file could not be closed.
*****************************************************************/
int _close(int file)
{
errno = EBADF;
return -1;
}
/**
* This library does not support any file I/O of any kind.
* This call will return a status indicating that the file
* in question is a character device.
*
* @return 0 Indicating that the call has succeeded.
*****************************************************************/
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
/**
* This library does not support any file I/O of any kind.
*
* @return 1 Indicating that file is a tty device (a terminal.)
*****************************************************************/
int _isatty(int file)
{
return 1;
}
/**
* This library does not support any file I/O of any kind.
*
* @return 0 Indicating that the request has succeeded.
*****************************************************************/
int _lseek(int file, int ptr, int dir)
{
return 0;
}
/**
* This library does not support any file I/O of any kind.
*
* @return -1 (error codition.)
*****************************************************************/
int _open(const char *name, int flags, int mode)
{
errno = ENFILE; // The system-wide limit (0) on total open files has been reached.
return -1;
}
/**
* This library does not support any file I/O of any kind.
*
* @return EOF.
*****************************************************************/
int _read(int file, char *ptr, int len)
{
return 0;
}
/**
* This function should satify the caller by simply returning len
* indicating that the write has succeeded as requested in spite
* of the fact that the data is simply ignored/discarded.
*
* @return len
*****************************************************************/
int _write(int file, char *ptr, int len)
{
return len;
}
/**
* Adjust the brk pointer up or down as requested.
*
* The initial brk address is set to _end (the end of the BSS).
* Any requests to adjust the brk will be performed without any
* error checking.
*
* @param delta The number of bytes to raise or lower the brk.
*
* @return The address that brk was set to before adjusting it by
* delta. Note that when delta is positive, this will return the
* address of the newly allocated region of memory.
*
* @bug It is possible that an errant program could call this and
* reduce the brk such that it points below _end or increase the
* brk to the point that it overlaps the stack.
*****************************************************************/
char *_sbrk (int delta)
{
extern char _end[];
static char *end_of_data = _end;
char *ptr = end_of_data;
end_of_data += delta;
return ptr;
}