aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-11-04 01:12:37 +0100
committerClifford Wolf <clifford@clifford.at>2015-11-04 12:55:33 +0100
commit4015d4a5ab90f9b225275325d52262523c3cfc31 (patch)
treea1bc875c5705859990b13e3c146a7a2198f50cc8 /scripts
parent8d9f048785a4972fee5817cc64ddb2097034b122 (diff)
downloadpicorv32-4015d4a5ab90f9b225275325d52262523c3cfc31.tar.gz
picorv32-4015d4a5ab90f9b225275325d52262523c3cfc31.zip
Added scripts/cxxdemo/
Diffstat (limited to 'scripts')
-rw-r--r--scripts/cxxdemo/.gitignore8
-rw-r--r--scripts/cxxdemo/Makefile36
-rw-r--r--scripts/cxxdemo/firmware.cc37
-rw-r--r--scripts/cxxdemo/start.S48
-rw-r--r--scripts/cxxdemo/start.ld5
-rw-r--r--scripts/cxxdemo/syscalls.c469
-rw-r--r--scripts/cxxdemo/testbench.v95
7 files changed, 698 insertions, 0 deletions
diff --git a/scripts/cxxdemo/.gitignore b/scripts/cxxdemo/.gitignore
new file mode 100644
index 0000000..3c67fe4
--- /dev/null
+++ b/scripts/cxxdemo/.gitignore
@@ -0,0 +1,8 @@
+firmware.d
+firmware.elf
+firmware.hex
+firmware.o
+syscalls.o
+testbench.exe
+testbench.vcd
+start.elf
diff --git a/scripts/cxxdemo/Makefile b/scripts/cxxdemo/Makefile
new file mode 100644
index 0000000..3d10104
--- /dev/null
+++ b/scripts/cxxdemo/Makefile
@@ -0,0 +1,36 @@
+CXX = riscv32-unknown-elf-g++
+CC = riscv32-unknown-elf-gcc
+AS = riscv32-unknown-elf-gcc
+CXXFLAGS = -MD -Os -Wall -std=c++11
+CCFLAGS = -MD -Os -Wall -std=c++11
+LDFLAGS = -Wl,--gc-sections
+LDLIBS = -lstdc++
+
+test: testbench.exe firmware.hex
+ vvp -N testbench.exe
+
+testbench.exe: testbench.v ../../picorv32.v
+ iverilog -o testbench.exe testbench.v ../../picorv32.v
+ chmod -x testbench.exe
+
+firmware.hex: firmware.elf start.elf
+ riscv32-unknown-elf-objcopy -O verilog start.elf start.tmp
+ riscv32-unknown-elf-objcopy -O verilog firmware.elf firmware.tmp
+ cat start.tmp firmware.tmp > firmware.hex
+ rm -f start.tmp firmware.tmp
+
+firmware.elf: firmware.o syscalls.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(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
+ rm -f testbench.exe 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..e0bddf0
--- /dev/null
+++ b/scripts/cxxdemo/firmware.cc
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+int main()
+{
+ printf("Hello World, C!\n");
+
+ std::cout << "Hello World, C++!" << std::endl;
+
+ 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/start.S b/scripts/cxxdemo/start.S
new file mode 100644
index 0000000..33114cc
--- /dev/null
+++ b/scripts/cxxdemo/start.S
@@ -0,0 +1,48 @@
+.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 a zero on the stack */
+addi sp,sp,-4
+sw zero,0(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..16f791f
--- /dev/null
+++ b/scripts/cxxdemo/syscalls.c
@@ -0,0 +1,469 @@
+// Based on riscv newlib libgloss/riscv/machine/syscall.h
+// Changes by Clifford Wolf
+
+//========================================================================
+// syscalls.c : Newlib operating system interface
+//========================================================================
+// This is the maven implementation of the narrow newlib operating
+// system interface. It is based on the minimum stubs in the newlib
+// documentation, the error stubs in libnosys, and the previous scale
+// implementation. Please do not include any additional system calls or
+// other functions in this file. Additional header and source files
+// should be in the machine subdirectory.
+//
+// Here is a list of the functions which make up the operating system
+// interface. The file management instructions execute syscall assembly
+// instructions so that a proxy kernel (or the simulator) can marshal up
+// the request to the host machine. The process management functions are
+// mainly just stubs since for now maven only supports a single process.
+//
+// - File management functions
+// + open : (v) open file
+// + lseek : (v) set position in file
+// + read : (v) read from file
+// + write : (v) write to file
+// + fstat : (z) status of an open file
+// + stat : (z) status of a file by name
+// + close : (z) close a file
+// + link : (z) rename a file
+// + unlink : (z) remote file's directory entry
+//
+// - Process management functions
+// + execve : (z) transfer control to new proc
+// + fork : (z) create a new process
+// + getpid : (v) get process id
+// + kill : (z) send signal to child process
+// + wait : (z) wait for a child process
+//
+// - Misc functions
+// + isatty : (v) query whether output stream is a terminal
+// + times : (z) timing information for current process
+// + sbrk : (v) increase program data space
+// + _exit : (-) exit program without cleaning up files
+//
+// There are two types of system calls. Those which return a value when
+// everything is okay (marked with (v) in above list) and those which
+// return a zero when everything is okay (marked with (z) in above
+// list). On an error (ie. when the error flag is 1) the return value is
+// always an errno which should correspond to the numbers in
+// newlib/libc/include/sys/errno.h
+//
+// Note that really I think we are supposed to define versions of these
+// functions with an underscore prefix (eg. _open). This is what some of
+// the newlib documentation says, and all the newlib code calls the
+// underscore version. This is because technically I don't think we are
+// supposed to pollute the namespace with these function names. If you
+// define MISSING_SYSCALL_NAMES in xcc/src/newlib/configure.host
+// then xcc/src/newlib/libc/include/_syslist.h will essentially define
+// all of the underscore versions to be equal to the non-underscore
+// versions. I tried not defining MISSING_SYSCALL_NAMES, and newlib
+// compiled fine but libstdc++ complained about not being able to fine
+// write, read, etc. So for now we do not use underscores (and we do
+// define MISSING_SYSCALL_NAMES).
+//
+// See the newlib documentation for more information
+// http://sourceware.org/newlib/libc.html#Syscalls
+
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+
+//------------------------------------------------------------------------
+// environment
+//------------------------------------------------------------------------
+// A pointer to a list of environment variables and their values. For a
+// minimal environment, this empty list is adequate. We used to define
+// environ here but it is already defined in
+// xcc/src/newlib/libc/stdlib/environ.c so to avoid multiple definition
+// errors we have commented this out for now.
+//
+// char* __env[1] = { 0 };
+// char** environ = __env;
+
+//------------------------------------------------------------------------
+// open
+//------------------------------------------------------------------------
+// Open a file.
+
+int open(const char* name, int flags, int mode)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// openat
+//------------------------------------------------------------------------
+// Open file relative to given directory
+int openat(int dirfd, const char* name, int flags, int mode)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// lseek
+//------------------------------------------------------------------------
+// Set position in a file.
+
+off_t lseek(int file, off_t ptr, int dir)
+{
+ errno = ESPIPE;
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// read
+//----------------------------------------------------------------------
+// Read from a file.
+
+ssize_t read(int file, void *ptr, size_t len)
+{
+ // always EOF
+ return 0;
+}
+
+//------------------------------------------------------------------------
+// write
+//------------------------------------------------------------------------
+// Write to a file.
+
+ssize_t write(int file, const void *ptr, size_t len)
+{
+ unsigned int *p = (unsigned int*)0x10000000;
+ const void *eptr = ptr + len;
+ while (ptr != eptr)
+ *p = *(char*)(ptr++);
+ return len;
+}
+
+//------------------------------------------------------------------------
+// fstat
+//------------------------------------------------------------------------
+// Status of an open file. The sys/stat.h header file required is
+// distributed in the include subdirectory for this C library.
+
+int fstat(int file, struct stat *st)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// stat
+//------------------------------------------------------------------------
+// Status of a file (by name).
+
+int stat(const char *file, struct stat *st)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// lstat
+//------------------------------------------------------------------------
+// Status of a link (by name).
+
+int lstat(const char *file, struct stat *st)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// fstatat
+//------------------------------------------------------------------------
+// Status of a file (by name) in a given directory.
+
+int fstatat(int dirfd, const char *file, struct stat *st, int flags)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// access
+//------------------------------------------------------------------------
+// Permissions of a file (by name).
+
+int access(const char *file, int mode)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// faccessat
+//------------------------------------------------------------------------
+// Permissions of a file (by name) in a given directory.
+
+int faccessat(int dirfd, const char *file, int mode, int flags)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// close
+//------------------------------------------------------------------------
+// Close a file.
+
+int close(int file)
+{
+ // close is always ok
+ return 0;
+}
+
+//------------------------------------------------------------------------
+// link
+//------------------------------------------------------------------------
+// Establish a new name for an existing file.
+
+int link(const char *old_name, const char *new_name)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// unlink
+//------------------------------------------------------------------------
+// Remove a file's directory entry.
+
+int unlink(const char *name)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// execve
+//------------------------------------------------------------------------
+// Transfer control to a new process. Minimal implementation for a
+// system without processes from newlib documentation.
+
+int execve(const char *name, char *const argv[], char *const env[])
+{
+ errno = ENOMEM;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// fork
+//------------------------------------------------------------------------
+// Create a new process. Minimal implementation for a system without
+// processes from newlib documentation.
+
+int fork()
+{
+ errno = EAGAIN;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// getpid
+//------------------------------------------------------------------------
+// Get process id. This is sometimes used to generate strings unlikely
+// to conflict with other processes. Minimal implementation for a
+// system without processes just returns 1.
+
+int getpid()
+{
+ return 1;
+}
+
+//------------------------------------------------------------------------
+// kill
+//------------------------------------------------------------------------
+// Send a signal. Minimal implementation for a system without processes
+// just causes an error.
+
+int kill(int pid, int sig)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// wait
+//------------------------------------------------------------------------
+// Wait for a child process. Minimal implementation for a system without
+// processes just causes an error.
+
+int wait(int *status)
+{
+ errno = ECHILD;
+ return -1;
+}
+
+//------------------------------------------------------------------------
+// isatty
+//------------------------------------------------------------------------
+// Query whether output stream is a terminal. For consistency with the
+// other minimal implementations, which only support output to stdout,
+// this minimal implementation is suggested by the newlib docs.
+
+int isatty(int file)
+{
+ return 1;
+}
+
+//------------------------------------------------------------------------
+// times
+//------------------------------------------------------------------------
+// Timing information for current process. From
+// newlib/libc/include/sys/times.h the tms struct fields are as follows:
+//
+// - clock_t tms_utime : user clock ticks
+// - clock_t tms_stime : system clock ticks
+// - clock_t tms_cutime : children's user clock ticks
+// - clock_t tms_cstime : children's system clock ticks
+//
+// Since maven does not currently support processes we set both of the
+// children's times to zero. Eventually we might want to separately
+// account for user vs system time, but for now we just return the total
+// number of cycles since starting the program.
+
+clock_t times(struct tms *buf)
+{
+ // when called for the first time, initialize t0
+ static struct timeval t0;
+ if (t0.tv_sec == 0)
+ gettimeofday(&t0, 0);
+
+ struct timeval t;
+ gettimeofday(&t, 0);
+
+ long long utime = (t.tv_sec - t0.tv_sec) * 1000000 + (t.tv_usec - t0.tv_usec);
+ buf->tms_utime = utime * CLOCKS_PER_SEC / 1000000;
+ buf->tms_stime = buf->tms_cstime = buf->tms_cutime = 0;
+
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// gettimeofday
+//----------------------------------------------------------------------
+// Get the current time. Only relatively correct.
+
+int gettimeofday(struct timeval *tp, void *tzp)
+{
+ asm volatile ("sbreak");
+ __builtin_unreachable();
+}
+
+//----------------------------------------------------------------------
+// ftime
+//----------------------------------------------------------------------
+// Get the current time. Only relatively correct.
+
+int ftime(struct timeb *tp)
+{
+ tp->time = tp->millitm = 0;
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// utime
+//----------------------------------------------------------------------
+// Stub.
+
+int utime(const char *path, const struct utimbuf *times)
+{
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// chown
+//----------------------------------------------------------------------
+// Stub.
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// chmod
+//----------------------------------------------------------------------
+// Stub.
+
+int chmod(const char *path, mode_t mode)
+{
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// chdir
+//----------------------------------------------------------------------
+// Stub.
+
+int chdir(const char *path)
+{
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// getcwd
+//----------------------------------------------------------------------
+// Stub.
+
+char *getcwd(char *buf, size_t size)
+{
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// sysconf
+//----------------------------------------------------------------------
+// Get configurable system variables
+
+long sysconf(int name)
+{
+ switch (name) {
+ case _SC_CLK_TCK:
+ return CLOCKS_PER_SEC;
+ }
+
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// sbrk
+//----------------------------------------------------------------------
+// Increase program data space. As malloc and related functions depend
+// on this, it is useful to have a working implementation. The following
+// is suggested by the newlib docs and suffices for a standalone
+// system.
+
+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;
+
+ // if (syscall_errno(SYS_brk, heap_end + incr, 0, 0, 0) != heap_end + incr)
+ // return (void *)-1;
+
+ heap_end += incr;
+ return (void *)(heap_end - incr);
+}
+
+//------------------------------------------------------------------------
+// _exit
+//------------------------------------------------------------------------
+// Exit a program without cleaning up files.
+
+void _exit(int exit_status)
+{
+ asm volatile ("sbreak");
+ __builtin_unreachable();
+}
diff --git a/scripts/cxxdemo/testbench.v b/scripts/cxxdemo/testbench.v
new file mode 100644
index 0000000..b8bed17
--- /dev/null
+++ b/scripts/cxxdemo/testbench.v
@@ -0,0 +1,95 @@
+`timescale 1 ns / 1 ps
+`undef VERBOSE_MEM
+`undef WRITE_VCD
+
+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 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;
+ reg [7:0] memory [0:MEM_SIZE-1];
+ initial $readmemh("firmware.hex", memory);
+
+ 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
+ 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
+ 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