diff --git a/makefile b/makefile index 551c235..0785463 100644 --- a/makefile +++ b/makefile @@ -3,10 +3,10 @@ DEBUG=no BENCH=no MULDIV=no -SRCS = $(wildcard src/*.c) \ - $(wildcard src/*.cpp) \ - $(wildcard src/*.S) \ - src/stub_stdlib.c +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) \ + src/stub_stdlib.c OBJDIR = build @@ -15,77 +15,78 @@ 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 + RISCV_PATH ?= /home/user/riscv/opt/rv32im/ endif MABI=ilp32 MARCH := rv32i_zicsr ifeq ($(MULDIV),yes) - MARCH := $(MARCH)m -endif -ifeq ($(COMPRESSED),yes) - MARCH := $(MARCH)ac + MARCH := $(MARCH)m endif -CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG -std=c++11 -fno-pic -ffreestanding -LDFLAGS += -march=$(MARCH) -mabi=$(MABI) -lc -lgcc -nostdlib -nostartfiles -nostartfiles - - - -#include ../../../resources/subproject.mk - +#CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG +#LDFLAGS += -march=$(MARCH) -mabi=$(MABI) ifeq ($(DEBUG),yes) - CFLAGS += -g3 -O0 + CFLAGS += -g3 -O0 endif ifeq ($(DEBUG),no) - CFLAGS += -g -Os + CFLAGS += -g -Os endif ifeq ($(BENCH),yes) - CFLAGS += -fno-inline + CFLAGS += -fno-inline endif ifeq ($(SIFIVE_GCC_PACK),yes) - RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ else - RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ + 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 -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 += -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 + +#CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG -std=c++11 -fno-pic -ffreestanding -MD -fstrict-volatile-bitfields -fno-strict-aliasing +#LDFLAGS += -march=$(MARCH) -mabi=$(MABI) -lc -lgcc -nostdlib -nostartfiles -mcmodel=medany -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map + +CFLAGS += -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) @@ -105,12 +106,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 $@ $^ + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ $(OBJDIR)/%.o: %.S mkdir -p $(dir $@) @@ -130,6 +130,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) + diff --git a/src/latex/main.pdf b/src/latex/main.pdf new file mode 100644 index 0000000..48f89f0 Binary files /dev/null and b/src/latex/main.pdf differ diff --git a/src/latex/main.tex b/src/latex/main.tex new file mode 100644 index 0000000..7aa9c92 --- /dev/null +++ b/src/latex/main.tex @@ -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} + + + diff --git a/src/main.c-kopia b/src/main.c-kopia new file mode 100644 index 0000000..ce5fe59 --- /dev/null +++ b/src/main.c-kopia @@ -0,0 +1,65 @@ +//#include "stddefs.h" +#include + +#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;iOUTPUT; + } +} + +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; + +} diff --git a/src/stub_stdlib.c b/src/stub_stdlib.c new file mode 100644 index 0000000..db81061 --- /dev/null +++ b/src/stub_stdlib.c @@ -0,0 +1,66 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#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 + diff --git a/src/stub_stdlib.c-rvddt b/src/stub_stdlib.c-rvddt new file mode 100644 index 0000000..5f3c656 --- /dev/null +++ b/src/stub_stdlib.c-rvddt @@ -0,0 +1,148 @@ +#include +#include + + +#include +#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; +}