diff options
Diffstat (limited to 'scripts/cxxdemo')
-rw-r--r-- | scripts/cxxdemo/.gitignore | 9 | ||||
-rw-r--r-- | scripts/cxxdemo/Makefile | 38 | ||||
-rw-r--r-- | scripts/cxxdemo/firmware.cc | 87 | ||||
-rw-r--r-- | scripts/cxxdemo/hex8tohex32.py | 34 | ||||
-rw-r--r-- | scripts/cxxdemo/start.S | 52 | ||||
-rw-r--r-- | scripts/cxxdemo/start.ld | 5 | ||||
-rw-r--r-- | scripts/cxxdemo/syscalls.c | 95 | ||||
-rw-r--r-- | scripts/cxxdemo/testbench.v | 114 |
8 files changed, 434 insertions, 0 deletions
diff --git a/scripts/cxxdemo/.gitignore b/scripts/cxxdemo/.gitignore new file mode 100644 index 0000000..47e6b5c --- /dev/null +++ b/scripts/cxxdemo/.gitignore @@ -0,0 +1,9 @@ +firmware.d +firmware.elf +firmware.hex +firmware32.hex +firmware.o +syscalls.o +testbench.vvp +testbench.vcd +start.elf diff --git a/scripts/cxxdemo/Makefile b/scripts/cxxdemo/Makefile new file mode 100644 index 0000000..2d95019 --- /dev/null +++ b/scripts/cxxdemo/Makefile @@ -0,0 +1,38 @@ +RISCV_TOOLS_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf- +CXX = $(RISCV_TOOLS_PREFIX)g++ +CC = $(RISCV_TOOLS_PREFIX)gcc +AS = $(RISCV_TOOLS_PREFIX)gcc +CXXFLAGS = -MD -Os -Wall -std=c++11 +CCFLAGS = -MD -Os -Wall -std=c++11 +LDFLAGS = -Wl,--gc-sections +LDLIBS = -lstdc++ + +test: testbench.vvp firmware32.hex + vvp -N testbench.vvp + +testbench.vvp: testbench.v ../../picorv32.v + iverilog -o testbench.vvp testbench.v ../../picorv32.v + chmod -x testbench.vvp + +firmware32.hex: firmware.elf start.elf hex8tohex32.py + $(RISCV_TOOLS_PREFIX)objcopy -O verilog start.elf start.tmp + $(RISCV_TOOLS_PREFIX)objcopy -O verilog firmware.elf firmware.tmp + cat start.tmp firmware.tmp > firmware.hex + python3 hex8tohex32.py firmware.hex > firmware32.hex + rm -f start.tmp firmware.tmp + +firmware.elf: firmware.o syscalls.o + $(CC) $(LDFLAGS) -o $@ $^ -T ../../firmware/riscv.ld $(LDLIBS) + chmod -x firmware.elf + +start.elf: start.S start.ld + $(CC) -nostdlib -o start.elf start.S -T start.ld $(LDLIBS) + chmod -x start.elf + +clean: + rm -f *.o *.d *.tmp start.elf + rm -f firmware.elf firmware.hex firmware32.hex + rm -f testbench.vvp testbench.vcd + +-include *.d +.PHONY: test clean diff --git a/scripts/cxxdemo/firmware.cc b/scripts/cxxdemo/firmware.cc new file mode 100644 index 0000000..638c0dd --- /dev/null +++ b/scripts/cxxdemo/firmware.cc @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <iostream> +#include <vector> +#include <algorithm> + +class ExampleBaseClass +{ +public: + ExampleBaseClass() { + std::cout << "ExampleBaseClass()" << std::endl; + } + + virtual ~ExampleBaseClass() { + std::cout << "~ExampleBaseClass()" << std::endl; + } + + virtual void print_something_virt() { + std::cout << "ExampleBaseClass::print_something_virt()" << std::endl; + } + + void print_something_novirt() { + std::cout << "ExampleBaseClass::print_something_novirt()" << std::endl; + } +}; + +class ExampleSubClass : public ExampleBaseClass +{ +public: + ExampleSubClass() { + std::cout << "ExampleSubClass()" << std::endl; + } + + virtual ~ExampleSubClass() { + std::cout << "~ExampleSubClass()" << std::endl; + } + + virtual void print_something_virt() { + std::cout << "ExampleSubClass::print_something_virt()" << std::endl; + } + + void print_something_novirt() { + std::cout << "ExampleSubClass::print_something_novirt()" << std::endl; + } +}; + +int main() +{ + printf("Hello World, C!\n"); + + std::cout << "Hello World, C++!" << std::endl; + + ExampleBaseClass *obj = new ExampleBaseClass; + obj->print_something_virt(); + obj->print_something_novirt(); + delete obj; + + obj = new ExampleSubClass; + obj->print_something_virt(); + obj->print_something_novirt(); + delete obj; + + std::vector<unsigned int> some_ints; + some_ints.push_back(0x48c9b3e4); + some_ints.push_back(0x79109b6a); + some_ints.push_back(0x16155039); + some_ints.push_back(0xa3635c9a); + some_ints.push_back(0x8d2f4702); + some_ints.push_back(0x38d232ae); + some_ints.push_back(0x93924a17); + some_ints.push_back(0x62b895cc); + some_ints.push_back(0x6130d459); + some_ints.push_back(0x837c8b44); + some_ints.push_back(0x3d59b4fe); + some_ints.push_back(0x444914d8); + some_ints.push_back(0x3a3dc660); + some_ints.push_back(0xe5a121ef); + some_ints.push_back(0xff00866d); + some_ints.push_back(0xb843b879); + + std::sort(some_ints.begin(), some_ints.end()); + + for (auto n : some_ints) + std::cout << std::hex << n << std::endl; + + std::cout << "All done." << std::endl; + return 0; +} diff --git a/scripts/cxxdemo/hex8tohex32.py b/scripts/cxxdemo/hex8tohex32.py new file mode 100644 index 0000000..ae44101 --- /dev/null +++ b/scripts/cxxdemo/hex8tohex32.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import fileinput +import itertools + +ptr = 0 +data = [] + +def write_data(): + if len(data) != 0: + print("@%08x" % (ptr >> 2)) + while len(data) % 4 != 0: + data.append(0) + for word_bytes in zip(*([iter(data)]*4)): + print("".join(["%02x" % b for b in reversed(word_bytes)])) + +for line in fileinput.input(): + if line.startswith("@"): + addr = int(line[1:], 16) + if addr > ptr+4: + write_data() + ptr = addr + data = [] + while ptr % 4 != 0: + data.append(0) + ptr -= 1 + else: + while ptr + len(data) < addr: + data.append(0) + else: + data += [int(tok, 16) for tok in line.split()] + +write_data() + diff --git a/scripts/cxxdemo/start.S b/scripts/cxxdemo/start.S new file mode 100644 index 0000000..f872a14 --- /dev/null +++ b/scripts/cxxdemo/start.S @@ -0,0 +1,52 @@ +.section .text +.global _ftext +.global _pvstart + +_pvstart: +/* zero-initialize all registers */ +addi x1, zero, 0 +addi x2, zero, 0 +addi x3, zero, 0 +addi x4, zero, 0 +addi x5, zero, 0 +addi x6, zero, 0 +addi x7, zero, 0 +addi x8, zero, 0 +addi x9, zero, 0 +addi x10, zero, 0 +addi x11, zero, 0 +addi x12, zero, 0 +addi x13, zero, 0 +addi x14, zero, 0 +addi x15, zero, 0 +addi x16, zero, 0 +addi x17, zero, 0 +addi x18, zero, 0 +addi x19, zero, 0 +addi x20, zero, 0 +addi x21, zero, 0 +addi x22, zero, 0 +addi x23, zero, 0 +addi x24, zero, 0 +addi x25, zero, 0 +addi x26, zero, 0 +addi x27, zero, 0 +addi x28, zero, 0 +addi x29, zero, 0 +addi x30, zero, 0 +addi x31, zero, 0 + +/* set stack pointer */ +lui sp, %hi(4*1024*1024) +addi sp, sp, %lo(4*1024*1024) + +/* push zeros on the stack for argc and argv */ +/* (stack is aligned to 16 bytes in riscv calling convention) */ +addi sp,sp,-16 +sw zero,0(sp) +sw zero,4(sp) +sw zero,8(sp) +sw zero,12(sp) + +/* jump to libc init */ +j _ftext diff --git a/scripts/cxxdemo/start.ld b/scripts/cxxdemo/start.ld new file mode 100644 index 0000000..773eee2 --- /dev/null +++ b/scripts/cxxdemo/start.ld @@ -0,0 +1,5 @@ +SECTIONS { +. = 0x00000000; +.text : { *(.text) } +_ftext = 0x00010000; +} diff --git a/scripts/cxxdemo/syscalls.c b/scripts/cxxdemo/syscalls.c new file mode 100644 index 0000000..8ea84ca --- /dev/null +++ b/scripts/cxxdemo/syscalls.c @@ -0,0 +1,95 @@ +// An extremely minimalist syscalls.c for newlib +// Based on riscv newlib libgloss/riscv/sys_*.c +// Written by Clifford Wolf. + +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n" + +asm ( + ".text\n" + ".align 2\n" + UNIMPL_FUNC(_open) + UNIMPL_FUNC(_openat) + UNIMPL_FUNC(_lseek) + UNIMPL_FUNC(_stat) + UNIMPL_FUNC(_lstat) + UNIMPL_FUNC(_fstatat) + UNIMPL_FUNC(_isatty) + UNIMPL_FUNC(_access) + UNIMPL_FUNC(_faccessat) + UNIMPL_FUNC(_link) + UNIMPL_FUNC(_unlink) + UNIMPL_FUNC(_execve) + UNIMPL_FUNC(_getpid) + UNIMPL_FUNC(_fork) + UNIMPL_FUNC(_kill) + UNIMPL_FUNC(_wait) + UNIMPL_FUNC(_times) + UNIMPL_FUNC(_gettimeofday) + UNIMPL_FUNC(_ftime) + UNIMPL_FUNC(_utime) + UNIMPL_FUNC(_chown) + UNIMPL_FUNC(_chmod) + UNIMPL_FUNC(_chdir) + UNIMPL_FUNC(_getcwd) + UNIMPL_FUNC(_sysconf) + "j unimplemented_syscall\n" +); + +void unimplemented_syscall() +{ + const char *p = "Unimplemented system call called!\n"; + while (*p) + *(volatile int*)0x10000000 = *(p++); + asm volatile ("ebreak"); + __builtin_unreachable(); +} + +ssize_t _read(int file, void *ptr, size_t len) +{ + // always EOF + return 0; +} + +ssize_t _write(int file, const void *ptr, size_t len) +{ + const void *eptr = ptr + len; + while (ptr != eptr) + *(volatile int*)0x10000000 = *(char*)(ptr++); + return len; +} + +int _close(int file) +{ + // close is called before _exit() + return 0; +} + +int _fstat(int file, struct stat *st) +{ + // fstat is called during libc startup + errno = ENOENT; + return -1; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern unsigned char _end[]; // Defined by linker + static unsigned long heap_end; + + if (heap_end == 0) + heap_end = (long)_end; + + heap_end += incr; + return (void *)(heap_end - incr); +} + +void _exit(int exit_status) +{ + asm volatile ("ebreak"); + __builtin_unreachable(); +} + diff --git a/scripts/cxxdemo/testbench.v b/scripts/cxxdemo/testbench.v new file mode 100644 index 0000000..ac9af70 --- /dev/null +++ b/scripts/cxxdemo/testbench.v @@ -0,0 +1,114 @@ +`timescale 1 ns / 1 ps +`undef VERBOSE_MEM +`undef WRITE_VCD +`undef MEM8BIT + +module testbench; + reg clk = 1; + reg resetn = 0; + wire trap; + + always #5 clk = ~clk; + + initial begin + repeat (100) @(posedge clk); + resetn <= 1; + end + + wire mem_valid; + wire mem_instr; + reg mem_ready; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [3:0] mem_wstrb; + reg [31:0] mem_rdata; + + picorv32 #( + .COMPRESSED_ISA(1) + ) uut ( + .clk (clk ), + .resetn (resetn ), + .trap (trap ), + .mem_valid (mem_valid ), + .mem_instr (mem_instr ), + .mem_ready (mem_ready ), + .mem_addr (mem_addr ), + .mem_wdata (mem_wdata ), + .mem_wstrb (mem_wstrb ), + .mem_rdata (mem_rdata ) + ); + + localparam MEM_SIZE = 4*1024*1024; +`ifdef MEM8BIT + reg [7:0] memory [0:MEM_SIZE-1]; + initial $readmemh("firmware.hex", memory); +`else + reg [31:0] memory [0:MEM_SIZE/4-1]; + initial $readmemh("firmware32.hex", memory); +`endif + + always @(posedge clk) begin + mem_ready <= 0; + if (mem_valid && !mem_ready) begin + mem_ready <= 1; + mem_rdata <= 'bx; + case (1) + mem_addr < MEM_SIZE: begin +`ifdef MEM8BIT + if (|mem_wstrb) begin + if (mem_wstrb[0]) memory[mem_addr + 0] <= mem_wdata[ 7: 0]; + if (mem_wstrb[1]) memory[mem_addr + 1] <= mem_wdata[15: 8]; + if (mem_wstrb[2]) memory[mem_addr + 2] <= mem_wdata[23:16]; + if (mem_wstrb[3]) memory[mem_addr + 3] <= mem_wdata[31:24]; + end else begin + mem_rdata <= {memory[mem_addr+3], memory[mem_addr+2], memory[mem_addr+1], memory[mem_addr]}; + end +`else + if (|mem_wstrb) begin + if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0]; + if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8]; + if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16]; + if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24]; + end else begin + mem_rdata <= memory[mem_addr >> 2]; + end +`endif + end + mem_addr == 32'h 1000_0000: begin + $write("%c", mem_wdata[7:0]); + end + endcase + end + if (mem_valid && mem_ready) begin +`ifdef VERBOSE_MEM + if (|mem_wstrb) + $display("WR: ADDR=%x DATA=%x MASK=%b", mem_addr, mem_wdata, mem_wstrb); + else + $display("RD: ADDR=%x DATA=%x%s", mem_addr, mem_rdata, mem_instr ? " INSN" : ""); +`endif + if (^mem_addr === 1'bx || + (mem_wstrb[0] && ^mem_wdata[ 7: 0] == 1'bx) || + (mem_wstrb[1] && ^mem_wdata[15: 8] == 1'bx) || + (mem_wstrb[2] && ^mem_wdata[23:16] == 1'bx) || + (mem_wstrb[3] && ^mem_wdata[31:24] == 1'bx)) begin + $display("CRITICAL UNDEF MEM TRANSACTION"); + $finish; + end + end + end + +`ifdef WRITE_VCD + initial begin + $dumpfile("testbench.vcd"); + $dumpvars(0, testbench); + end +`endif + + always @(posedge clk) begin + if (resetn && trap) begin + repeat (10) @(posedge clk); + $display("TRAP"); + $finish; + end + end +endmodule |