diff --git a/isolde/sw/simple_system/bsp/Makefile b/isolde/sw/simple_system/bsp/Makefile new file mode 100644 index 00000000..8e122e0e --- /dev/null +++ b/isolde/sw/simple_system/bsp/Makefile @@ -0,0 +1,38 @@ +CV_SW_TOOLCHAIN ?= /opt/riscv +RISCV ?= $(CV_SW_TOOLCHAIN) +RISCV_EXE_PREFIX ?= $(RISCV)/bin/riscv32-unknown-elf- +RISCV_GCC = $(RISCV_EXE_PREFIX)gcc +RISCV_AR = $(RISCV_EXE_PREFIX)ar +SRC = crt0.S simple_system_common.c startup.c tinyprintf.c +OBJ = crt0.o simple_system_common.o startup.o tinyprintf.o +LIBCV-VERIF = libcv-verif.a +TINY_PRINTF_FLAGS += -DTINYPRINTF_DEFINE_TFP_PRINTF +TINY_PRINTF_FLAGS += -DTINYPRINTF_DEFINE_TFP_SPRINTF + + +CFLAGS ?= -Os -g -static -mabi=ilp32 -march=$(CV_SW_MARCH) $(TINY_PRINTF_FLAGS) -ffunction-sections -fdata-sections -Wall -pedantic + +all: $(LIBCV-VERIF) + +$(LIBCV-VERIF): $(OBJ) + $(RISCV_AR) rcs $@ $(OBJ) + +%.o : %.c + $(RISCV_GCC) $(CFLAGS) -c $< -o $@ + +%.o : %.S + $(RISCV_GCC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJ) $(LIBCV-VERIF) + + +vars: + @echo "make bsp variables:" + @echo " CV_SW_TOOLCHAIN = $(CV_SW_TOOLCHAIN)" + @echo " CV_SW_MARCH = $(CV_SW_MARCH)" + @echo " RISCV = $(RISCV)" + @echo " RISCV_EXE_PREFIX = $(RISCV_EXE_PREFIX)" + @echo " RISCV_GCC = $(RISCV_GCC)" + @echo " RISCV_MARCH = $(RISCV_MARCH)" + diff --git a/isolde/sw/simple_system/bsp/common-llvm.mk b/isolde/sw/simple_system/bsp/common-llvm.mk new file mode 100644 index 00000000..66365413 --- /dev/null +++ b/isolde/sw/simple_system/bsp/common-llvm.mk @@ -0,0 +1,103 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +COMMON_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +COMMON_SRCS = $(wildcard $(COMMON_DIR)/*.c) +INCS := -I$(COMMON_DIR) + + +TARGET := riscv32 +ARCH := rv32g +RISCV_ABI := ilp32 + +RISCV_WARNINGS += -Wunused-variable -Wall -Wextra -Wno-unused-command-line-argument # -Werror + +LLVM_FLAGS ?= --target=$(TARGET) -march=$(ARCH) -menable-experimental-extensions -mabi=$(RISCV_ABI) -mno-relax +RISCV_FLAGS ?= $(LLVM_FLAGS) -mcmodel=medany -O3 -ffast-math -g $(RISCV_WARNINGS) +RISCV_CCFLAGS ?= $(RISCV_FLAGS) -ffunction-sections -fdata-sections -std=gnu99 -nostdlib -nostartfiles +RISCV_CXXFLAGS ?= $(RISCV_FLAGS) -ffunction-sections -fdata-sections +RISCV_LDFLAGS ?= -static -nostdlib + +LINKER_SCRIPT ?= $(COMMON_DIR)/link.ld + +CFLAGS ?= -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany -Wall -g -O3\ + -fvisibility=hidden -nostdlib -nostartfiles -ffreestanding $(PROGRAM_CFLAGS) + +ifdef PROGRAM +PROGRAM_C := $(PROGRAM).c +endif + +SRCS = $(COMMON_SRCS) $(PROGRAM_C) $(EXTRA_SRCS) + +C_SRCS = $(filter %.c, $(SRCS)) +ASM_SRCS = $(filter %.S, $(SRCS)) + +CC := $(LLVM_TOOLCHAIN)/clang +LD := $(LLVM_TOOLCHAIN)/riscv32-unknown-elf-ld +#LD := $(LLVM_TOOLCHAIN)/ld.lld +#LD := $(GCC_TOOLCHAIN)/riscv32-unknown-elf-gcc + + +#OBJCOPY := $(LLVM_TOOLCHAIN)/llvm-objcopy +OBJDUMP := $(GCC_TOOLCHAIN)/riscv32-unknown-elf-objdump +#OBJDUMP := $(LLVM_TOOLCHAIN)/llvm-objdump + + +CRT ?= $(COMMON_DIR)/crt0.S + + + + +OBJS := ${C_SRCS:.c=.o} ${ASM_SRCS:.S=.o} ${CRT:.S=.o} +DEPS = $(OBJS:%.o=%.d) + +ifdef PROGRAM +OUTFILES := $(PROGRAM).elf +else +OUTFILES := $(OBJS) +endif + +all: $(OUTFILES) + +ifdef PROGRAM +$(PROGRAM).elf: $(OBJS) $(LINKER_SCRIPT) +# $(LD) $(CFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@ $(LIBS) + $(LD) $(RISCV_LDFLAGS) -Map $@.map -T $(LINKER_SCRIPT) $(OBJS) -o $@ $(LIBS) + $(OBJDUMP) -dh $@ >$@.headers + + +.PHONY: disassemble +disassemble: $(PROGRAM).dis +endif + +%.dis: %.elf + $(OBJDUMP) -fhSD $^ > $@ + +# Note: this target requires the srecord package to be installed. +# XXX: This could be replaced by objcopy once +# https://sourceware.org/bugzilla/show_bug.cgi?id=19921 +# is widely available. +%.vmem: %.bin + srec_cat $^ -binary -offset 0x0000 -byte-swap 4 -o $@ -vmem + +%.bin: %.elf + $(OBJCOPY) -O binary $^ $@ + +%.o: %.c + $(CC) -c $(RISCV_CCFLAGS) $(INCS) -o $@ $< +# Rule to compile C to assembly +%.s: %.c + $(CC) -S $(RISCV_CCFLAGS) $(INCS) -o $@ $< + + +%.o: %.S + $(CC) -c $(RISCV_CCFLAGS) $(INCS) -o $@ $< + +clean: + $(RM) -f $(OBJS) $(DEPS) + rm -f *.bin *.vmem *.elf *.headers + +distclean: clean + $(RM) -f $(OUTFILES) diff --git a/isolde/sw/simple_system/bsp/common.mk b/isolde/sw/simple_system/bsp/common.mk new file mode 100644 index 00000000..ae0a876e --- /dev/null +++ b/isolde/sw/simple_system/bsp/common.mk @@ -0,0 +1,84 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +COMMON_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +COMMON_SRCS = $(wildcard $(COMMON_DIR)/*.c) +INCS := -I$(COMMON_DIR) + +# ARCH = rv32im # to disable compressed instructions +ARCH ?= rv32im_zicsr + +ifdef PROGRAM +PROGRAM_C := $(PROGRAM).c +endif + +SRCS = $(COMMON_SRCS) $(PROGRAM_C) $(EXTRA_SRCS) + +C_SRCS = $(filter %.c, $(SRCS)) +ASM_SRCS = $(filter %.S, $(SRCS)) + +CC = riscv32-unknown-elf-gcc + +CROSS_COMPILE = $(patsubst %-gcc,%-,$(CC)) +OBJCOPY ?= $(CROSS_COMPILE)objcopy +OBJDUMP ?= $(CROSS_COMPILE)objdump + +LINKER_SCRIPT ?= $(COMMON_DIR)/link.ld +CRT ?= $(COMMON_DIR)/crt0.S + +TINY_PRINTF_FLAGS += -DTINYPRINTF_DEFINE_TFP_PRINTF +TINY_PRINTF_FLAGS += -DTINYPRINTF_DEFINE_TFP_SPRINTF +CFLAGS ?= -march=$(ARCH) -mabi=ilp32 -static -mcmodel=medany -Wall -g -O3\ + -fvisibility=hidden -nostdlib -nostartfiles -ffreestanding $(TINY_PRINTF_FLAGS) $(PROGRAM_CFLAGS) + +OBJS := ${C_SRCS:.c=.o} ${ASM_SRCS:.S=.o} ${CRT:.S=.o} +DEPS = $(OBJS:%.o=%.d) + +ifdef PROGRAM +OUTFILES := $(PROGRAM).elf +else +OUTFILES := $(OBJS) +endif + +all: $(OUTFILES) + +ifdef PROGRAM +$(PROGRAM).elf: $(OBJS) $(LINKER_SCRIPT) + $(CC) $(CFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@ $(LIBS) + $(OBJDUMP) -dh $@ >$@.headers + + +.PHONY: disassemble +disassemble: $(PROGRAM).dis +endif + +%.dis: %.elf + $(OBJDUMP) -fhSD $^ > $@ + +# Note: this target requires the srecord package to be installed. +# XXX: This could be replaced by objcopy once +# https://sourceware.org/bugzilla/show_bug.cgi?id=19921 +# is widely available. +%.vmem: %.bin + srec_cat $^ -binary -offset 0x0000 -byte-swap 4 -o $@ -vmem + +%.bin: %.elf + $(OBJCOPY) -O binary $^ $@ + +%.o: %.c + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< +# Rule to compile C to assembly +%.s: %.c + $(CC) $(CFLAGS) -S $(INCS) $< -o $@ + +%.o: %.S + $(CC) $(CFLAGS) -MMD -c $(INCS) -o $@ $< + +clean: + $(RM) -f $(OBJS) $(DEPS) + rm -f *.bin *.vmem *.elf *.headers + +distclean: clean + $(RM) -f $(OUTFILES) diff --git a/isolde/sw/simple_system/bsp/crt0.S b/isolde/sw/simple_system/bsp/crt0.S new file mode 100644 index 00000000..be2a1069 --- /dev/null +++ b/isolde/sw/simple_system/bsp/crt0.S @@ -0,0 +1,105 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +#include "simple_system_regs.h" + +.section .text + +default_exc_handler: + jal x0, simple_exc_handler + +timer_handler: + jal x0, simple_timer_handler + +reset_handler: + /* set all registers to zero */ + mv x1, x0 + mv x2, x1 + mv x3, x1 + mv x4, x1 + mv x5, x1 + mv x6, x1 + mv x7, x1 + mv x8, x1 + mv x9, x1 + mv x10, x1 + mv x11, x1 + mv x12, x1 + mv x13, x1 + mv x14, x1 + mv x15, x1 + mv x16, x1 + mv x17, x1 + mv x18, x1 + mv x19, x1 + mv x20, x1 + mv x21, x1 + mv x22, x1 + mv x23, x1 + mv x24, x1 + mv x25, x1 + mv x26, x1 + mv x27, x1 + mv x28, x1 + mv x29, x1 + mv x30, x1 + mv x31, x1 + + /* stack initilization */ + la x2, _stack_start + +_start: + .global _start + + /* clear BSS */ + la x26, _bss_start + la x27, _bss_end + + bge x26, x27, zero_loop_end + +zero_loop: + sw x0, 0(x26) + addi x26, x26, 4 + ble x26, x27, zero_loop +zero_loop_end: + + +main_entry: + /* jump to startup program entry */ +// addi x10, x0, 0 +// addi x11, x0, 0 + jal x1, startup + /* Halt simulation */ + li a1, 0 + li a2, 0 + li a3, 0 + li a4, 0 + li a5, 0 + li a7, 93 + ecall + + /* If execution ends up here just put the core to sleep */ +sleep_loop: + wfi + j sleep_loop + +/* =================================================== [ exceptions ] === */ +/* This section has to be down here, since we have to disable rvc for it */ + + .section .vectors, "ax" + .option norvc; + + // All unimplemented interrupts/exceptions go to the default_exc_handler. + .org 0x00 + .rept 7 + jal x0, default_exc_handler + .endr + jal x0, timer_handler + .rept 23 + jal x0, default_exc_handler + .endr + + // reset vector + .org 0x80 + jal x0, reset_handler diff --git a/isolde/sw/simple_system/bsp/link.ld b/isolde/sw/simple_system/bsp/link.ld new file mode 100644 index 00000000..297ffc1a --- /dev/null +++ b/isolde/sw/simple_system/bsp/link.ld @@ -0,0 +1,90 @@ +/* Copyright lowRISC contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 */ + +OUTPUT_ARCH(riscv) + +MEMORY +{ +/* Change this if you'd like different sizes. Arty A7-100(35) has a maximum of 607.5KB(225KB) + BRAM space. Configuration below is for maximum BRAM capacity with Artya A7-35 while letting + CoreMark run (.vmem of 152.8KB). +*/ + ram : ORIGIN = 0x00100000, LENGTH = 0x30000 /* 192 kB */ + stack : ORIGIN = 0x00130000, LENGTH = 0x8000 /* 32 kB */ +} + +/* Stack information variables */ +_min_stack = 0x2000; /* 8K - minimum stack space to reserve */ +_stack_len = LENGTH(stack); +_stack_start = ORIGIN(stack) + LENGTH(stack); + +_entry_point = _vectors_start + 0x80; +ENTRY(_entry_point) + +/* The tohost address is used by Spike for a magic "stop me now" message. This + is set to equal SIM_CTRL_CTRL (see simple_system_regs.h), which has that + effect in simple_system simulations. Note that it must be 8-byte aligned. + + We don't read data back from Spike, so fromhost is set to some dummy value: + we place it just above the top of the stack. + */ +tohost = 0x20008; +fromhost = _stack_start + 0x10; + +SECTIONS +{ + .vectors : + { + . = ALIGN(4); + _vectors_start = .; + KEEP(*(.vectors)) + _vectors_end = .; + } > ram + + .text : { + . = ALIGN(4); + *(.text) + *(.text.*) + } > ram + + .rodata : { + . = ALIGN(4); + /* Small RO data before large RO data */ + *(.srodata) + *(.srodata.*) + *(.rodata); + *(.rodata.*) + } > ram + + .data : { + . = ALIGN(4); + /* Small data before large data */ + *(.sdata) + *(.sdata.*) + *(.data); + *(.data.*) + } > ram + + .bss : + { + . = ALIGN(4); + _bss_start = .; + /* Small BSS before large BSS */ + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(COMMON) + _bss_end = .; + } > ram + + /* ensure there is enough room for stack */ + .stack (NOLOAD): { + . = ALIGN(4); + . = . + _min_stack ; + . = ALIGN(4); + stack = . ; + _stack = . ; + } > stack +} diff --git a/isolde/sw/simple_system/bsp/simple_system_common.c b/isolde/sw/simple_system/bsp/simple_system_common.c new file mode 100644 index 00000000..8b3969d4 --- /dev/null +++ b/isolde/sw/simple_system/bsp/simple_system_common.c @@ -0,0 +1,191 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "simple_system_common.h" +#include "tinyprintf.h" + + +void puthex(uint32_t h) { + int cur_digit; + // Iterate through h taking top 4 bits each time and outputting ASCII of hex + // digit for those 4 bits + for (int i = 0; i < 8; i++) { + cur_digit = h >> 28; + + if (cur_digit < 10) + putchar('0' + cur_digit); + else + putchar('A' - 10 + cur_digit); + + h <<= 4; + } +} + +#define MMADDR_EXIT SIM_CTRL_BASE + SIM_CTRL_CTRL +void sim_halt() { DEV_WRITE(MMADDR_EXIT, 1); } + +void pcount_reset() { + asm volatile( + "csrw minstret, x0\n" + "csrw mcycle, x0\n" + "csrw mhpmcounter3, x0\n" + "csrw mhpmcounter4, x0\n" + "csrw mhpmcounter5, x0\n" + "csrw mhpmcounter6, x0\n" + "csrw mhpmcounter7, x0\n" + "csrw mhpmcounter8, x0\n" + "csrw mhpmcounter9, x0\n" + "csrw mhpmcounter10, x0\n" + "csrw mhpmcounter11, x0\n" + "csrw mhpmcounter12, x0\n" + "csrw mhpmcounter13, x0\n" + "csrw mhpmcounter14, x0\n" + "csrw mhpmcounter15, x0\n" + "csrw mhpmcounter16, x0\n" + "csrw mhpmcounter17, x0\n" + "csrw mhpmcounter18, x0\n" + "csrw mhpmcounter19, x0\n" + "csrw mhpmcounter20, x0\n" + "csrw mhpmcounter21, x0\n" + "csrw mhpmcounter22, x0\n" + "csrw mhpmcounter23, x0\n" + "csrw mhpmcounter24, x0\n" + "csrw mhpmcounter25, x0\n" + "csrw mhpmcounter26, x0\n" + "csrw mhpmcounter27, x0\n" + "csrw mhpmcounter28, x0\n" + "csrw mhpmcounter29, x0\n" + "csrw mhpmcounter30, x0\n" + "csrw mhpmcounter31, x0\n" + "csrw minstreth, x0\n" + "csrw mcycleh, x0\n" + "csrw mhpmcounter3h, x0\n" + "csrw mhpmcounter4h, x0\n" + "csrw mhpmcounter5h, x0\n" + "csrw mhpmcounter6h, x0\n" + "csrw mhpmcounter7h, x0\n" + "csrw mhpmcounter8h, x0\n" + "csrw mhpmcounter9h, x0\n" + "csrw mhpmcounter10h, x0\n" + "csrw mhpmcounter11h, x0\n" + "csrw mhpmcounter12h, x0\n" + "csrw mhpmcounter13h, x0\n" + "csrw mhpmcounter14h, x0\n" + "csrw mhpmcounter15h, x0\n" + "csrw mhpmcounter16h, x0\n" + "csrw mhpmcounter17h, x0\n" + "csrw mhpmcounter18h, x0\n" + "csrw mhpmcounter19h, x0\n" + "csrw mhpmcounter20h, x0\n" + "csrw mhpmcounter21h, x0\n" + "csrw mhpmcounter22h, x0\n" + "csrw mhpmcounter23h, x0\n" + "csrw mhpmcounter24h, x0\n" + "csrw mhpmcounter25h, x0\n" + "csrw mhpmcounter26h, x0\n" + "csrw mhpmcounter27h, x0\n" + "csrw mhpmcounter28h, x0\n" + "csrw mhpmcounter29h, x0\n" + "csrw mhpmcounter30h, x0\n" + "csrw mhpmcounter31h, x0\n"); +} + +unsigned int get_mepc() { + uint32_t result; + __asm__ volatile("csrr %0, mepc;" : "=r"(result)); + return result; +} + +unsigned int get_mcause() { + uint32_t result; + __asm__ volatile("csrr %0, mcause;" : "=r"(result)); + return result; +} + +unsigned int get_mtval() { + uint32_t result; + __asm__ volatile("csrr %0, mtval;" : "=r"(result)); + return result; +} + +void simple_exc_handler(void) { + #if 0 + volatile register int a7 asm("a7"); + + // Check if A7 equals 93 + //https://jborza.com/post/2021-05-11-riscv-linux-syscalls/ + if (a7 == 93) { +#else + int result; + asm volatile ("mv %0, a7" : "=r"(result)); + // Check if A7 equals 93 + //https://jborza.com/post/2021-05-11-riscv-linux-syscalls/ + if (result == 93) { +#endif + printf("exit()\n"); + printf("======\n"); + }else{ + printf("EXCEPTION!!!\n"); + printf("============\n"); + printf("MEPC: 0x"); + puthex(get_mepc()); + printf("\nMCAUSE: 0x"); + puthex(get_mcause()); + printf("\nMTVAL: 0x"); + puthex(get_mtval()); + putchar('\n'); + } + sim_halt(); + + while(1); +} + +volatile uint64_t time_elapsed; +uint64_t time_increment; + +inline static void increment_timecmp(uint64_t time_base) { + uint64_t current_time = timer_read(); + current_time += time_base; + timecmp_update(current_time); +} + +void timer_enable(uint64_t time_base) { + time_elapsed = 0; + time_increment = time_base; + // Set timer values + increment_timecmp(time_base); + // enable timer interrupt + asm volatile("csrs mie, %0\n" : : "r"(0x80)); + // enable global interrupt + asm volatile("csrs mstatus, %0\n" : : "r"(0x8)); +} + +void timer_disable(void) { asm volatile("csrc mie, %0\n" : : "r"(0x80)); } + +uint64_t timer_read(void) { + uint32_t current_timeh; + uint32_t current_time; + // check if time overflowed while reading and try again + do { + current_timeh = DEV_READ(TIMER_BASE + TIMER_MTIMEH, 0); + current_time = DEV_READ(TIMER_BASE + TIMER_MTIME, 0); + } while (current_timeh != DEV_READ(TIMER_BASE + TIMER_MTIMEH, 0)); + uint64_t final_time = ((uint64_t)current_timeh << 32) | current_time; + return final_time; +} + +void timecmp_update(uint64_t new_time) { + DEV_WRITE(TIMER_BASE + TIMER_MTIMECMP, -1); + DEV_WRITE(TIMER_BASE + TIMER_MTIMECMPH, new_time >> 32); + DEV_WRITE(TIMER_BASE + TIMER_MTIMECMP, new_time); +} + +uint64_t get_elapsed_time(void) { return time_elapsed; } + +void simple_timer_handler(void) __attribute__((interrupt)); + +void simple_timer_handler(void) { + increment_timecmp(time_increment); + time_elapsed++; +} diff --git a/isolde/sw/simple_system/bsp/simple_system_common.h b/isolde/sw/simple_system/bsp/simple_system_common.h new file mode 100644 index 00000000..650ea6bc --- /dev/null +++ b/isolde/sw/simple_system/bsp/simple_system_common.h @@ -0,0 +1,116 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SIMPLE_SYSTEM_COMMON_H__ + +#include + +#include "simple_system_regs.h" + +#define DEV_WRITE(addr, val) (*((volatile uint32_t *)(addr)) = val) +#define DEV_READ(addr, val) (*((volatile uint32_t *)(addr))) +#define PCOUNT_READ(name, dst) asm volatile("csrr %0, " #name ";" : "=r"(dst)) + +extern void _putcf (void * unused, char c); +/** + * Writes character to simulator out log. Signature matches c stdlib function + * of the same name. + * + * @param c Character to output + * @returns Character output (never fails so no EOF ever returned) + */ +int putchar(char c); + +/** + * Writes string to simulator out log. Signature matches c stdlib function of + * the same name. + * + * @param str String to output + * @returns 0 always (never fails so no error) + */ +int puts(const char *str); + +/** + * Writes ASCII hex representation of number to simulator out log. + * + * @param h Number to output in hex + */ +void puthex(uint32_t h); + +/** + * Immediately halts the simulation + */ +void sim_halt(); + +/** + * Enables/disables performance counters. This effects mcycle and minstret as + * well as the mhpmcounterN counters. + * + * @param enable if non-zero enables, otherwise disables + */ +static inline void pcount_enable(int enable) { + // Note cycle is disabled with everything else + unsigned int inhibit_val = enable ? 0x0 : 0xFFFFFFFF; + // CSR 0x320 was called `mucounteren` in the privileged spec v1.9.1, it was + // then dropped in v1.10, and then re-added in v1.11 with the name + // `mcountinhibit`. Unfortunately, the version of binutils we use only allows + // the old name, and LLVM only supports the new name (though this is changed + // on trunk to support both), so we use the numeric value here for maximum + // compatibility. + asm volatile("csrw 0x320, %0\n" : : "r"(inhibit_val)); +} + +/** + * Resets all performance counters. This effects mcycle and minstret as well + * as the mhpmcounterN counters. + */ +void pcount_reset(); + +/** + * Enables timer interrupt + * + * @param time_base Number of time ticks to count before interrupt + */ +void timer_enable(uint64_t time_base); + +/** + * Returns current mtime value + */ +uint64_t timer_read(void); + +/** + * Set a new timer value + * + * @param new_time New value for time + */ +void timecmp_update(uint64_t new_time); + +/** + * Disables timer interrupt + */ +void timer_disable(void); + +/** + * Returns current global time value + */ +uint64_t get_elapsed_time(void); + +/** + * Enables/disables the instruction cache. This has no effect on Ibex + * configurations that do not have an instruction cache and in particular is + * safe to execute on those configurations. + * + * @param enable if non-zero enables, otherwise disables + */ +static inline void icache_enable(int enable) { + if (enable) { + // Set icache enable bit in CPUCTRLSTS + asm volatile("csrs 0x7c0, 1"); + } else { + // Clear icache enable bit in CPUCTRLSTS + asm volatile("csrc 0x7c0, 1"); + } +} + +#endif diff --git a/isolde/sw/simple_system/bsp/simple_system_regs.h b/isolde/sw/simple_system/bsp/simple_system_regs.h new file mode 100644 index 00000000..36b1e6bc --- /dev/null +++ b/isolde/sw/simple_system/bsp/simple_system_regs.h @@ -0,0 +1,18 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SIMPLE_SYSTEM_REGS_H__ +#define SIMPLE_SYSTEM_REGS_H__ + +#define SIM_CTRL_BASE 0x20000 +#define SIM_CTRL_OUT 0x0 +#define SIM_CTRL_CTRL 0x8 + +#define TIMER_BASE 0x30000 +#define TIMER_MTIME 0x0 +#define TIMER_MTIMEH 0x4 +#define TIMER_MTIMECMP 0x8 +#define TIMER_MTIMECMPH 0xC + +#endif // SIMPLE_SYSTEM_REGS_H__ diff --git a/isolde/sw/simple_system/bsp/startup.c b/isolde/sw/simple_system/bsp/startup.c new file mode 100644 index 00000000..4e21f965 --- /dev/null +++ b/isolde/sw/simple_system/bsp/startup.c @@ -0,0 +1,28 @@ + +#define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#include "tinyprintf.h" + +#include "simple_system_common.h" + + +extern int main(int argc, char *argv[]); + + + + void _putcf (void * unused, char c) { + (int)unused; + DEV_WRITE(SIM_CTRL_BASE + SIM_CTRL_OUT, (unsigned char)c); +} + +int putchar(char c){ + _putcf (0, c); + return 1; +} + + + +void startup(){ + init_printf(0, _putcf); + main(0, 0); +} \ No newline at end of file diff --git a/isolde/sw/simple_system/bsp/tinyprintf.c b/isolde/sw/simple_system/bsp/tinyprintf.c new file mode 100644 index 00000000..00abf803 --- /dev/null +++ b/isolde/sw/simple_system/bsp/tinyprintf.c @@ -0,0 +1,521 @@ +/* +File: tinyprintf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "tinyprintf.h" + + +/* + * Configuration + */ + +/* Enable long int support */ +#define PRINTF_LONG_SUPPORT + +/* Enable long long int support (implies long int support) */ +//#define PRINTF_LONG_LONG_SUPPORT + +/* Enable %z (size_t) support */ +#define PRINTF_SIZE_T_SUPPORT + +/* + * Configuration adjustments + */ +#ifdef PRINTF_SIZE_T_SUPPORT +#include +#endif + +#ifdef PRINTF_LONG_LONG_SUPPORT +# define PRINTF_LONG_SUPPORT +#endif + +/* __SIZEOF___ defined at least by gcc */ +#ifdef __SIZEOF_POINTER__ +# define SIZEOF_POINTER __SIZEOF_POINTER__ +#endif +#ifdef __SIZEOF_LONG_LONG__ +# define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__ +#endif +#ifdef __SIZEOF_LONG__ +# define SIZEOF_LONG __SIZEOF_LONG__ +#endif +#ifdef __SIZEOF_INT__ +# define SIZEOF_INT __SIZEOF_INT__ +#endif + +#ifdef __GNUC__ +# define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline)) +#else +# define _TFP_GCC_NO_INLINE_ +#endif + +/* + * Implementation + */ +struct param { + char lz:1; /**< Leading zeros */ + char alt:1; /**< alternate form */ + char uc:1; /**< Upper case (for base16 only) */ + char align_left:1; /**< 0 == align right (default), 1 == align left */ + unsigned int width; /**< field width */ + char sign; /**< The sign to display (if any) */ + unsigned int base; /**< number base (e.g.: 8, 10, 16) */ + char *bf; /**< Buffer to output */ +}; + + +#ifdef PRINTF_LONG_LONG_SUPPORT +static void _TFP_GCC_NO_INLINE_ ulli2a( + unsigned long long int num, struct param *p) +{ + int n = 0; + unsigned long long int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void lli2a(long long int num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + ulli2a(num, p); +} +#endif + +#ifdef PRINTF_LONG_SUPPORT +static void uli2a(unsigned long int num, struct param *p) +{ + int n = 0; + unsigned long int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void li2a(long num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + uli2a(num, p); +} +#endif + +static void ui2a(unsigned int num, struct param *p) +{ + int n = 0; + unsigned int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void i2a(int num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + ui2a(num, p); +} + +static int a2d(char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static char a2u(char ch, const char **src, int base, unsigned int *nump) +{ + const char *p = *src; + unsigned int num = 0; + int digit; + while ((digit = a2d(ch)) >= 0) { + if (digit > base) + break; + num = num * base + digit; + ch = *p++; + } + *src = p; + *nump = num; + return ch; +} + +static void putchw(void *putp, putcf putf, struct param *p) +{ + char ch; + int n = p->width; + char *bf = p->bf; + + /* Number of filling characters */ + while (*bf++ && n > 0) + n--; + if (p->sign) + n--; + if (p->alt && p->base == 16) + n -= 2; + else if (p->alt && p->base == 8) + n--; + + /* Fill with space to align to the right, before alternate or sign */ + if (!p->lz && !p->align_left) { + while (n-- > 0) + putf(putp, ' '); + } + + /* print sign */ + if (p->sign) + putf(putp, p->sign); + + /* Alternate */ + if (p->alt && p->base == 16) { + putf(putp, '0'); + putf(putp, (p->uc ? 'X' : 'x')); + } else if (p->alt && p->base == 8) { + putf(putp, '0'); + } + + /* Fill with zeros, after alternate or sign */ + if (p->lz) { + while (n-- > 0) + putf(putp, '0'); + } + + /* Put actual buffer */ + bf = p->bf; + while ((ch = *bf++)) + putf(putp, ch); + + /* Fill with space to align to the left, after string */ + if (!p->lz && p->align_left) { + while (n-- > 0) + putf(putp, ' '); + } +} + +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va) +{ + struct param p; +#ifdef PRINTF_LONG_SUPPORT + char bf[23]; /* long = 64b on some architectures */ +#else + char bf[12]; /* int = 32b on some architectures */ +#endif + char ch; + p.bf = bf; + + while ((ch = *(fmt++))) { + if (ch != '%') { + putf(putp, ch); + } else { +#ifdef PRINTF_LONG_SUPPORT + char lng = 0; /* 1 for long, 2 for long long */ +#endif + /* Init parameter struct */ + p.lz = 0; + p.alt = 0; + p.width = 0; + p.align_left = 0; + p.sign = 0; + + /* Flags */ + while ((ch = *(fmt++))) { + switch (ch) { + case '-': + p.align_left = 1; + continue; + case '0': + p.lz = 1; + continue; + case '#': + p.alt = 1; + continue; + default: + break; + } + break; + } + + /* Width */ + if (ch >= '0' && ch <= '9') { + ch = a2u(ch, &fmt, 10, &(p.width)); + } + + /* We accept 'x.y' format but don't support it completely: + * we ignore the 'y' digit => this ignores 0-fill + * size and makes it == width (ie. 'x') */ + if (ch == '.') { + p.lz = 1; /* zero-padding */ + /* ignore actual 0-fill size: */ + do { + ch = *(fmt++); + } while ((ch >= '0') && (ch <= '9')); + } + +#ifdef PRINTF_SIZE_T_SUPPORT +# ifdef PRINTF_LONG_SUPPORT + if (ch == 'z') { + ch = *(fmt++); + if (sizeof(size_t) == sizeof(unsigned long int)) + lng = 1; +# ifdef PRINTF_LONG_LONG_SUPPORT + else if (sizeof(size_t) == sizeof(unsigned long long int)) + lng = 2; +# endif + } else +# endif +#endif + +#ifdef PRINTF_LONG_SUPPORT + if (ch == 'l') { + ch = *(fmt++); + lng = 1; +#ifdef PRINTF_LONG_LONG_SUPPORT + if (ch == 'l') { + ch = *(fmt++); + lng = 2; + } +#endif + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u': + p.base = 10; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'd': + case 'i': + p.base = 10; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + lli2a(va_arg(va, long long int), &p); + else +#endif + if (1 == lng) + li2a(va_arg(va, long int), &p); + else +#endif + i2a(va_arg(va, int), &p); + putchw(putp, putf, &p); + break; +#ifdef SIZEOF_POINTER + case 'p': + p.alt = 1; +# if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT + lng = 0; +# elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG + lng = 1; +# elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG + lng = 2; +# endif +#endif + case 'x': + case 'X': + p.base = 16; + p.uc = (ch == 'X')?1:0; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'o': + p.base = 8; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'c': + putf(putp, (char)(va_arg(va, int))); + break; + case 's': + p.bf = va_arg(va, char *); + putchw(putp, putf, &p); + p.bf = bf; + break; + case '%': + putf(putp, ch); + default: + break; + } + } + } + abort:; +} + +#if TINYPRINTF_DEFINE_TFP_PRINTF +static putcf stdout_putf; +static void *stdout_putp; + +void init_printf(void *putp, putcf putf) +{ + stdout_putf = putf; + stdout_putp = putp; +} + +void tfp_printf(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + tfp_format(stdout_putp, stdout_putf, fmt, va); + va_end(va); +} +#endif + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +struct _vsnprintf_putcf_data +{ + size_t dest_capacity; + char *dest; + size_t num_chars; +}; + +static void _vsnprintf_putcf(void *p, char c) +{ + struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p; + if (data->num_chars < data->dest_capacity) + data->dest[data->num_chars] = c; + data->num_chars ++; +} + +int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + struct _vsnprintf_putcf_data data; + + if (size < 1) + return 0; + + data.dest = str; + data.dest_capacity = size-1; + data.num_chars = 0; + tfp_format(&data, _vsnprintf_putcf, format, ap); + + if (data.num_chars < data.dest_capacity) + data.dest[data.num_chars] = '\0'; + else + data.dest[data.dest_capacity] = '\0'; + + return data.num_chars; +} + +int tfp_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsnprintf(str, size, format, ap); + va_end(ap); + return retval; +} + +struct _vsprintf_putcf_data +{ + char *dest; + size_t num_chars; +}; + +static void _vsprintf_putcf(void *p, char c) +{ + struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p; + data->dest[data->num_chars++] = c; +} + +int tfp_vsprintf(char *str, const char *format, va_list ap) +{ + struct _vsprintf_putcf_data data; + data.dest = str; + data.num_chars = 0; + tfp_format(&data, _vsprintf_putcf, format, ap); + data.dest[data.num_chars] = '\0'; + return data.num_chars; +} + +int tfp_sprintf(char *str, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsprintf(str, format, ap); + va_end(ap); + return retval; +} +#endif \ No newline at end of file diff --git a/isolde/sw/simple_system/bsp/tinyprintf.h b/isolde/sw/simple_system/bsp/tinyprintf.h new file mode 100644 index 00000000..a7dc2bf7 --- /dev/null +++ b/isolde/sw/simple_system/bsp/tinyprintf.h @@ -0,0 +1,186 @@ +/* +File: tinyprintf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'. + +They provide a simple and small (+400 loc) printf functionality to +be used in embedded systems. + +I've found them so useful in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and the 'sprintf' family of +functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf'). + +The formats supported by this implementation are: +'c' 'd' 'i' 'o' 'p' 'u' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then +the long specifier is also supported. Note that this will pull in some +long math routines (pun intended!) and thus make your executable +noticeably longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the +long long specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t +specifier. + +The memory footprint of course depends on the target CPU, compiler and +compiler options, but a rough guesstimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your mileage may vary. By hacking the source code you can +get rid of some hundred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf, you need to supply your own character output function, +something like : + +void putc ( void* p, char c) +{ + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; +} + +Before you can call printf, you need to initialize it to use your +character output function with something like: + +init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything really) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it is safe +to call it from interrupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set +(default). Setting it to 0 makes it possible to use them along with +'stdio.h' printf's in a single source file. When +'TINYPRINTF_OVERRIDE_LIBC' is set, please note that printf/sprintf are +not function-like macros, so if you have variables or struct members +with these names, things will explode in your face. Without variadic +macros this is the best we can do to wrap these function. If it is a +problem, just give up the macros and use the functions directly, or +rename them. + +It is also possible to avoid defining tfp_printf and/or tfp_sprintf by +clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or +'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to +export only tfp_format, which is at the core of all the other +functions. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +/* Global configuration */ + +/* Set this to 0 if you do not want to provide tfp_printf */ +#ifndef TINYPRINTF_DEFINE_TFP_PRINTF +# define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#endif + +/* Set this to 0 if you do not want to provide + tfp_sprintf/snprintf/vsprintf/vsnprintf */ +#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF +# define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#endif + +/* Set this to 0 if you do not want tfp_printf and + tfp_{vsn,sn,vs,s}printf to be also available as + printf/{vsn,sn,vs,s}printf */ +#ifndef TINYPRINTF_OVERRIDE_LIBC +# define TINYPRINTF_OVERRIDE_LIBC 1 +#endif + +/* Optional external types dependencies */ + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +# include /* size_t */ +#endif + +/* Declarations */ + +#ifdef __GNUC__ +# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) \ + __attribute__((format (printf, fmt_idx, arg1_idx))) +#else +# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*putcf) (void *, char); + +/* + 'tfp_format' really is the central function for all tinyprintf. For + each output character after formatting, the 'putf' callback is + called with 2 args: + - an arbitrary void* 'putp' param defined by the user and + passed unmodified from 'tfp_format', + - the character. + The 'tfp_printf' and 'tfp_sprintf' functions simply define their own + callback and pass to it the right 'putp' it is expecting. +*/ +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) \ + _TFP_SPECIFY_PRINTF_FMT(3, 4); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) \ + _TFP_SPECIFY_PRINTF_FMT(2, 3); +# if TINYPRINTF_OVERRIDE_LIBC +# define vsnprintf tfp_vsnprintf +# define snprintf tfp_snprintf +# define vsprintf tfp_vsprintf +# define sprintf tfp_sprintf +# endif +#endif + +#if TINYPRINTF_DEFINE_TFP_PRINTF +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +# if TINYPRINTF_OVERRIDE_LIBC +# define printf tfp_printf +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/isolde/sw/simple_system/vlinstr_test/Makefile b/isolde/sw/simple_system/vlinstr_test/Makefile index 62258cac..47bc538d 100644 --- a/isolde/sw/simple_system/vlinstr_test/Makefile +++ b/isolde/sw/simple_system/vlinstr_test/Makefile @@ -13,8 +13,8 @@ EXTRA_SRCS := # Check the COMPILER variable passed via the command line ifeq ($(COMPILER), llvm) - include $(PROGRAM_DIR)/../common/common-llvm.mk + include $(PROGRAM_DIR)/../bsp/common-llvm.mk else - include $(PROGRAM_DIR)/../common/common.mk + include $(PROGRAM_DIR)/../bsp/common.mk endif diff --git a/isolde/sw/simple_system/vlinstr_test/hello_test.c b/isolde/sw/simple_system/vlinstr_test/hello_test.c index 0d3f4b41..2d21ab32 100644 --- a/isolde/sw/simple_system/vlinstr_test/hello_test.c +++ b/isolde/sw/simple_system/vlinstr_test/hello_test.c @@ -14,12 +14,13 @@ #include "simple_system_common.h" +#include "tinyprintf.h" int main(int argc, char **argv) { - puts("Hello test instr\n"); + printf("Hello test instr\n"); unsigned int enc_instr64 = 0xBEAD0000; // Example value unsigned int dummy = 0xBADCAFE;