Compare commits
29 Commits
Author | SHA1 | Date |
---|---|---|
colin.liang | f6b14b047b | |
colin.liang | 780c18e008 | |
colin.liang | dfc2c47327 | |
colin.liang | 7f42e7f7a4 | |
colin.liang | b03844d9ac | |
colin.liang | dcab0c3178 | |
colin.liang | ef6fb8848f | |
colin.liang | 2b3f3d3f3d | |
colin.liang | 287e1416ea | |
colin.liang | e345620054 | |
colin.liang | 2cf0e04e02 | |
colin.liang | eab4b918b9 | |
colin.liang | e44af58d63 | |
colin.liang | ce40766cbd | |
colin.liang | 361dba595d | |
colin.liang | 6e318265dc | |
colin.liang | 2d6b66d3b4 | |
colin.liang | 3cfab6b748 | |
colin.liang | b5edff85f7 | |
colin.liang | bb0bf253eb | |
colin.liang | 4beed17d0a | |
colin.liang | 665f26dc63 | |
colin.liang | 1436980611 | |
colin.liang | 92b7265264 | |
colin.liang | 9adf1c0029 | |
colin.liang | 9c0d7d7593 | |
colin.liang | af85947a58 | |
colin.liang | 8b3d3390f5 | |
colin.liang | d9e14153fc |
|
@ -3,6 +3,7 @@
|
||||||
/firmware/firmware.bin
|
/firmware/firmware.bin
|
||||||
/firmware/firmware.elf
|
/firmware/firmware.elf
|
||||||
/firmware/firmware.hex
|
/firmware/firmware.hex
|
||||||
|
/firmware/firmware.dis
|
||||||
/firmware/firmware.map
|
/firmware/firmware.map
|
||||||
/dhrystone/dhry.bin
|
/dhrystone/dhry.bin
|
||||||
/dhrystone/dhry.elf
|
/dhrystone/dhry.elf
|
||||||
|
@ -36,3 +37,4 @@
|
||||||
/synth.v
|
/synth.v
|
||||||
.*.swp
|
.*.swp
|
||||||
.vscode
|
.vscode
|
||||||
|
build
|
||||||
|
|
73
Makefile
73
Makefile
|
@ -12,22 +12,30 @@ IVERILOG = iverilog$(ICARUS_SUFFIX)
|
||||||
VVP = vvp$(ICARUS_SUFFIX)
|
VVP = vvp$(ICARUS_SUFFIX)
|
||||||
|
|
||||||
TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
|
TEST_OBJS = $(addsuffix .o,$(basename $(wildcard tests/*.S)))
|
||||||
FIRMWARE_OBJS = firmware/start.o firmware/irq.o firmware/print.o firmware/hello.o firmware/sieve.o firmware/multest.o firmware/stats.o
|
FIRMWARE_OBJS = build/start.o build/print.o build/hello.o build/sieve.o build/multest.o build/stats.o
|
||||||
GCC_WARNS = -Werror -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
|
GCC_WARNS = -Werror -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings
|
||||||
GCC_WARNS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic # -Wconversion
|
GCC_WARNS += -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic # -Wconversion
|
||||||
TOOLCHAIN_PREFIX = $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)/bin/riscv32-unknown-elf-
|
TOOLCHAIN_PREFIX = $(RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX)/bin/riscv32-unknown-elf-
|
||||||
|
|
||||||
# Add things like "export http_proxy=... https_proxy=..." here
|
CFLAGS = -MD -O3 -mabi=ilp32 -march=rv32im -DTIME -DRISCV
|
||||||
|
|
||||||
GIT_ENV = true
|
GIT_ENV = true
|
||||||
|
|
||||||
test_verilator: testbench_verilator firmware/firmware.hex
|
test_verilator: build/testbench_verilator build/firmware.hex build/dhry.hex
|
||||||
./testbench_verilator
|
cd build && ./testbench_verilator firmware.hex
|
||||||
|
cd build && ./testbench_verilator dhry.hex
|
||||||
|
|
||||||
testbench_verilator: testbench_wb.v picorv32.v testbench.cc
|
firmware: build/testbench_verilator build/firmware.hex
|
||||||
|
cd build && ./testbench_verilator firmware.hex
|
||||||
|
|
||||||
|
dhry: build/firmware.hex build/dhry.hex
|
||||||
|
cd build && ./testbench_verilator dhry.hex
|
||||||
|
|
||||||
|
build/testbench_verilator: testbench_wb.v picorv32.v testbench.cc
|
||||||
$(VERILATOR) --cc --exe -Wno-lint -trace --top-module picorv32_wrapper testbench_wb.v picorv32.v testbench.cc \
|
$(VERILATOR) --cc --exe -Wno-lint -trace --top-module picorv32_wrapper testbench_wb.v picorv32.v testbench.cc \
|
||||||
--Mdir testbench_verilator_dir
|
--Mdir testbench_verilator_dir
|
||||||
$(MAKE) -C testbench_verilator_dir -f Vpicorv32_wrapper.mk
|
$(MAKE) -C testbench_verilator_dir -f Vpicorv32_wrapper.mk
|
||||||
cp testbench_verilator_dir/Vpicorv32_wrapper testbench_verilator
|
cp testbench_verilator_dir/Vpicorv32_wrapper build/testbench_verilator
|
||||||
|
|
||||||
check: check-yices
|
check: check-yices
|
||||||
|
|
||||||
|
@ -44,25 +52,58 @@ check.smt2: picorv32.v
|
||||||
synth.v: picorv32.v scripts/yosys/synth_sim.ys
|
synth.v: picorv32.v scripts/yosys/synth_sim.ys
|
||||||
yosys -qv3 -l synth.log scripts/yosys/synth_sim.ys
|
yosys -qv3 -l synth.log scripts/yosys/synth_sim.ys
|
||||||
|
|
||||||
firmware/firmware.hex: firmware/firmware.elf
|
|
||||||
|
# firmware.hex
|
||||||
|
|
||||||
|
build/firmware.hex: build/firmware.elf
|
||||||
$(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@
|
$(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@
|
||||||
|
|
||||||
firmware/firmware.elf: $(FIRMWARE_OBJS) $(TEST_OBJS) firmware/sections.lds
|
build/firmware.elf: $(FIRMWARE_OBJS) $(TEST_OBJS) firmware/sections.lds
|
||||||
$(TOOLCHAIN_PREFIX)gcc -Os -mabi=ilp32 -march=rv32im -ffreestanding -nostdlib -o $@ \
|
$(TOOLCHAIN_PREFIX)gcc -Os -mabi=ilp32 -march=rv32im -ffreestanding -nostdlib -o $@ \
|
||||||
-Wl,--build-id=none,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
|
-Wl,--build-id=none,-Bstatic,-T,firmware/sections.lds,-Map,build/firmware.map,--strip-debug \
|
||||||
$(FIRMWARE_OBJS) $(TEST_OBJS) -lgcc
|
$(FIRMWARE_OBJS) $(TEST_OBJS) -lgcc
|
||||||
|
$(TOOLCHAIN_PREFIX)objdump -S $@ > build/firmware.dis
|
||||||
chmod -x $@
|
chmod -x $@
|
||||||
|
|
||||||
firmware/start.o: firmware/start.S
|
build/start.o: firmware/start.S
|
||||||
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32im -o $@ $<
|
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32im -o $@ $<
|
||||||
|
|
||||||
firmware/%.o: firmware/%.c
|
build/%.o: firmware/%.c
|
||||||
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32i -Os --std=c99 $(GCC_WARNS) -ffreestanding -nostdlib -o $@ $<
|
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32i -Os --std=c99 $(GCC_WARNS) -ffreestanding -nostdlib -o $@ $<
|
||||||
|
|
||||||
tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
|
tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
|
||||||
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32im -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
|
$(TOOLCHAIN_PREFIX)gcc -c -mabi=ilp32 -march=rv32im -o $@ -DTEST_FUNC_NAME=$(notdir $(basename $<)) \
|
||||||
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
|
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
|
||||||
|
|
||||||
|
|
||||||
|
# dhry.hex
|
||||||
|
|
||||||
|
DHRY_OBJS = build/dhry_1.o build/dhry_2.o build/syscalls.o build/stdlib.o
|
||||||
|
|
||||||
|
build/dhry.hex: build/dhry.elf
|
||||||
|
$(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@
|
||||||
|
|
||||||
|
build/dhry.elf: $(DHRY_OBJS)
|
||||||
|
$(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -Wl,-Bstatic,-T,firmware/riscv.ld,-Map,build/dhry.map,--strip-debug -o $@ $(DHRY_OBJS) -lgcc -lc
|
||||||
|
$(TOOLCHAIN_PREFIX)objdump -S $@ > build/dhry.dis
|
||||||
|
chmod -x $@
|
||||||
|
|
||||||
|
build/dhry_1.o: dhrystone/dhry_1.c
|
||||||
|
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
build/dhry_2.o: dhrystone/dhry_2.c
|
||||||
|
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
build/syscalls.o: dhrystone/syscalls.c
|
||||||
|
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
build/stdlib.o: dhrystone/stdlib.c
|
||||||
|
$(TOOLCHAIN_PREFIX)gcc -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
build/dhry_1.o build/dhry_2.o: CFLAGS += -Wno-implicit-int -Wno-implicit-function-declaration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
download-tools:
|
download-tools:
|
||||||
sudo bash -c 'set -ex; mkdir -p /var/cache/distfiles; $(GIT_ENV); \
|
sudo bash -c 'set -ex; mkdir -p /var/cache/distfiles; $(GIT_ENV); \
|
||||||
$(foreach REPO,riscv-gnu-toolchain riscv-binutils-gdb riscv-gcc riscv-glibc riscv-newlib, \
|
$(foreach REPO,riscv-gnu-toolchain riscv-binutils-gdb riscv-gcc riscv-glibc riscv-newlib, \
|
||||||
|
@ -114,11 +155,13 @@ toc:
|
||||||
gawk '/^-+$$/ { y=tolower(x); gsub("[^a-z0-9]+", "-", y); gsub("-$$", "", y); printf("- [%s](#%s)\n", x, y); } { x=$$0; }' README.md
|
gawk '/^-+$$/ { y=tolower(x); gsub("[^a-z0-9]+", "-", y); gsub("-$$", "", y); printf("- [%s](#%s)\n", x, y); } { x=$$0; }' README.md
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
rm -rf build || true
|
||||||
|
mkdir -p build
|
||||||
rm -rf riscv-gnu-toolchain-riscv32i riscv-gnu-toolchain-riscv32ic \
|
rm -rf riscv-gnu-toolchain-riscv32i riscv-gnu-toolchain-riscv32ic \
|
||||||
riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
|
riscv-gnu-toolchain-riscv32im riscv-gnu-toolchain-riscv32imc
|
||||||
rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \
|
rm -vrf $(TEST_OBJS) check.smt2 check.vcd synth.v synth.log \
|
||||||
firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.map \
|
testbench_verilator_dir
|
||||||
testbench_wb.vvp testbench.vcd testbench.trace \
|
|
||||||
testbench_verilator testbench_verilator_dir
|
|
||||||
|
|
||||||
.PHONY: test_wb test_wb_vcd download-tools build-tools toc clean
|
.PHONY: test_wb test_wb_vcd download-tools build-tools toc clean
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,94 +2,69 @@
|
||||||
// Based on riscv newlib libgloss/riscv/sys_*.c
|
// Based on riscv newlib libgloss/riscv/sys_*.c
|
||||||
// Written by Clifford Wolf.
|
// Written by Clifford Wolf.
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
|
#define UNIMPL_FUNC(_f) ".globl " #_f "\n.type " #_f ", @function\n" #_f ":\n"
|
||||||
|
|
||||||
asm (
|
asm(".text\n"
|
||||||
".text\n"
|
".align 2\n" UNIMPL_FUNC(_open) UNIMPL_FUNC(_openat) UNIMPL_FUNC(_lseek)
|
||||||
".align 2\n"
|
UNIMPL_FUNC(_stat) UNIMPL_FUNC(_lstat) UNIMPL_FUNC(_fstatat)
|
||||||
UNIMPL_FUNC(_open)
|
UNIMPL_FUNC(_isatty) UNIMPL_FUNC(_access) UNIMPL_FUNC(_faccessat)
|
||||||
UNIMPL_FUNC(_openat)
|
UNIMPL_FUNC(_link) UNIMPL_FUNC(_unlink) UNIMPL_FUNC(_execve)
|
||||||
UNIMPL_FUNC(_lseek)
|
UNIMPL_FUNC(_getpid) UNIMPL_FUNC(_fork) UNIMPL_FUNC(_kill)
|
||||||
UNIMPL_FUNC(_stat)
|
UNIMPL_FUNC(_wait) UNIMPL_FUNC(_times) UNIMPL_FUNC(
|
||||||
UNIMPL_FUNC(_lstat)
|
_gettimeofday) UNIMPL_FUNC(_ftime)
|
||||||
UNIMPL_FUNC(_fstatat)
|
UNIMPL_FUNC(_utime) UNIMPL_FUNC(_chown)
|
||||||
UNIMPL_FUNC(_isatty)
|
UNIMPL_FUNC(_chmod) UNIMPL_FUNC(_chdir)
|
||||||
UNIMPL_FUNC(_access)
|
UNIMPL_FUNC(_getcwd) UNIMPL_FUNC(
|
||||||
UNIMPL_FUNC(_faccessat)
|
_sysconf) "j unimplemented_syscall\n");
|
||||||
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()
|
void unimplemented_syscall() {
|
||||||
{
|
|
||||||
const char *p = "Unimplemented system call called!\n";
|
const char *p = "Unimplemented system call called!\n";
|
||||||
while (*p)
|
while (*p) *(volatile int *)0x10000000 = *(p++);
|
||||||
*(volatile int*)0x10000000 = *(p++);
|
|
||||||
asm volatile("ebreak");
|
asm volatile("ebreak");
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t _read(int file, void *ptr, size_t len)
|
ssize_t _read(int file, void *ptr, size_t len) {
|
||||||
{
|
|
||||||
// always EOF
|
// always EOF
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t _write(int file, const void *ptr, size_t len)
|
ssize_t _write(int file, const void *ptr, size_t len) {
|
||||||
{
|
|
||||||
const void *eptr = ptr + len;
|
const void *eptr = ptr + len;
|
||||||
while (ptr != eptr)
|
while (ptr != eptr) *(volatile int *)0x10000000 = *(char *)(ptr++);
|
||||||
*(volatile int*)0x10000000 = *(char*)(ptr++);
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _close(int file)
|
int _close(int file) {
|
||||||
{
|
|
||||||
// close is called before _exit()
|
// close is called before _exit()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _fstat(int file, struct stat *st)
|
int _fstat(int file, struct stat *st) {
|
||||||
{
|
|
||||||
// fstat is called during libc startup
|
// fstat is called during libc startup
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *_sbrk(ptrdiff_t incr)
|
void *_sbrk(ptrdiff_t incr) {
|
||||||
{
|
|
||||||
extern unsigned char _end[]; // Defined by linker
|
extern unsigned char _end[]; // Defined by linker
|
||||||
static unsigned long heap_end;
|
static unsigned long heap_end;
|
||||||
|
|
||||||
if (heap_end == 0)
|
if (heap_end == 0) heap_end = (long)_end;
|
||||||
heap_end = (long)_end;
|
|
||||||
|
|
||||||
heap_end += incr;
|
heap_end += incr;
|
||||||
return (void *)(heap_end - incr);
|
return (void *)(heap_end - incr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _exit(int exit_status)
|
void _exit(int exit_status) {
|
||||||
{
|
asm volatile("li a0, 0x20000000");
|
||||||
|
asm volatile("li a1, 123456789");
|
||||||
|
asm volatile("sw a1,0(a0)");
|
||||||
|
|
||||||
asm volatile("ebreak");
|
asm volatile("ebreak");
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// irq.c
|
|
||||||
uint32_t *irq(uint32_t *regs, uint32_t irqs);
|
|
||||||
|
|
||||||
// print.c
|
// print.c
|
||||||
void print_chr(char ch);
|
void print_chr(char ch);
|
||||||
void print_str(const char *p);
|
void print_str(const char *p);
|
||||||
|
|
140
firmware/irq.c
140
firmware/irq.c
|
@ -1,140 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
#include "firmware.h"
|
|
||||||
|
|
||||||
uint32_t *irq(uint32_t *regs, uint32_t irqs)
|
|
||||||
{
|
|
||||||
static unsigned int ext_irq_4_count = 0;
|
|
||||||
static unsigned int ext_irq_5_count = 0;
|
|
||||||
static unsigned int timer_irq_count = 0;
|
|
||||||
|
|
||||||
// checking compressed isa q0 reg handling
|
|
||||||
if ((irqs & 6) != 0) {
|
|
||||||
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
|
|
||||||
uint32_t instr = *(uint16_t*)pc;
|
|
||||||
|
|
||||||
if ((instr & 3) == 3)
|
|
||||||
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
|
|
||||||
|
|
||||||
if (((instr & 3) != 3) != (regs[0] & 1)) {
|
|
||||||
print_str("Mismatch between q0 LSB and decoded instruction word! q0=0x");
|
|
||||||
print_hex(regs[0], 8);
|
|
||||||
print_str(", instr=0x");
|
|
||||||
if ((instr & 3) == 3)
|
|
||||||
print_hex(instr, 8);
|
|
||||||
else
|
|
||||||
print_hex(instr, 4);
|
|
||||||
print_str("\n");
|
|
||||||
__asm__ volatile ("ebreak");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & (1<<4)) != 0) {
|
|
||||||
ext_irq_4_count++;
|
|
||||||
// print_str("[EXT-IRQ-4]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & (1<<5)) != 0) {
|
|
||||||
ext_irq_5_count++;
|
|
||||||
// print_str("[EXT-IRQ-5]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & 1) != 0) {
|
|
||||||
timer_irq_count++;
|
|
||||||
// print_str("[TIMER-IRQ]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & 6) != 0)
|
|
||||||
{
|
|
||||||
uint32_t pc = (regs[0] & 1) ? regs[0] - 3 : regs[0] - 4;
|
|
||||||
uint32_t instr = *(uint16_t*)pc;
|
|
||||||
|
|
||||||
if ((instr & 3) == 3)
|
|
||||||
instr = instr | (*(uint16_t*)(pc + 2)) << 16;
|
|
||||||
|
|
||||||
print_str("\n");
|
|
||||||
print_str("------------------------------------------------------------\n");
|
|
||||||
|
|
||||||
if ((irqs & 2) != 0) {
|
|
||||||
if (instr == 0x00100073 || instr == 0x9002) {
|
|
||||||
print_str("EBREAK instruction at 0x");
|
|
||||||
print_hex(pc, 8);
|
|
||||||
print_str("\n");
|
|
||||||
} else {
|
|
||||||
print_str("Illegal Instruction at 0x");
|
|
||||||
print_hex(pc, 8);
|
|
||||||
print_str(": 0x");
|
|
||||||
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((irqs & 4) != 0) {
|
|
||||||
print_str("Bus error in Instruction at 0x");
|
|
||||||
print_hex(pc, 8);
|
|
||||||
print_str(": 0x");
|
|
||||||
print_hex(instr, ((instr & 3) == 3) ? 8 : 4);
|
|
||||||
print_str("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
for (int k = 0; k < 4; k++)
|
|
||||||
{
|
|
||||||
int r = i + k*8;
|
|
||||||
|
|
||||||
if (r == 0) {
|
|
||||||
print_str("pc ");
|
|
||||||
} else
|
|
||||||
if (r < 10) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('0' + r);
|
|
||||||
print_chr(' ');
|
|
||||||
print_chr(' ');
|
|
||||||
} else
|
|
||||||
if (r < 20) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('1');
|
|
||||||
print_chr('0' + r - 10);
|
|
||||||
print_chr(' ');
|
|
||||||
} else
|
|
||||||
if (r < 30) {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('2');
|
|
||||||
print_chr('0' + r - 20);
|
|
||||||
print_chr(' ');
|
|
||||||
} else {
|
|
||||||
print_chr('x');
|
|
||||||
print_chr('3');
|
|
||||||
print_chr('0' + r - 30);
|
|
||||||
print_chr(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
print_hex(regs[r], 8);
|
|
||||||
print_str(k == 3 ? "\n" : " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
print_str("------------------------------------------------------------\n");
|
|
||||||
|
|
||||||
print_str("Number of fast external IRQs counted: ");
|
|
||||||
print_dec(ext_irq_4_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
print_str("Number of slow external IRQs counted: ");
|
|
||||||
print_dec(ext_irq_5_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
print_str("Number of timer IRQs counted: ");
|
|
||||||
print_dec(timer_irq_count);
|
|
||||||
print_str("\n");
|
|
||||||
|
|
||||||
__asm__ volatile ("ebreak");
|
|
||||||
}
|
|
||||||
|
|
||||||
return regs;
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ OUTPUT_ARCH(riscv)
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x00010000;
|
. = 0x00000000;
|
||||||
.text :
|
.text :
|
||||||
{
|
{
|
||||||
*(.text)
|
*(.text)
|
||||||
|
|
|
@ -15,7 +15,7 @@ MEMORY {
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
.memory : {
|
.memory : {
|
||||||
. = 0x10000;
|
. = 0x00000;
|
||||||
start*(.text);
|
start*(.text);
|
||||||
*(.text);
|
*(.text);
|
||||||
*(*);
|
*(*);
|
||||||
|
|
309
firmware/start.S
309
firmware/start.S
|
@ -5,26 +5,14 @@
|
||||||
// binary, for any purpose, commercial or non-commercial, and by any
|
// binary, for any purpose, commercial or non-commercial, and by any
|
||||||
// means.
|
// means.
|
||||||
|
|
||||||
#define ENABLE_QREGS
|
|
||||||
#define ENABLE_HELLO
|
#define ENABLE_HELLO
|
||||||
#define ENABLE_RVTST
|
|
||||||
#define ENABLE_SIEVE
|
#define ENABLE_SIEVE
|
||||||
#define ENABLE_MULTST
|
#define ENABLE_MULTST
|
||||||
#define ENABLE_STATS
|
#define ENABLE_STATS
|
||||||
|
|
||||||
#ifndef ENABLE_QREGS
|
|
||||||
# undef ENABLE_RVTST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Only save registers in IRQ wrapper that are to be saved by the caller in
|
|
||||||
// the RISC-V ABI, with the excpetion of the stack pointer. The IRQ handler
|
|
||||||
// will save the rest if necessary. I.e. skip x3, x4, x8, x9, and x18-x27.
|
|
||||||
#undef ENABLE_FASTIRQ
|
|
||||||
|
|
||||||
#include "custom_ops.S"
|
#include "custom_ops.S"
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.global irq
|
|
||||||
.global hello
|
.global hello
|
||||||
.global sieve
|
.global sieve
|
||||||
.global multest
|
.global multest
|
||||||
|
@ -39,305 +27,8 @@
|
||||||
.global stats
|
.global stats
|
||||||
|
|
||||||
reset_vec:
|
reset_vec:
|
||||||
// no more than 16 bytes here !
|
|
||||||
picorv32_waitirq_insn(zero)
|
|
||||||
picorv32_maskirq_insn(zero, zero)
|
|
||||||
j start
|
j start
|
||||||
|
|
||||||
|
|
||||||
/* Interrupt handler
|
|
||||||
**********************************/
|
|
||||||
|
|
||||||
.balign 16
|
|
||||||
irq_vec:
|
|
||||||
/* save registers */
|
|
||||||
|
|
||||||
#ifdef ENABLE_QREGS
|
|
||||||
|
|
||||||
picorv32_setq_insn(q2, x1)
|
|
||||||
picorv32_setq_insn(q3, x2)
|
|
||||||
|
|
||||||
lui x1, %hi(irq_regs)
|
|
||||||
addi x1, x1, %lo(irq_regs)
|
|
||||||
|
|
||||||
picorv32_getq_insn(x2, q0)
|
|
||||||
sw x2, 0*4(x1)
|
|
||||||
|
|
||||||
picorv32_getq_insn(x2, q2)
|
|
||||||
sw x2, 1*4(x1)
|
|
||||||
|
|
||||||
picorv32_getq_insn(x2, q3)
|
|
||||||
sw x2, 2*4(x1)
|
|
||||||
|
|
||||||
#ifdef ENABLE_FASTIRQ
|
|
||||||
sw x5, 5*4(x1)
|
|
||||||
sw x6, 6*4(x1)
|
|
||||||
sw x7, 7*4(x1)
|
|
||||||
sw x10, 10*4(x1)
|
|
||||||
sw x11, 11*4(x1)
|
|
||||||
sw x12, 12*4(x1)
|
|
||||||
sw x13, 13*4(x1)
|
|
||||||
sw x14, 14*4(x1)
|
|
||||||
sw x15, 15*4(x1)
|
|
||||||
sw x16, 16*4(x1)
|
|
||||||
sw x17, 17*4(x1)
|
|
||||||
sw x28, 28*4(x1)
|
|
||||||
sw x29, 29*4(x1)
|
|
||||||
sw x30, 30*4(x1)
|
|
||||||
sw x31, 31*4(x1)
|
|
||||||
#else
|
|
||||||
sw x3, 3*4(x1)
|
|
||||||
sw x4, 4*4(x1)
|
|
||||||
sw x5, 5*4(x1)
|
|
||||||
sw x6, 6*4(x1)
|
|
||||||
sw x7, 7*4(x1)
|
|
||||||
sw x8, 8*4(x1)
|
|
||||||
sw x9, 9*4(x1)
|
|
||||||
sw x10, 10*4(x1)
|
|
||||||
sw x11, 11*4(x1)
|
|
||||||
sw x12, 12*4(x1)
|
|
||||||
sw x13, 13*4(x1)
|
|
||||||
sw x14, 14*4(x1)
|
|
||||||
sw x15, 15*4(x1)
|
|
||||||
sw x16, 16*4(x1)
|
|
||||||
sw x17, 17*4(x1)
|
|
||||||
sw x18, 18*4(x1)
|
|
||||||
sw x19, 19*4(x1)
|
|
||||||
sw x20, 20*4(x1)
|
|
||||||
sw x21, 21*4(x1)
|
|
||||||
sw x22, 22*4(x1)
|
|
||||||
sw x23, 23*4(x1)
|
|
||||||
sw x24, 24*4(x1)
|
|
||||||
sw x25, 25*4(x1)
|
|
||||||
sw x26, 26*4(x1)
|
|
||||||
sw x27, 27*4(x1)
|
|
||||||
sw x28, 28*4(x1)
|
|
||||||
sw x29, 29*4(x1)
|
|
||||||
sw x30, 30*4(x1)
|
|
||||||
sw x31, 31*4(x1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else // ENABLE_QREGS
|
|
||||||
|
|
||||||
#ifdef ENABLE_FASTIRQ
|
|
||||||
sw gp, 0*4+0x200(zero)
|
|
||||||
sw x1, 1*4+0x200(zero)
|
|
||||||
sw x2, 2*4+0x200(zero)
|
|
||||||
sw x5, 5*4+0x200(zero)
|
|
||||||
sw x6, 6*4+0x200(zero)
|
|
||||||
sw x7, 7*4+0x200(zero)
|
|
||||||
sw x10, 10*4+0x200(zero)
|
|
||||||
sw x11, 11*4+0x200(zero)
|
|
||||||
sw x12, 12*4+0x200(zero)
|
|
||||||
sw x13, 13*4+0x200(zero)
|
|
||||||
sw x14, 14*4+0x200(zero)
|
|
||||||
sw x15, 15*4+0x200(zero)
|
|
||||||
sw x16, 16*4+0x200(zero)
|
|
||||||
sw x17, 17*4+0x200(zero)
|
|
||||||
sw x28, 28*4+0x200(zero)
|
|
||||||
sw x29, 29*4+0x200(zero)
|
|
||||||
sw x30, 30*4+0x200(zero)
|
|
||||||
sw x31, 31*4+0x200(zero)
|
|
||||||
#else
|
|
||||||
sw gp, 0*4+0x200(zero)
|
|
||||||
sw x1, 1*4+0x200(zero)
|
|
||||||
sw x2, 2*4+0x200(zero)
|
|
||||||
sw x3, 3*4+0x200(zero)
|
|
||||||
sw x4, 4*4+0x200(zero)
|
|
||||||
sw x5, 5*4+0x200(zero)
|
|
||||||
sw x6, 6*4+0x200(zero)
|
|
||||||
sw x7, 7*4+0x200(zero)
|
|
||||||
sw x8, 8*4+0x200(zero)
|
|
||||||
sw x9, 9*4+0x200(zero)
|
|
||||||
sw x10, 10*4+0x200(zero)
|
|
||||||
sw x11, 11*4+0x200(zero)
|
|
||||||
sw x12, 12*4+0x200(zero)
|
|
||||||
sw x13, 13*4+0x200(zero)
|
|
||||||
sw x14, 14*4+0x200(zero)
|
|
||||||
sw x15, 15*4+0x200(zero)
|
|
||||||
sw x16, 16*4+0x200(zero)
|
|
||||||
sw x17, 17*4+0x200(zero)
|
|
||||||
sw x18, 18*4+0x200(zero)
|
|
||||||
sw x19, 19*4+0x200(zero)
|
|
||||||
sw x20, 20*4+0x200(zero)
|
|
||||||
sw x21, 21*4+0x200(zero)
|
|
||||||
sw x22, 22*4+0x200(zero)
|
|
||||||
sw x23, 23*4+0x200(zero)
|
|
||||||
sw x24, 24*4+0x200(zero)
|
|
||||||
sw x25, 25*4+0x200(zero)
|
|
||||||
sw x26, 26*4+0x200(zero)
|
|
||||||
sw x27, 27*4+0x200(zero)
|
|
||||||
sw x28, 28*4+0x200(zero)
|
|
||||||
sw x29, 29*4+0x200(zero)
|
|
||||||
sw x30, 30*4+0x200(zero)
|
|
||||||
sw x31, 31*4+0x200(zero)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ENABLE_QREGS
|
|
||||||
|
|
||||||
/* call interrupt handler C function */
|
|
||||||
|
|
||||||
lui sp, %hi(irq_stack)
|
|
||||||
addi sp, sp, %lo(irq_stack)
|
|
||||||
|
|
||||||
// arg0 = address of regs
|
|
||||||
lui a0, %hi(irq_regs)
|
|
||||||
addi a0, a0, %lo(irq_regs)
|
|
||||||
|
|
||||||
// arg1 = interrupt type
|
|
||||||
#ifdef ENABLE_QREGS
|
|
||||||
picorv32_getq_insn(a1, q1)
|
|
||||||
#else
|
|
||||||
addi a1, tp, 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// call to C function
|
|
||||||
jal ra, irq
|
|
||||||
|
|
||||||
/* restore registers */
|
|
||||||
|
|
||||||
#ifdef ENABLE_QREGS
|
|
||||||
|
|
||||||
// new irq_regs address returned from C code in a0
|
|
||||||
addi x1, a0, 0
|
|
||||||
|
|
||||||
lw x2, 0*4(x1)
|
|
||||||
picorv32_setq_insn(q0, x2)
|
|
||||||
|
|
||||||
lw x2, 1*4(x1)
|
|
||||||
picorv32_setq_insn(q1, x2)
|
|
||||||
|
|
||||||
lw x2, 2*4(x1)
|
|
||||||
picorv32_setq_insn(q2, x2)
|
|
||||||
|
|
||||||
#ifdef ENABLE_FASTIRQ
|
|
||||||
lw x5, 5*4(x1)
|
|
||||||
lw x6, 6*4(x1)
|
|
||||||
lw x7, 7*4(x1)
|
|
||||||
lw x10, 10*4(x1)
|
|
||||||
lw x11, 11*4(x1)
|
|
||||||
lw x12, 12*4(x1)
|
|
||||||
lw x13, 13*4(x1)
|
|
||||||
lw x14, 14*4(x1)
|
|
||||||
lw x15, 15*4(x1)
|
|
||||||
lw x16, 16*4(x1)
|
|
||||||
lw x17, 17*4(x1)
|
|
||||||
lw x28, 28*4(x1)
|
|
||||||
lw x29, 29*4(x1)
|
|
||||||
lw x30, 30*4(x1)
|
|
||||||
lw x31, 31*4(x1)
|
|
||||||
#else
|
|
||||||
lw x3, 3*4(x1)
|
|
||||||
lw x4, 4*4(x1)
|
|
||||||
lw x5, 5*4(x1)
|
|
||||||
lw x6, 6*4(x1)
|
|
||||||
lw x7, 7*4(x1)
|
|
||||||
lw x8, 8*4(x1)
|
|
||||||
lw x9, 9*4(x1)
|
|
||||||
lw x10, 10*4(x1)
|
|
||||||
lw x11, 11*4(x1)
|
|
||||||
lw x12, 12*4(x1)
|
|
||||||
lw x13, 13*4(x1)
|
|
||||||
lw x14, 14*4(x1)
|
|
||||||
lw x15, 15*4(x1)
|
|
||||||
lw x16, 16*4(x1)
|
|
||||||
lw x17, 17*4(x1)
|
|
||||||
lw x18, 18*4(x1)
|
|
||||||
lw x19, 19*4(x1)
|
|
||||||
lw x20, 20*4(x1)
|
|
||||||
lw x21, 21*4(x1)
|
|
||||||
lw x22, 22*4(x1)
|
|
||||||
lw x23, 23*4(x1)
|
|
||||||
lw x24, 24*4(x1)
|
|
||||||
lw x25, 25*4(x1)
|
|
||||||
lw x26, 26*4(x1)
|
|
||||||
lw x27, 27*4(x1)
|
|
||||||
lw x28, 28*4(x1)
|
|
||||||
lw x29, 29*4(x1)
|
|
||||||
lw x30, 30*4(x1)
|
|
||||||
lw x31, 31*4(x1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
picorv32_getq_insn(x1, q1)
|
|
||||||
picorv32_getq_insn(x2, q2)
|
|
||||||
|
|
||||||
#else // ENABLE_QREGS
|
|
||||||
|
|
||||||
// new irq_regs address returned from C code in a0
|
|
||||||
addi a1, zero, 0x200
|
|
||||||
beq a0, a1, 1f
|
|
||||||
ebreak
|
|
||||||
1:
|
|
||||||
|
|
||||||
#ifdef ENABLE_FASTIRQ
|
|
||||||
lw gp, 0*4+0x200(zero)
|
|
||||||
lw x1, 1*4+0x200(zero)
|
|
||||||
lw x2, 2*4+0x200(zero)
|
|
||||||
lw x5, 5*4+0x200(zero)
|
|
||||||
lw x6, 6*4+0x200(zero)
|
|
||||||
lw x7, 7*4+0x200(zero)
|
|
||||||
lw x10, 10*4+0x200(zero)
|
|
||||||
lw x11, 11*4+0x200(zero)
|
|
||||||
lw x12, 12*4+0x200(zero)
|
|
||||||
lw x13, 13*4+0x200(zero)
|
|
||||||
lw x14, 14*4+0x200(zero)
|
|
||||||
lw x15, 15*4+0x200(zero)
|
|
||||||
lw x16, 16*4+0x200(zero)
|
|
||||||
lw x17, 17*4+0x200(zero)
|
|
||||||
lw x28, 28*4+0x200(zero)
|
|
||||||
lw x29, 29*4+0x200(zero)
|
|
||||||
lw x30, 30*4+0x200(zero)
|
|
||||||
lw x31, 31*4+0x200(zero)
|
|
||||||
#else
|
|
||||||
lw gp, 0*4+0x200(zero)
|
|
||||||
lw x1, 1*4+0x200(zero)
|
|
||||||
lw x2, 2*4+0x200(zero)
|
|
||||||
// do not restore x3 (gp)
|
|
||||||
lw x4, 4*4+0x200(zero)
|
|
||||||
lw x5, 5*4+0x200(zero)
|
|
||||||
lw x6, 6*4+0x200(zero)
|
|
||||||
lw x7, 7*4+0x200(zero)
|
|
||||||
lw x8, 8*4+0x200(zero)
|
|
||||||
lw x9, 9*4+0x200(zero)
|
|
||||||
lw x10, 10*4+0x200(zero)
|
|
||||||
lw x11, 11*4+0x200(zero)
|
|
||||||
lw x12, 12*4+0x200(zero)
|
|
||||||
lw x13, 13*4+0x200(zero)
|
|
||||||
lw x14, 14*4+0x200(zero)
|
|
||||||
lw x15, 15*4+0x200(zero)
|
|
||||||
lw x16, 16*4+0x200(zero)
|
|
||||||
lw x17, 17*4+0x200(zero)
|
|
||||||
lw x18, 18*4+0x200(zero)
|
|
||||||
lw x19, 19*4+0x200(zero)
|
|
||||||
lw x20, 20*4+0x200(zero)
|
|
||||||
lw x21, 21*4+0x200(zero)
|
|
||||||
lw x22, 22*4+0x200(zero)
|
|
||||||
lw x23, 23*4+0x200(zero)
|
|
||||||
lw x24, 24*4+0x200(zero)
|
|
||||||
lw x25, 25*4+0x200(zero)
|
|
||||||
lw x26, 26*4+0x200(zero)
|
|
||||||
lw x27, 27*4+0x200(zero)
|
|
||||||
lw x28, 28*4+0x200(zero)
|
|
||||||
lw x29, 29*4+0x200(zero)
|
|
||||||
lw x30, 30*4+0x200(zero)
|
|
||||||
lw x31, 31*4+0x200(zero)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ENABLE_QREGS
|
|
||||||
|
|
||||||
picorv32_retirq_insn()
|
|
||||||
|
|
||||||
.balign 0x200
|
|
||||||
irq_regs:
|
|
||||||
// registers are saved to this memory region during interrupt handling
|
|
||||||
// the program counter is saved as register 0
|
|
||||||
.fill 32,4
|
|
||||||
|
|
||||||
// stack for the interrupt handler
|
|
||||||
.fill 128,4
|
|
||||||
irq_stack:
|
|
||||||
|
|
||||||
|
|
||||||
/* Main program
|
/* Main program
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
|
|
1361
picorv32.v
1361
picorv32.v
File diff suppressed because it is too large
Load Diff
31
testbench.cc
31
testbench.cc
|
@ -1,14 +1,28 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Vpicorv32_wrapper.h"
|
#include "Vpicorv32_wrapper.h"
|
||||||
#include "verilated_vcd_c.h"
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
int main(int argc, char **argv, char **env)
|
int main(int argc, char** argv, char** env) {
|
||||||
{
|
printf("Built with %s %s.\n", Verilated::productName(),
|
||||||
printf("Built with %s %s.\n", Verilated::productName(), Verilated::productVersion());
|
Verilated::productVersion());
|
||||||
printf("Recommended: Verilator 4.0 or later.\n");
|
printf("Recommended: Verilator 4.0 or later.\n");
|
||||||
|
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
Vpicorv32_wrapper* top = new Vpicorv32_wrapper;
|
Vpicorv32_wrapper* top = new Vpicorv32_wrapper;
|
||||||
|
|
||||||
|
std::string hexfile;
|
||||||
|
if (argc > 1) {
|
||||||
|
hexfile = std::string(argv[1]);
|
||||||
|
} else {
|
||||||
|
hexfile = std::string("firmware/firmware.hex");
|
||||||
|
}
|
||||||
|
auto hex = (uint8_t*)(top->hex_file.data());
|
||||||
|
auto csr = hexfile.c_str();
|
||||||
|
for (int i = 0; i < hexfile.size(); i += 1) {
|
||||||
|
*(hex + (128 - i)) = *(uint8_t*)(csr + i);
|
||||||
|
}
|
||||||
|
|
||||||
// Tracing (vcd)
|
// Tracing (vcd)
|
||||||
VerilatedVcdC* tfp = NULL;
|
VerilatedVcdC* tfp = NULL;
|
||||||
const char* flag_vcd = Verilated::commandArgsPlusMatch("vcd");
|
const char* flag_vcd = Verilated::commandArgsPlusMatch("vcd");
|
||||||
|
@ -26,21 +40,18 @@ int main(int argc, char **argv, char **env)
|
||||||
trace_fd = fopen("testbench.trace", "w");
|
trace_fd = fopen("testbench.trace", "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
top->wb_clk = 0;
|
top->clk = 0;
|
||||||
top->wb_rst = 1;
|
top->rst = 1;
|
||||||
|
|
||||||
int t = 0;
|
int t = 0;
|
||||||
while (!Verilated::gotFinish()) {
|
while (!Verilated::gotFinish()) {
|
||||||
if (t > 200)
|
if (t > 200) top->rst = 0;
|
||||||
top->wb_rst = 0;
|
top->clk = !top->clk;
|
||||||
top->wb_clk = !top->wb_clk;
|
|
||||||
top->eval();
|
top->eval();
|
||||||
if (tfp) tfp->dump(t);
|
if (tfp) tfp->dump(t);
|
||||||
if (trace_fd && top->wb_clk && top->trace_valid) fprintf(trace_fd, "%9.9lx\n", top->trace_data);
|
|
||||||
t += 5;
|
t += 5;
|
||||||
}
|
}
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
delete top;
|
delete top;
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
217
testbench_wb.v
217
testbench_wb.v
|
@ -1,80 +1,17 @@
|
||||||
`timescale 1 ns / 1 ps
|
`timescale 1 ns / 1 ps
|
||||||
|
|
||||||
`ifndef VERILATOR
|
|
||||||
module testbench #(
|
|
||||||
parameter VERBOSE = 0
|
|
||||||
);
|
|
||||||
reg clk = 1;
|
|
||||||
reg resetn = 1;
|
|
||||||
wire trap;
|
|
||||||
|
|
||||||
always #5 clk = ~clk;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
repeat (100) @(posedge clk);
|
|
||||||
resetn <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
if ($test$plusargs("vcd")) begin
|
|
||||||
$dumpfile("testbench.vcd");
|
|
||||||
$dumpvars(0, testbench);
|
|
||||||
end
|
|
||||||
repeat (1000000) @(posedge clk);
|
|
||||||
$display("TIMEOUT");
|
|
||||||
$finish;
|
|
||||||
end
|
|
||||||
|
|
||||||
wire trace_valid;
|
|
||||||
wire [35:0] trace_data;
|
|
||||||
integer trace_file;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
if ($test$plusargs("trace")) begin
|
|
||||||
trace_file = $fopen("testbench.trace", "w");
|
|
||||||
repeat (10) @(posedge clk);
|
|
||||||
while (!trap) begin
|
|
||||||
@(posedge clk);
|
|
||||||
if (trace_valid) $fwrite(trace_file, "%x\n", trace_data);
|
|
||||||
end
|
|
||||||
$fclose(trace_file);
|
|
||||||
$display("Finished writing testbench.trace.");
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
picorv32_wrapper #(
|
|
||||||
.VERBOSE(VERBOSE)
|
|
||||||
) top (
|
|
||||||
.wb_clk(clk),
|
|
||||||
.wb_rst(resetn),
|
|
||||||
.trap(trap),
|
|
||||||
.trace_valid(trace_valid),
|
|
||||||
.trace_data(trace_data)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
`endif
|
|
||||||
|
|
||||||
module picorv32_wrapper #(
|
module picorv32_wrapper #(
|
||||||
parameter VERBOSE = 0
|
parameter VERBOSE = 0
|
||||||
) (
|
) (
|
||||||
input wb_clk,
|
input clk,
|
||||||
input wb_rst,
|
input rst,
|
||||||
output trap,
|
output trap,
|
||||||
output trace_valid,
|
input [1024:0] hex_file
|
||||||
output [35:0] trace_data
|
|
||||||
);
|
);
|
||||||
wire exit;
|
wire exit;
|
||||||
reg [31:0] irq = 0;
|
|
||||||
wire mem_instr;
|
|
||||||
|
|
||||||
reg [15:0] count_cycle = 0;
|
reg [15:0] count_cycle = 0;
|
||||||
always @(posedge wb_clk) count_cycle <= !wb_rst ? count_cycle + 1 : 0;
|
always @(posedge clk) count_cycle <= !rst ? count_cycle + 1 : 0;
|
||||||
|
|
||||||
always @* begin
|
|
||||||
irq = 0;
|
|
||||||
irq[4] = &count_cycle[12:0];
|
|
||||||
irq[5] = &count_cycle[15:0];
|
|
||||||
end
|
|
||||||
|
|
||||||
wire [31:0] wb_m2s_adr;
|
wire [31:0] wb_m2s_adr;
|
||||||
wire [31:0] wb_m2s_dat;
|
wire [31:0] wb_m2s_dat;
|
||||||
|
@ -88,30 +25,20 @@ module picorv32_wrapper #(
|
||||||
picorv32_wb #() uut (
|
picorv32_wb #() uut (
|
||||||
.trap(trap),
|
.trap(trap),
|
||||||
.exit(exit),
|
.exit(exit),
|
||||||
.irq(irq),
|
|
||||||
.trace_valid(trace_valid),
|
|
||||||
.trace_data(trace_data),
|
|
||||||
.mem_instr(mem_instr),
|
|
||||||
|
|
||||||
.wb_clk_i(wb_clk),
|
.clk(clk),
|
||||||
.wb_rst_i(wb_rst),
|
.rst(rst)
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [1023:0] firmware_file;
|
|
||||||
initial begin
|
initial begin
|
||||||
if (!$value$plusargs("firmware=%s", firmware_file))
|
$readmemh(hex_file, uut.memory);
|
||||||
firmware_file = "firmware/firmware.hex";
|
$display("HEX File : %s", hex_file);
|
||||||
// firmware_file = "dhrystone/dhry.hex";
|
|
||||||
$readmemh(firmware_file, uut.memory);
|
|
||||||
end
|
end
|
||||||
|
|
||||||
integer cycle_counter;
|
integer cycle_counter;
|
||||||
always @(posedge wb_clk) begin
|
always @(posedge clk) begin
|
||||||
cycle_counter <= !wb_rst ? cycle_counter + 1 : 0;
|
cycle_counter <= !rst ? cycle_counter + 1 : 0;
|
||||||
if (!wb_rst && trap) begin
|
if (!rst && trap) begin
|
||||||
`ifndef VERILATOR
|
|
||||||
repeat (10) @(posedge wb_clk);
|
|
||||||
`endif
|
|
||||||
$display("TRAP after %1d clock cycles", cycle_counter);
|
$display("TRAP after %1d clock cycles", cycle_counter);
|
||||||
if (exit) begin
|
if (exit) begin
|
||||||
$display("ALL TESTS PASSED.");
|
$display("ALL TESTS PASSED.");
|
||||||
|
@ -125,124 +52,62 @@ module picorv32_wrapper #(
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
* picorv32_wb
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
module picorv32_wb #(
|
module picorv32_wb #(
|
||||||
) (
|
) (
|
||||||
output trap,
|
output trap,
|
||||||
output reg exit,
|
output reg exit,
|
||||||
|
|
||||||
// Wishbone interfaces
|
input rst,
|
||||||
input wb_rst_i,
|
input clk
|
||||||
input wb_clk_i,
|
|
||||||
|
|
||||||
output reg [31:0] wbm_adr_o,
|
|
||||||
output reg [31:0] wbm_dat_o,
|
|
||||||
input [31:0] wbm_dat_i,
|
|
||||||
output reg wbm_we_o,
|
|
||||||
output reg [3:0] wbm_sel_o,
|
|
||||||
output reg wbm_stb_o,
|
|
||||||
input wbm_ack_i,
|
|
||||||
output reg wbm_cyc_o,
|
|
||||||
|
|
||||||
// Pico Co-Processor Interface (PCPI)
|
|
||||||
output pcpi_valid,
|
|
||||||
output [31:0] pcpi_insn,
|
|
||||||
output [31:0] pcpi_rs1,
|
|
||||||
output [31:0] pcpi_rs2,
|
|
||||||
input pcpi_wr,
|
|
||||||
input [31:0] pcpi_rd,
|
|
||||||
input pcpi_wait,
|
|
||||||
input pcpi_ready,
|
|
||||||
|
|
||||||
// IRQ interface
|
|
||||||
input [31:0] irq,
|
|
||||||
output [31:0] eoi,
|
|
||||||
|
|
||||||
// Trace Interface
|
|
||||||
output trace_valid,
|
|
||||||
output [35:0] trace_data,
|
|
||||||
|
|
||||||
output mem_instr
|
|
||||||
);
|
);
|
||||||
wire mem_valid;
|
|
||||||
wire [31:0] mem_addr;
|
|
||||||
wire [31:0] mem_wdata;
|
|
||||||
wire [ 3:0] mem_wstrb;
|
|
||||||
reg mem_ready;
|
|
||||||
reg [31:0] mem_rdata;
|
|
||||||
|
|
||||||
wire mem_la_read;
|
wire mem_la_read;
|
||||||
wire mem_la_write;
|
wire mem_la_write;
|
||||||
wire [31:0] mem_la_addr;
|
wire [31:0] mem_la_addr;
|
||||||
wire [31:0] mem_la_wdata;
|
wire [31:0] mem_la_wdata;
|
||||||
|
reg [31:0] mem_la_rdata;
|
||||||
wire [ 3:0] mem_la_wstrb;
|
wire [ 3:0] mem_la_wstrb;
|
||||||
|
|
||||||
|
|
||||||
wire clk;
|
|
||||||
wire resetn;
|
wire resetn;
|
||||||
initial exit = 0;
|
initial exit = 0;
|
||||||
|
|
||||||
assign clk = wb_clk_i;
|
assign resetn = ~rst;
|
||||||
assign resetn = ~wb_rst_i;
|
|
||||||
|
|
||||||
picorv32 #(
|
picorv32 #(
|
||||||
.CATCH_MISALIGN(0),
|
.PROGADDR_RESET(32'h0000_0000),
|
||||||
.ENABLE_MUL(1),
|
.STACKADDR(32'h0004_0000)
|
||||||
.ENABLE_DIV(1),
|
|
||||||
.ENABLE_IRQ(1),
|
|
||||||
.ENABLE_TRACE(1),
|
|
||||||
.MASKED_IRQ(32'h0000_0000),
|
|
||||||
.LATCHED_IRQ(32'hffff_ffff),
|
|
||||||
.PROGADDR_RESET(32'h0001_0000),
|
|
||||||
.PROGADDR_IRQ(32'h0001_0010),
|
|
||||||
.STACKADDR(32'h0001_0000)
|
|
||||||
) picorv32_core (
|
) picorv32_core (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.resetn(resetn),
|
.resetn(resetn),
|
||||||
.trap (trap),
|
.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),
|
|
||||||
.mem_la_read (mem_la_read),
|
.mem_la_read (mem_la_read),
|
||||||
.mem_la_write(mem_la_write),
|
.mem_la_write(mem_la_write),
|
||||||
.mem_la_addr (mem_la_addr),
|
.mem_la_addr (mem_la_addr),
|
||||||
.mem_la_wdata(mem_la_wdata),
|
.mem_la_wdata(mem_la_wdata),
|
||||||
.mem_la_wstrb(mem_la_wstrb),
|
.mem_la_rdata(mem_la_rdata),
|
||||||
.irq (irq),
|
.mem_la_wstrb(mem_la_wstrb)
|
||||||
.eoi (eoi),
|
|
||||||
|
|
||||||
.trace_valid(trace_valid),
|
|
||||||
.trace_data (trace_data)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
reg [7:0] memory[0:256*1024-1];
|
reg [7:0] memory[0:256*1024-1];
|
||||||
|
|
||||||
assign mem_ready = 1;
|
integer fconsole, fif;
|
||||||
|
initial begin
|
||||||
|
fconsole = $fopen("console.log", "w");
|
||||||
|
fif = $fopen("if.log", "w");
|
||||||
|
end
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
mem_rdata[7:0] <= mem_la_read ? memory[mem_la_addr+0] : 'bx;
|
mem_la_rdata[7:0] <= mem_la_read ? memory[mem_la_addr+0] : 'bx;
|
||||||
mem_rdata[15:8] <= mem_la_read ? memory[mem_la_addr+1] : 'bx;
|
mem_la_rdata[15:8] <= mem_la_read ? memory[mem_la_addr+1] : 'bx;
|
||||||
mem_rdata[23:16] <= mem_la_read ? memory[mem_la_addr+2] : 'bx;
|
mem_la_rdata[23:16] <= mem_la_read ? memory[mem_la_addr+2] : 'bx;
|
||||||
mem_rdata[31:24] <= mem_la_read ? memory[mem_la_addr+3] : 'bx;
|
mem_la_rdata[31:24] <= mem_la_read ? memory[mem_la_addr+3] : 'bx;
|
||||||
if (mem_la_write) begin
|
if (mem_la_write) begin
|
||||||
case (mem_la_addr)
|
case (mem_la_addr)
|
||||||
32'h1000_0000: begin
|
32'h1000_0000: begin
|
||||||
`ifndef TIMING
|
$fwrite(fconsole, "%c", mem_la_wdata);
|
||||||
$write("%c", mem_la_wdata);
|
|
||||||
$fflush();
|
|
||||||
`endif
|
|
||||||
end
|
end
|
||||||
32'h2000_0000: begin
|
32'h2000_0000: begin
|
||||||
if (mem_la_wdata[31:0] == 123456789) exit = 1;
|
if (mem_la_wdata[31:0] == 123456789) exit = 1;
|
||||||
|
@ -256,4 +121,26 @@ module picorv32_wb #(
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// always @(posedge clk) begin
|
||||||
|
// if (fetch_next) begin
|
||||||
|
// if (&dbg_insn_opcode[1:0])
|
||||||
|
// $fwrite(
|
||||||
|
// fif,
|
||||||
|
// "DECODE: 0x%08x 0x%08x %-0s\n",
|
||||||
|
// dbg_insn_addr,
|
||||||
|
// dbg_insn_opcode,
|
||||||
|
// dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"
|
||||||
|
// );
|
||||||
|
// else
|
||||||
|
// $fwrite(
|
||||||
|
// fif,
|
||||||
|
// "DECODE: 0x%08x 0x%04x %-0s\n",
|
||||||
|
// dbg_insn_addr,
|
||||||
|
// dbg_insn_opcode[15:0],
|
||||||
|
// dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"
|
||||||
|
// );
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
Loading…
Reference in New Issue