aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2018-10-19 13:04:41 +0200
committerGitHub <noreply@github.com>2018-10-19 13:04:41 +0200
commit3a6ac16259af8ae6bc6abf8ef1713152fa67f771 (patch)
tree83bdc0d24484fd69a1ee2ab27ddde358bd58aef4
parenta721bb0c6eb01084cf5f0701e0dcdf55f06bbe77 (diff)
parent82b44105a025cb611b4f641aebb1e585848a12a8 (diff)
downloadpicorv32-3a6ac16259af8ae6bc6abf8ef1713152fa67f771.tar.gz
picorv32-3a6ac16259af8ae6bc6abf8ef1713152fa67f771.zip
Merge pull request #94 from hutch31/master
Added new testbench and linker file for ROM load
-rw-r--r--scripts/romload/.gitignore11
-rw-r--r--scripts/romload/Makefile41
-rw-r--r--scripts/romload/firmware.c21
-rw-r--r--scripts/romload/hex8tohex32.py34
-rw-r--r--scripts/romload/map2debug.py30
-rw-r--r--scripts/romload/sections.ld45
-rw-r--r--scripts/romload/start.S52
-rw-r--r--scripts/romload/syscalls.c95
-rw-r--r--scripts/romload/testbench.v140
9 files changed, 469 insertions, 0 deletions
diff --git a/scripts/romload/.gitignore b/scripts/romload/.gitignore
new file mode 100644
index 0000000..6f1295b
--- /dev/null
+++ b/scripts/romload/.gitignore
@@ -0,0 +1,11 @@
+firmware.d
+firmware.elf
+firmware.hex
+firmware32.hex
+firmware.o
+firmware_addr.txt
+firmware_dbg.v
+syscalls.o
+testbench.vvp
+testbench.vcd
+start.elf
diff --git a/scripts/romload/Makefile b/scripts/romload/Makefile
new file mode 100644
index 0000000..d510fa8
--- /dev/null
+++ b/scripts/romload/Makefile
@@ -0,0 +1,41 @@
+ifndef RISCV_TOOLS_PREFIX
+RISCV_TOOLS_PREFIX = /opt/riscv32ic/bin/riscv32-unknown-elf-
+endif
+CXX = $(RISCV_TOOLS_PREFIX)g++ -march=rv32i
+CC = $(RISCV_TOOLS_PREFIX)gcc -march=rv32i
+AS = $(RISCV_TOOLS_PREFIX)gcc -march=rv32i
+CXXFLAGS = -MD -Os -Wall -std=c++11
+CCFLAGS = -MD -Os -Wall
+#LDFLAGS = -Wl,--gc-sections,--no-relax
+LDFLAGS = -Wl,--gc-sections
+LDLIBS =
+
+test: testbench.vvp firmware32.hex
+ vvp -l testbench.log -N testbench.vvp
+
+testbench.vvp: testbench.v ../../picorv32.v firmware_dbg.v
+ iverilog -o testbench.vvp testbench.v ../../picorv32.v
+ chmod -x testbench.vvp
+
+firmware32.hex: firmware.elf hex8tohex32.py
+ $(RISCV_TOOLS_PREFIX)objcopy -O verilog firmware.elf firmware.tmp
+ python3 hex8tohex32.py firmware.tmp > firmware32.hex
+
+
+firmware_dbg.v: firmware.map
+ python3 map2debug.py
+
+start.o: start.S
+ $(CC) -c -nostdlib start.S $(LDLIBS)
+
+firmware.elf: firmware.o syscalls.o start.o
+ $(CC) $(LDFLAGS),-Map=firmware.map -o $@ $^ -T sections.ld $(LDLIBS)
+ chmod -x firmware.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/romload/firmware.c b/scripts/romload/firmware.c
new file mode 100644
index 0000000..72bb9a1
--- /dev/null
+++ b/scripts/romload/firmware.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int x1 = 1000;
+int x2 = 2000;
+
+void main()
+{
+ int z;
+ x1 = 50;
+ x2 = 50;
+
+ printf("hello\n");
+ z = (x1 + x2);
+ if (z == 100)
+ printf("TEST PASSED\n");
+ else
+ printf("TEST FAILED, z=%d\n", z);
+ exit(0);
+}
+
diff --git a/scripts/romload/hex8tohex32.py b/scripts/romload/hex8tohex32.py
new file mode 100644
index 0000000..ae44101
--- /dev/null
+++ b/scripts/romload/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/romload/map2debug.py b/scripts/romload/map2debug.py
new file mode 100644
index 0000000..fc5c97c
--- /dev/null
+++ b/scripts/romload/map2debug.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import re
+
+symbol = re.compile("\s*0x([0-9a-f]+)\s+([\w_]+)")
+symbol_map = {}
+with open("firmware.map", "r") as fh:
+ for fd in fh:
+ sym = symbol.match(fd)
+ if (sym):
+ addr = int(sym.group(1), 16)
+ symbol_map[addr] = sym.group(2)
+
+with open("firmware_dbg.v", "w") as fh:
+ for k, v in symbol_map.items():
+ fh.write("`define C_SYM_{1:s} 32'h{0:08x}\n".format(k, v.upper()))
+ fh.write(" task firmware_dbg;\n")
+ fh.write(" input [31:0] addr;\n");
+ fh.write(" begin\n");
+ fh.write(" case (addr)\n");
+ for k, v in symbol_map.items():
+ fh.write(" 32'h{0:08x} : $display(\"%t: FCALL: {1:s}\", $time);\n".format(k, v))
+ fh.write(" endcase\n");
+ fh.write(" end\n");
+ fh.write(" endtask\n");
+
+with open("firmware_addr.txt", "w") as fh:
+ for k, v in symbol_map.items():
+ fh.write("{0:08x} {1:s}\n".format(k,v))
+
diff --git a/scripts/romload/sections.ld b/scripts/romload/sections.ld
new file mode 100644
index 0000000..2ec3954
--- /dev/null
+++ b/scripts/romload/sections.ld
@@ -0,0 +1,45 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+*/
+
+/* starting address needs to be > 0 due to known bug in RISCV/GNU linker */
+MEMORY {
+ rom(rwx) : ORIGIN = 0x00000100, LENGTH = 63k
+ ram(rwx) : ORIGIN = 0x00020000, LENGTH = 16k
+}
+
+ENTRY(_pvstart);
+
+SECTIONS {
+ .rom : {
+ _pvstart*(.text);
+ start*(.text);
+ . = 0x100;
+ . = ALIGN(4);
+ *(.text);
+ } > rom
+
+ .data : {
+ _data_lma = LOADADDR(.data);
+ _data = .;
+ __global_pointer$ = . ;
+ *(.data .data.* )
+ *(.sdata .sdata.*)
+ . = ALIGN(4);
+ _edata = .;
+ } >ram AT>rom
+
+ .bss : {
+ _bss_start = .;
+ *(.bss .bss.*)
+ . = ALIGN(4);
+ _bss_end = .;
+ _end = .;
+ } >ram
+
+}
diff --git a/scripts/romload/start.S b/scripts/romload/start.S
new file mode 100644
index 0000000..be59808
--- /dev/null
+++ b/scripts/romload/start.S
@@ -0,0 +1,52 @@
+.section .text
+.global _start
+.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)
+
+j _start
diff --git a/scripts/romload/syscalls.c b/scripts/romload/syscalls.c
new file mode 100644
index 0000000..82e633b
--- /dev/null
+++ b/scripts/romload/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/romload/testbench.v b/scripts/romload/testbench.v
new file mode 100644
index 0000000..e38819d
--- /dev/null
+++ b/scripts/romload/testbench.v
@@ -0,0 +1,140 @@
+`timescale 1 ns / 1 ps
+`undef VERBOSE_MEM
+//`undef WRITE_VCD
+`undef MEM8BIT
+
+// define the size of our ROM
+// simulates ROM by suppressing writes below this address
+`define ROM_SIZE 32'h0001_00FF
+
+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;
+
+`include "firmware_dbg.v"
+
+ picorv32 #(
+ .COMPRESSED_ISA(1),
+ .PROGADDR_RESET(32'h100)
+ ) 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);
+ end
+`else
+ reg [31:0] memory [0:MEM_SIZE/4-1];
+ integer x;
+
+ // simulate hardware assist of clearing RAM and copying ROM data into
+ // memory
+ initial
+ begin
+ // clear memory
+ for (x=0; x<MEM_SIZE/4; x=x+1) memory[x] = 0;
+ // load rom contents
+ $readmemh("firmware32.hex", memory);
+ // copy .data section
+ for (x=0; x<(`C_SYM__BSS_START - `C_SYM___GLOBAL_POINTER); x=x+4)
+ memory[(`C_SYM___GLOBAL_POINTER+x)/4] = memory[(`C_SYM__DATA_LMA+x)/4];
+ end
+`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) && (mem_addr >= `ROM_SIZE)) 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 FIRMWARE_DEBUG_ADDR
+ firmware_dbg(mem_addr);
+`endif
+ if ((mem_wstrb == 4'h0) && (mem_rdata === 32'bx)) $display("READ FROM UNITIALIZED ADDR=%x", mem_addr);
+`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