Compare commits

..

29 Commits
test ... master

Author SHA1 Message Date
colin.liang f6b14b047b Refine memory interface. Change start addr from 10000 to 0. 2023-01-18 21:09:57 +08:00
colin.liang 780c18e008 Remove debug function. 2023-01-17 21:04:09 +08:00
colin.liang dfc2c47327 Refine memory interface. 2023-01-17 20:39:24 +08:00
colin.liang 7f42e7f7a4 Refine picorv code. 2023-01-17 14:51:40 +08:00
colin.liang b03844d9ac remove irq in testbench. 2023-01-17 13:01:41 +08:00
colin.liang dcab0c3178 Delete trace code in picorv. 2023-01-17 13:00:31 +08:00
colin.liang ef6fb8848f Remove irq support. 2023-01-16 20:41:28 +08:00
colin.liang 2b3f3d3f3d Move debug from core to test bench. 2023-01-13 16:11:36 +08:00
colin.liang 287e1416ea Add console.log output. 2023-01-13 15:46:50 +08:00
colin.liang e345620054 Add dhry.hex build in the top makefile. 2023-01-13 15:32:58 +08:00
colin.liang 2cf0e04e02 Add disasmmably. 2023-01-13 15:10:40 +08:00
colin.liang eab4b918b9 Refine testbench.v. 2023-01-13 14:59:49 +08:00
colin.liang e44af58d63 Refine hex file index from verialtor c code. 2023-01-13 14:49:21 +08:00
colin.liang ce40766cbd Refine tester. test common and dhry at the same time. 2023-01-12 21:18:03 +08:00
colin.liang 361dba595d remove compressed_instr. 2023-01-12 19:55:50 +08:00
colin.liang 6e318265dc format code. 2023-01-12 19:00:41 +08:00
colin.liang 2d6b66d3b4 remove BARREL_SHIFTER. 2023-01-12 17:48:48 +08:00
colin.liang 3cfab6b748 remove TWO_STAGE_SHIFT. 2023-01-12 17:36:57 +08:00
colin.liang b5edff85f7 Remove TWO_CYCLE_COMPARE. 2023-01-12 17:35:47 +08:00
colin.liang bb0bf253eb remove TWO_CYCLE_ALU. 2023-01-12 17:31:14 +08:00
colin.liang 4beed17d0a Format code. 2023-01-12 17:22:59 +08:00
colin.liang 665f26dc63 remove unsed. 2023-01-12 17:09:59 +08:00
colin.liang 1436980611 remove WITH_PCPI. 2023-01-12 17:07:04 +08:00
colin.liang 92b7265264 Remote unuse fast mul code. 2023-01-12 17:04:17 +08:00
colin.liang 9adf1c0029 Remove Config of IRQ, Use reg module from latch. 2023-01-12 17:02:34 +08:00
colin.liang 9c0d7d7593 Remove MUL DIV config paremeter. 2023-01-12 16:27:05 +08:00
colin.liang af85947a58 Remote ENABLE_REGS_DUALPORT and init reg zero. 2023-01-12 16:09:10 +08:00
colin.liang 8b3d3390f5 Remove CATCH_MISALIGN CATCH_ILLINSN. 2023-01-12 16:05:34 +08:00
colin.liang d9e14153fc Remote COMPOSE_ISA support. 2023-01-12 15:58:11 +08:00
11 changed files with 1177 additions and 2460 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -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) *(volatile int *)0x10000000 = *(p++);
while (*p) asm volatile("ebreak");
*(volatile int*)0x10000000 = *(p++); __builtin_unreachable();
asm volatile ("ebreak");
__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) *(volatile int *)0x10000000 = *(char *)(ptr++);
while (ptr != eptr) return len;
*(volatile int*)0x10000000 = *(char*)(ptr++);
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 ("ebreak"); asm volatile("li a1, 123456789");
__builtin_unreachable(); asm volatile("sw a1,0(a0)");
}
asm volatile("ebreak");
__builtin_unreachable();
}

View File

@ -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);

View File

@ -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;
}

View File

@ -10,7 +10,7 @@ OUTPUT_ARCH(riscv)
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x00010000; . = 0x00000000;
.text : .text :
{ {
*(.text) *(.text)

View File

@ -15,7 +15,7 @@ MEMORY {
SECTIONS { SECTIONS {
.memory : { .memory : {
. = 0x10000; . = 0x00000;
start*(.text); start*(.text);
*(.text); *(.text);
*(*); *(*);

View File

@ -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
**********************************/ **********************************/

2687
picorv32.v

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +1,57 @@
#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;
// Tracing (vcd) std::string hexfile;
VerilatedVcdC* tfp = NULL; if (argc > 1) {
const char* flag_vcd = Verilated::commandArgsPlusMatch("vcd"); hexfile = std::string(argv[1]);
if (flag_vcd && 0==strcmp(flag_vcd, "+vcd")) { } else {
Verilated::traceEverOn(true); hexfile = std::string("firmware/firmware.hex");
tfp = new VerilatedVcdC; }
top->trace (tfp, 99); auto hex = (uint8_t*)(top->hex_file.data());
tfp->open("testbench.vcd"); auto csr = hexfile.c_str();
} for (int i = 0; i < hexfile.size(); i += 1) {
*(hex + (128 - i)) = *(uint8_t*)(csr + i);
}
// Tracing (data bus, see showtrace.py) // Tracing (vcd)
FILE *trace_fd = NULL; VerilatedVcdC* tfp = NULL;
const char* flag_trace = Verilated::commandArgsPlusMatch("trace"); const char* flag_vcd = Verilated::commandArgsPlusMatch("vcd");
if (flag_trace && 0==strcmp(flag_trace, "+trace")) { if (flag_vcd && 0 == strcmp(flag_vcd, "+vcd")) {
trace_fd = fopen("testbench.trace", "w"); Verilated::traceEverOn(true);
} tfp = new VerilatedVcdC;
top->trace(tfp, 99);
tfp->open("testbench.vcd");
}
top->wb_clk = 0; // Tracing (data bus, see showtrace.py)
top->wb_rst = 1; FILE* trace_fd = NULL;
const char* flag_trace = Verilated::commandArgsPlusMatch("trace");
if (flag_trace && 0 == strcmp(flag_trace, "+trace")) {
trace_fd = fopen("testbench.trace", "w");
}
int t = 0; top->clk = 0;
while (!Verilated::gotFinish()) { top->rst = 1;
if (t > 200)
top->wb_rst = 0; int t = 0;
top->wb_clk = !top->wb_clk; while (!Verilated::gotFinish()) {
top->eval(); if (t > 200) top->rst = 0;
if (tfp) tfp->dump (t); top->clk = !top->clk;
if (trace_fd && top->wb_clk && top->trace_valid) fprintf(trace_fd, "%9.9lx\n", top->trace_data); top->eval();
t += 5; if (tfp) tfp->dump(t);
} t += 5;
if (tfp) tfp->close(); }
delete top; if (tfp) tfp->close();
exit(0); delete top;
exit(0);
} }

View File

@ -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