Skip to content
Snippets Groups Projects
Commit 13933f9f authored by Pavel Pisa's avatar Pavel Pisa
Browse files

seminaries/qtrvsim/os-emu-example: initial version of C library use example.


Functional in with user QEMU for 32 or even 64-bit build
on GNU{Linux system. printf() works on qtrvsim_gui but
actual malloc/sbrk code does not. qtrvsim_cli missing
system-calls support at all.

Signed-off-by: default avatarPavel Pisa <pisa@cmp.felk.cvut.cz>
parent f6124d88
No related branches found
No related tags found
No related merge requests found
*.o
*.srec
depend
malloc-test
ARCH=riscv64-unknown-elf
#ARCH=riscv64-linux-gnu
SOURCES = malloc-test.c
TARGET_EXE = malloc-test
SOURCES += qtrvsim_sys_stub.c crt0local.S
LOADLIBES += -lc
CC=$(ARCH)-gcc
CXX=$(ARCH)-g++
AS=$(ARCH)-as
LD=$(ARCH)-ld
OBJCOPY=$(ARCH)-objcopy
ARCHFLAGS += -mabi=ilp32
ARCHFLAGS += -march=rv32im
ARCHFLAGS += -fno-lto
#ARCHFLAGS += -mabi=lp64
#ARCHFLAGS += -march=rv64imac
CFLAGS += -ggdb -Os -Wall
CXXFLAGS+= -ggdb -Os -Wall
AFLAGS += -ggdb
LDFLAGS += -ggdb
LDFLAGS += -nostartfiles
LDFLAGS += -nostdlib
LDFLAGS += -static
#LDFLAGS += -specs=/opt/musl/riscv64-linux-gnu/lib/musl-gcc.specs
LOADLIBES += -lgcc
CFLAGS += $(ARCHFLAGS)
CXXFLAGS+= $(ARCHFLAGS)
AFLAGS += $(ARCHFLAGS)
LDFLAGS += $(ARCHFLAGS)
OBJECTS += $(filter %.o,$(SOURCES:%.S=%.o))
OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o))
OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o))
all : default
.PHONY : default clean dep all run_test
%.o:%.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@
%.o:%.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
%.o:%.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $<
%.s:%.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $< -o $@
default : $(TARGET_EXE)
#default : run_test
$(TARGET_EXE) : $(OBJECTS)
$(CC) $(LDFLAGS) $^ $(LOADLIBES) -o $@
dep: depend
depend: $(SOURCES) $(glob *.h)
echo '# autogenerated dependencies' > depend
ifneq ($(filter %.S,$(SOURCES)),)
$(CC) -D__ASSEMBLY__ $(AFLAGS) -w -E -M $(filter %.S,$(SOURCES)) \
>> depend
endif
ifneq ($(filter %.c,$(SOURCES)),)
$(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \
>> depend
endif
ifneq ($(filter %.cpp,$(SOURCES)),)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \
>> depend
endif
clean:
rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) depend
run_test: $(TARGET_EXE)
qtrvsim_cli --pipelined \
--dump-cycles $< \
--serout serial_port.out
# --serin serial_port.in \
-include depend
/* minimal replacement of crt0.o which is else provided by C library */
.globl main
.globl _start
.globl __start
.globl _heap_stack_start
.globl _heap_stack_end
.option norelax
.text
__start:
_start:
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, _heap_stack_end
addi a0, zero, 0
addi a1, zero, 0
jal main
quit:
addi a0, zero, 0
addi a7, zero, 93 /* SYS_exit */
ecall
loop: ebreak
beq zero, zero, loop
.bss
_heap_stack_start:
.skip 16384
_heap_stack_end:
.end _start
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#define CHUNK_COUNT 5
static inline
uint32_t fill_value(int chunk, int idx)
{
return (chunk * 77) ^ idx * 55;
}
static inline
size_t chunk_len(int chunk)
{
return chunk * 137;
}
int main(void)
{
uint32_t *chunks[CHUNK_COUNT];
printf("Starting malloc-test\n");
for (int chunk = 0; chunk < CHUNK_COUNT; chunk++) {
size_t len = chunk_len(chunk);
uint32_t *p = malloc(len * sizeof(uint32_t));
chunks[chunk] = p;
if (!p) {
printf("FAILED alloc of chunk %d, len %d\n", chunk, (int)len);
exit(1);
} else {
printf("Alloc of chunk %d, len %d address %p\n", chunk, (int)len, p);
}
while (len--) {
*(p++) = fill_value(chunk, len);
}
}
for (int chunk = 0; chunk < CHUNK_COUNT; chunk++) {
size_t len = chunk_len(chunk);
uint32_t *p = chunks[chunk];
while (len--) {
if (*(p++) != fill_value(chunk, len)) {
printf("FAILED chunk %d, data compare\n", chunk);
exit(1);
}
}
printf("Chunk %d check OK\n", chunk);
}
printf("Succeed malloc-test\n");
return 0;
}
// ******************************************************************
// QtRvSim emulator https://github.com/cvut/qtrvsim support filees
//
// qtrvsim_regs.h - definition of the QtRvSim simulator peripherals
//
// (C) Copyright 2019 - 2022 by Pavel Pisa
// e-mail: pisa@cmp.felk.cvut.cz
// homepage: http://cmp.felk.cvut.cz/~pisa
// license: any combination of GPL, LGPL, MPL or BSD licenses
//
// ******************************************************************
#ifndef QTRVSIM_REGS_H
#define QTRVSIM_REGS_H
// Serial port/terminal registers
// There is mirror of this region at address 0xffff0000
// to match QtSpim and Mars emulators
#define SERIAL_PORT_BASE, 0xffffc000 // base address of serial port region
#define SERP_RX_ST_REG, 0xffffc000 // Receiver status register
#define SERP_RX_ST_REG_o, 0x0000 // Offset of RX_ST_REG
#define SERP_RX_ST_REG_READY_m, 0x1 // Data byte is ready to be read
#define SERP_RX_ST_REG_IE_m, 0x2 // Enable Rx ready interrupt
#define SERP_RX_DATA_REG, 0xffffc004 // Received data byte in 8 LSB bits
#define SERP_RX_DATA_REG_o, 0x0004 // Offset of RX_DATA_REG
#define SERP_TX_ST_REG, 0xffffc008 // Transmitter status register
#define SERP_TX_ST_REG_o, 0x0008 // Offset of TX_ST_REG
#define SERP_TX_ST_REG_READY_m, 0x1 // Transmitter can accept next byte
#define SERP_TX_ST_REG_IE_m, 0x2 // Enable Tx ready interrupt
#define SERP_TX_DATA_REG, 0xffffc00c // Write word to send 8 LSB bits to terminal
#define SERP_TX_DATA_REG_o, 0x000c // Offset of TX_DATA_REG
// Memory mapped peripheral for dial knobs input,
// LED and RGB LEDs output designed to match
// MZ_APO education Zynq based board developed
// by Petr Porazil and Pavel Pisa at PiKRON.com company
#define SPILED_REG_BASE 0xffffc100 // base of SPILED port region
#define SPILED_REG_LED_LINE 0xffffc104 // 32 bit word mapped as output
#define SPILED_REG_LED_LINE_o 0x0004 // Offset of the LED_LINE
#define SPILED_REG_LED_RGB1 0xffffc110 // RGB LED 1 color components
#define SPILED_REG_LED_RGB1_o 0x0010 // Offset of LED_RGB1
#define SPILED_REG_LED_RGB2 0xffffc114 // RGB LED 2 color components
#define SPILED_REG_LED_RGB2_o 0x0014 // Offset of LED_RGB2
#define SPILED_REG_KNOBS_8BIT 0xffffc124 // Three 8 bit knob values
#define SPILED_REG_KNOBS_8BIT_o 0x0024 // Offset of KNOBS_8BIT
// The simple 16-bit per pixel (RGB565) frame-buffer
// display size is 480 x 320 pixel
// Pixel format RGB565 expect
// bits 11 .. 15 red component
// bits 5 .. 10 green component
// bits 0 .. 4 blue component
#define LCD_FB_START 0xffe00000
#define LCD_FB_END 0xffe4afff
// Mapping of interrupts
// Irq number Cause/Status Bit Source
// 2 / HW0 10 Serial port ready to accept character to Tx
// 3 / HW1 11 There is received character ready to be read
// 7 / HW5 15 Counter reached value in Compare register
#endif /*QTRVSIM_REGS_H*/
/* Support files for GNU libc. Files in the system namespace go here.
Files in the C namespace (ie those that do not start with an
underscore) go in .c. */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h>
#include <reent.h>
#include "qtrvsim_unistd.h"
#define UNUSED_PARAM(symbol) ((void)(symbol))
/* Register name - works in collusion with the linker. */
register char * stack_ptr asm ("sp");
int _read(int file, char *ptr, int len);
int
_read (int file,
char * ptr,
int len)
{
register int __a7 asm("a7") = __NR_read;
register int __a0 asm("a0") = file;
register char * __a1 asm("a1") = ptr;
register int __a2 asm("a2") = len;
__asm__ volatile (
"ecall\n\t"
: "=r" (__a0)
: "r" (__a7), "r" (__a0), "r" (__a1), "r"(__a2)
: );
return __a0 < 0 ? -1: __a0;
}
int _write(int file, const char *ptr, int len);
int
_write (int file,
const char * ptr,
int len)
{
register int __a7 asm("a7") = __NR_write;
register int __a0 asm("a0") = file;
register const char * __a1 asm("a1") = ptr;
register int __a2 asm("a2") = len;
__asm__ volatile (
"ecall\n\t"
: "=r" (__a0)
: "r" (__a7), "r" (__a0), "r" (__a1), "r"(__a2)
: );
return __a0 < 0 ? -1: __a0;
}
int
_lseek (int file,
int pos,
int dir)
{
UNUSED_PARAM(file);
UNUSED_PARAM(pos);
UNUSED_PARAM(dir);
return -1;
}
int _openat(int fd, const char *path, int flags, ...);
int
_openat (int fd, const char * path,
int flags,
...)
{
register int __a7 asm("a7") = __NR_openat;
// use fd = -100 for normal open behaviour. Full openat not supported.
register int __a0 asm("a0") = fd;
register const char * __a1 asm("a1") = path;
register int __a2 asm("a2") = flags;
register int __a3 asm("a3");
if (flags & O_CREAT) {
va_list list;
va_start(list, flags);
__a3 = va_arg(list, int);
va_end(list);
}
__asm__ volatile (
"ecall\n\t"
: "=r" (__a0)
: "r" (__a7), "r" (__a0), "r" (__a1), "r"(__a2), "r"(__a3)
: );
return __a0 < 0 ? -1: __a0;
}
int _close(int file);
int
_close (int file)
{
register int __a7 asm("a7") = __NR_close;
register int __a0 asm("a0") = file;
__asm__ volatile (
"ecall\n\t"
: "=r" (__a0)
: "r" (__a7), "r" (__a0)
: );
return __a0 < 0 ? -1: __a0;
}
void _exit(int n);
void
_exit (int n)
{
register int __a7 asm("a7") = __NR_exit;
register int __a0 asm("a0") = n;
while(1) __asm__ volatile (
"ecall\n\t"
:
: "r" (__a7), "r" (__a0)
: );
}
void abort(void);
void abort(void)
{
while(1) __asm__ volatile (
"ebreak\n\t"
:
:
: );
}
int _kill(int n, int m);
int
_kill (int n, int m)
{
UNUSED_PARAM(n);
UNUSED_PARAM(m);
return -1;
}
int _getpid(void);
int
_getpid (void)
{
return 1;
}
void *_sbrk(ptrdiff_t incr);
void *
_sbrk (ptrdiff_t incr)
{
extern char _heap_stack_start;
static char *heap_end;
char * prev_heap_end;
incr=(incr+3) & ~3;
if (heap_end == NULL)
heap_end = & _heap_stack_start;
prev_heap_end = heap_end;
if ((heap_end + incr > stack_ptr) && (&_heap_stack_start < stack_ptr))
{
/* Some of the libstdc++-v3 tests rely upon detecting
out of memory errors, so do not abort here. */
#if 1
extern void abort (void);
_write (1, "_sbrk: Heap and stack collision\n", 32);
abort ();
#else
errno = ENOMEM;
return (caddr_t) -1;
#endif
}
heap_end += incr;
return /*(caddr_t)*/ prev_heap_end;
}
int _fstat(int file, struct stat *st);
int
_fstat (int file, struct stat * st)
{
UNUSED_PARAM(file);
UNUSED_PARAM(st);
return -1;
}
int _stat (const char *fname, struct stat *st);
int _stat (const char *fname, struct stat *st)
{
UNUSED_PARAM(fname);
UNUSED_PARAM(st);
return -1;
}
int _link(const char *path1, const char *path2);
int
_link (const char *path1,
const char *path2)
{
UNUSED_PARAM(path1);
UNUSED_PARAM(path2);
return -1;
}
int _unlink(const char *path);
int
_unlink (const char *path)
{
UNUSED_PARAM(path);
return -1;
}
void _raise(void);
void
_raise (void)
{
return;
}
int _gettimeofday(struct timeval *tp, struct timezone *tzp);
int
_gettimeofday (struct timeval *tp,
struct timezone *tzp)
{
if(tp)
{
tp->tv_sec = 0;
tp->tv_usec = 0;
}
/* Return fixed data for the timezone. */
if (tzp)
{
tzp->tz_minuteswest = 0;
tzp->tz_dsttime = 0;
}
return 0;
}
/* Return a clock that ticks at 100Hz. */
clock_t _times(struct tms *tp);
clock_t
_times (struct tms * tp)
{
clock_t timeval = 0;
if (tp)
{
tp->tms_utime = timeval; /* user time */
tp->tms_stime = 0; /* system time */
tp->tms_cutime = 0; /* user time, children */
tp->tms_cstime = 0; /* system time, children */
}
return timeval;
};
int isatty(int fd);
int
isatty (int fd)
{
UNUSED_PARAM(fd);
return 1;
}
int _system(const char *s);
int
_system (const char *s)
{
UNUSED_PARAM(s);
return -1;
}
int _rename(const char *oldpath, const char *newpath);
int
_rename (const char * oldpath, const char * newpath)
{
UNUSED_PARAM(oldpath);
UNUSED_PARAM(newpath);
return -1;
}
/* extern (.*) ([^ ]*) _PARAMS \(\(struct _reent \*(,*)(.*)\)\); */
/* \1 \2 (struct _reent *\3\4) { return \2(\4);} */
struct _reent;
int _close_r(struct _reent *reent, int file)
{ UNUSED_PARAM(reent); return _close(file);}
/*
int _fcntl_r(struct _reent *, int, int, int)
{ return _fcntl( int, int, int);}
*/
int _fstat_r(struct _reent *reent, int file, struct stat *st);
int _fstat_r(struct _reent *reent, int file, struct stat *st)
{ UNUSED_PARAM(reent); return _fstat(file, st);}
int _getpid_r(struct _reent *reent);
int _getpid_r(struct _reent *reent)
{ UNUSED_PARAM(reent); return _getpid();}
int _kill_r(struct _reent *reent, int n, int m);
int _kill_r(struct _reent *reent, int n, int m)
{ UNUSED_PARAM(reent); return _kill(n, m);}
int _link_r(struct _reent *reent, const char *path1, const char *path2);
int _link_r(struct _reent *reent, const char *path1, const char *path2)
{ UNUSED_PARAM(reent); return _link(path1, path2);}
_off_t _lseek_r(struct _reent *reent, int file, _off_t pos, int dir);
_off_t _lseek_r(struct _reent *reent, int file, _off_t pos, int dir)
{ UNUSED_PARAM(reent); return _lseek(file, pos, dir);}
int _open_r(struct _reent *reent, const char *path, int flags, int opts);
int _open_r(struct _reent *reent, const char *path, int flags, int opts)
{ UNUSED_PARAM(reent); return _openat(-100, path, flags, opts);}
int _openat_r(struct _reent *reent, int fd, const char *path, int flags, int opts);
int _openat_r(struct _reent *reent, int fd, const char *path, int flags, int opts)
{ UNUSED_PARAM(reent); return _openat(fd, path, flags, opts);}
_ssize_t _read_r(struct _reent *reent, int file, void *ptr, size_t len);
_ssize_t _read_r(struct _reent *reent, int file, void *ptr, size_t len)
{ UNUSED_PARAM(reent); return _read(file, ptr, len);}
void *_sbrk_r(struct _reent *reent, ptrdiff_t incr);
void *_sbrk_r(struct _reent *reent, ptrdiff_t incr)
{ UNUSED_PARAM(reent); return _sbrk(incr);}
int _stat_r(struct _reent *reent, const char *path, struct stat *st);
int _stat_r(struct _reent *reent, const char *path, struct stat *st)
{ UNUSED_PARAM(reent); return _stat(path, st);}
int _unlink_r(struct _reent *reent, const char *path);
int _unlink_r(struct _reent *reent, const char *path)
{ UNUSED_PARAM(reent); return _unlink(path);}
_ssize_t _write_r(struct _reent *reent, int file, const void *ptr, size_t len);
_ssize_t _write_r(struct _reent *reent, int file, const void *ptr, size_t len)
{ UNUSED_PARAM(reent); return _write(file, ptr, len);}
/* FIXME: TDK added dummy functions. Need to implement. */
int _isatty(int fd);
int _isatty(int fd)
{
UNUSED_PARAM(fd);
return -1;
}
int _swistat(int fd, struct stat *st);
int _swistat(int fd, struct stat *st)
{
UNUSED_PARAM(fd);
UNUSED_PARAM(st);
return -1;
}
/* Return a clock that ticks at 100Hz. */
clock_t _clock(void);
clock_t _clock(void)
{
clock_t timeval=0;
return timeval;
}
int _swiclose(int fh);
int _swiclose(int fh)
{
UNUSED_PARAM(fh);
return -1;
}
int _swiopen(const char *path, int flags);
int _swiopen(const char *path, int flags)
{
UNUSED_PARAM(path);
UNUSED_PARAM(flags);
return -1;
}
int _swiwrite(int fh, char *ptr, int len);
int _swiwrite(int fh, char *ptr, int len)
{
UNUSED_PARAM(fh);
UNUSED_PARAM(ptr);
UNUSED_PARAM(len);
return -1;
}
int _swilseek(int fd, int ptr, int dir);
int _swilseek(int fd, int ptr, int dir)
{
UNUSED_PARAM(fd);
UNUSED_PARAM(ptr);
UNUSED_PARAM(dir);
return -1;
}
int _swiread(int fh, char *ptr, int len);
int _swiread(int fh, char *ptr, int len)
{
UNUSED_PARAM(fh);
UNUSED_PARAM(ptr);
UNUSED_PARAM(len);
return -1;
}
void initialise_monitor_handles(void);
void initialise_monitor_handles(void)
{
}
// ******************************************************************
// QtRvSim emulator https://github.com/cvut/qtrvsim support filees
//
// qtrvsim_unistd.h - definition of the QtRvSim syscall numbers
//
// (C) Copyright 2019 - 2022 by Pavel Pisa
// e-mail: pisa@cmp.felk.cvut.cz
// homepage: http://cmp.felk.cvut.cz/~pisa
// license: any combination of GPL, LGPL, MPL or BSD licenses
//
// ******************************************************************
#ifndef QTRVSIM_UNISTD_H
#define QTRVSIM_UNISTD_H
// Linux kernel compatible system calls subset
#define __NR_exit 93 // void exit(int status)
#define __NR_read 63 // ssize_t read(int fd, void *buf, size_t count)
#define __NR_write 64 // ssize_t write(int fd, const void *buf, size_t count)
#define __NR_close 57 // int close(int fd)
#define __NR_openat 56 // int openat(int fd, const char *pathname, int flags, mode_t mode)
// use fd = -100 for normal open behaviour. Full openat not supported.
#define __NR_brk 214 // void * brk(void *addr)
#define __NR_ftruncate64 46 // int ftruncate64(int fd, off_t length)
#define __NR_readv 65 // ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
#define __NR_writev 66 // ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
#endif /*QTRVSIM_UNISTD_H*/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment