mirror of https://github.com/YosysHQ/picorv32.git
Merge branch 'master' into compressed
This commit is contained in:
commit
df25ba5831
|
@ -537,7 +537,7 @@ pure RV32I target, and install it in `/opt/riscv32i`:
|
||||||
|
|
||||||
git clone https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-rv32i
|
git clone https://github.com/riscv/riscv-gnu-toolchain riscv-gnu-toolchain-rv32i
|
||||||
cd riscv-gnu-toolchain-rv32i
|
cd riscv-gnu-toolchain-rv32i
|
||||||
git checkout 06c957a
|
git checkout acfa480
|
||||||
|
|
||||||
mkdir build; cd build
|
mkdir build; cd build
|
||||||
../configure --with-xlen=32 --with-arch=I --prefix=/opt/riscv32i
|
../configure --with-xlen=32 --with-arch=I --prefix=/opt/riscv32i
|
||||||
|
@ -547,7 +547,7 @@ The commands will all be named using the prefix `riscv32-unknown-elf-`, which
|
||||||
makes it easy to install them side-by-side with the regular riscv-tools, which
|
makes it easy to install them side-by-side with the regular riscv-tools, which
|
||||||
are using the name prefix `riscv64-unknown-elf-` by default.
|
are using the name prefix `riscv64-unknown-elf-` by default.
|
||||||
|
|
||||||
*Note: This instructions are for git rev 06c957a (2016-01-20) of riscv-gnu-toolchain.*
|
*Note: This instructions are for git rev acfa480 (2016-04-06) of riscv-gnu-toolchain.*
|
||||||
|
|
||||||
|
|
||||||
Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs
|
Evaluation: Timing and Utilization on Xilinx 7-Series FPGAs
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
.looplog
|
||||||
|
riscv-fesvr
|
||||||
|
riscv-isa-sim
|
||||||
|
riscv-torture
|
||||||
|
tests
|
||||||
|
test.S
|
||||||
|
test.elf
|
||||||
|
test.bin
|
||||||
|
test.hex
|
||||||
|
test.ref
|
||||||
|
test.vvp
|
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
test: riscv-torture/build.ok riscv-isa-sim/build.ok
|
||||||
|
bash test.sh
|
||||||
|
|
||||||
|
riscv-torture/build.ok: riscv-torture-rv32.diff
|
||||||
|
rm -rf riscv-torture
|
||||||
|
git clone https://github.com/ucb-bar/riscv-torture.git riscv-torture
|
||||||
|
cd riscv-torture && git checkout 2bc0c42
|
||||||
|
cd riscv-torture && patch -p1 < ../riscv-torture-rv32.diff
|
||||||
|
cd riscv-torture && patch -p1 < ../riscv-torture-genloop.diff
|
||||||
|
cd riscv-torture && ./sbt generator/run && touch build.ok
|
||||||
|
|
||||||
|
riscv-fesvr/build.ok:
|
||||||
|
rm -rf riscv-fesvr
|
||||||
|
git clone https://github.com/riscv/riscv-fesvr.git riscv-fesvr
|
||||||
|
+cd riscv-fesvr && git checkout 1c02bd6 && ./configure && make && touch build.ok
|
||||||
|
|
||||||
|
riscv-isa-sim/build.ok: riscv-fesvr/build.ok
|
||||||
|
rm -rf riscv-isa-sim
|
||||||
|
git clone https://github.com/riscv/riscv-isa-sim.git riscv-isa-sim
|
||||||
|
cd riscv-isa-sim && git checkout 10ae74e && patch -p1 < ../riscv-isa-sim-sbreak.diff
|
||||||
|
cd riscv-isa-sim && LDFLAGS="-L../riscv-fesvr" ./configure --with-isa=RV32IMC
|
||||||
|
+cd riscv-isa-sim && ln -s ../riscv-fesvr/fesvr . && make && touch build.ok
|
||||||
|
|
||||||
|
batch_list = $(shell bash -c 'for i in {0..999}; do printf "%03d\n" $$i; done')
|
||||||
|
|
||||||
|
batch: $(addprefix tests/test_,$(addsuffix .ok,$(batch_list)))
|
||||||
|
|
||||||
|
tests/testbench.vvp: testbench.v ../../picorv32.v
|
||||||
|
mkdir -p tests
|
||||||
|
iverilog -o tests/testbench.vvp testbench.v ../../picorv32.v
|
||||||
|
|
||||||
|
tests/generated.ok: riscv-torture/build.ok
|
||||||
|
rm -f riscv-torture/output/test_*
|
||||||
|
cd riscv-torture && ./sbt 'generator/run -n 1000'
|
||||||
|
touch tests/generated.ok
|
||||||
|
|
||||||
|
define test_template
|
||||||
|
tests/test_$(1).S: tests/generated.ok
|
||||||
|
mkdir -p tests
|
||||||
|
mv riscv-torture/output/test_$(1).S tests/
|
||||||
|
|
||||||
|
tests/test_$(1).elf: tests/test_$(1).S
|
||||||
|
riscv32-unknown-elf-gcc -m32 -ffreestanding -nostdlib -Wl,-Bstatic,-T,sections.lds -I. -o tests/test_$(1).elf tests/test_$(1).S
|
||||||
|
|
||||||
|
tests/test_$(1).bin: tests/test_$(1).elf
|
||||||
|
riscv32-unknown-elf-objcopy -O binary tests/test_$(1).elf tests/test_$(1).bin
|
||||||
|
|
||||||
|
tests/test_$(1).hex: tests/test_$(1).bin
|
||||||
|
python3 ../../firmware/makehex.py tests/test_$(1).bin 4096 > tests/test_$(1).hex
|
||||||
|
|
||||||
|
tests/test_$(1).ref: tests/test_$(1).elf riscv-isa-sim/build.ok
|
||||||
|
LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike tests/test_$(1).elf > tests/test_$(1).ref
|
||||||
|
|
||||||
|
tests/test_$(1).ok: tests/testbench.vvp tests/test_$(1).hex tests/test_$(1).ref
|
||||||
|
vvp tests/testbench.vvp +hex=tests/test_$(1).hex +ref=tests/test_$(1).ref | tee tests/test_$(1).out
|
||||||
|
grep -q PASSED tests/test_$(1).out
|
||||||
|
mv tests/test_$(1).out tests/test_$(1).ok
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(foreach id,$(batch_list),$(eval $(call test_template,$(id))))
|
||||||
|
|
||||||
|
loop:
|
||||||
|
date +"%s %Y-%m-%d %H:%M:%S START" >> .looplog
|
||||||
|
+set -ex; while true; do \
|
||||||
|
rm -rf tests; $(MAKE) batch; \
|
||||||
|
date +"%s %Y-%m-%d %H:%M:%S NEXT" >> .looplog; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf riscv-torture riscv-fesvr riscv-isa-sim tests
|
||||||
|
rm -f test.S test.elf test.bin test.hex test.ref test.vvp
|
||||||
|
|
||||||
|
.PHONY: test batch loop clean
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
|
||||||
|
index a17200f..af3a7ad 100644
|
||||||
|
--- a/riscv/insns/c_ebreak.h
|
||||||
|
+++ b/riscv/insns/c_ebreak.h
|
||||||
|
@@ -1,2 +1,9 @@
|
||||||
|
require_extension('C');
|
||||||
|
+
|
||||||
|
+for (int i = 0; i < 16*1024; i += 4) {
|
||||||
|
+ unsigned int dat = MMU.load_int32(i);
|
||||||
|
+ printf("%08x\n", dat);
|
||||||
|
+}
|
||||||
|
+exit(0);
|
||||||
|
+
|
||||||
|
throw trap_breakpoint();
|
||||||
|
diff --git a/riscv/insns/sbreak.h b/riscv/insns/sbreak.h
|
||||||
|
index c22776c..31397dd 100644
|
||||||
|
--- a/riscv/insns/sbreak.h
|
||||||
|
+++ b/riscv/insns/sbreak.h
|
||||||
|
@@ -1 +1,7 @@
|
||||||
|
+for (int i = 0; i < 16*1024; i += 4) {
|
||||||
|
+ unsigned int dat = MMU.load_int32(i);
|
||||||
|
+ printf("%08x\n", dat);
|
||||||
|
+}
|
||||||
|
+exit(0);
|
||||||
|
+
|
||||||
|
throw trap_breakpoint();
|
|
@ -0,0 +1,40 @@
|
||||||
|
diff --git a/generator/src/main/scala/main.scala b/generator/src/main/scala/main.scala
|
||||||
|
index 7c78982..1572771 100644
|
||||||
|
--- a/generator/src/main/scala/main.scala
|
||||||
|
+++ b/generator/src/main/scala/main.scala
|
||||||
|
@@ -8,7 +8,7 @@ import java.util.Properties
|
||||||
|
import scala.collection.JavaConversions._
|
||||||
|
|
||||||
|
case class Options(var outFileName: String = "test",
|
||||||
|
- var confFileName: String = "config/default.config")
|
||||||
|
+ var confFileName: String = "config/default.config", var numOutFiles: Int = 0)
|
||||||
|
|
||||||
|
object Generator extends App
|
||||||
|
{
|
||||||
|
@@ -17,15 +17,25 @@ object Generator extends App
|
||||||
|
val parser = new OptionParser[Options]("generator/run") {
|
||||||
|
opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
|
||||||
|
opt[String]('o', "output") valueName("<filename>") text("output filename") action {(s: String, c) => c.copy(outFileName = s)}
|
||||||
|
+ opt[Int]('n', "numfiles") valueName("<num_files>") text("number of output files") action {(n: Int, c) => c.copy(numOutFiles = n)}
|
||||||
|
}
|
||||||
|
parser.parse(args, Options()) match {
|
||||||
|
case Some(opts) =>
|
||||||
|
- generate(opts.confFileName, opts.outFileName)
|
||||||
|
+ generate_loop(opts.confFileName, opts.outFileName, opts.numOutFiles)
|
||||||
|
case None =>
|
||||||
|
System.exit(1) //error message printed by parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ def generate_loop(confFile: String, outFileName: String, numOutFiles: Int) = {
|
||||||
|
+ if (numOutFiles > 0) {
|
||||||
|
+ for (i <- 0 to (numOutFiles-1))
|
||||||
|
+ generate(confFile, outFileName + ("_%03d" format (i)))
|
||||||
|
+ } else {
|
||||||
|
+ generate(confFile, outFileName)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
def generate(confFile: String, outFileName: String): String = {
|
||||||
|
val config = new Properties()
|
||||||
|
val in = new FileInputStream(confFile)
|
|
@ -0,0 +1,147 @@
|
||||||
|
diff --git a/config/default.config b/config/default.config
|
||||||
|
index b671223..e6bd131 100644
|
||||||
|
--- a/config/default.config
|
||||||
|
+++ b/config/default.config
|
||||||
|
@@ -1,18 +1,18 @@
|
||||||
|
torture.generator.nseqs 1000
|
||||||
|
torture.generator.memsize 1024
|
||||||
|
torture.generator.fprnd 0
|
||||||
|
-torture.generator.amo true
|
||||||
|
-torture.generator.mul true
|
||||||
|
-torture.generator.divider true
|
||||||
|
+torture.generator.amo false
|
||||||
|
+torture.generator.mul false
|
||||||
|
+torture.generator.divider false
|
||||||
|
torture.generator.run_twice true
|
||||||
|
|
||||||
|
torture.generator.mix.xmem 10
|
||||||
|
torture.generator.mix.xbranch 20
|
||||||
|
-torture.generator.mix.xalu 50
|
||||||
|
-torture.generator.mix.fgen 10
|
||||||
|
-torture.generator.mix.fpmem 5
|
||||||
|
-torture.generator.mix.fax 3
|
||||||
|
-torture.generator.mix.fdiv 2
|
||||||
|
+torture.generator.mix.xalu 70
|
||||||
|
+torture.generator.mix.fgen 0
|
||||||
|
+torture.generator.mix.fpmem 0
|
||||||
|
+torture.generator.mix.fax 0
|
||||||
|
+torture.generator.mix.fdiv 0
|
||||||
|
torture.generator.mix.vec 0
|
||||||
|
|
||||||
|
torture.generator.vec.vf 1
|
||||||
|
diff --git a/generator/src/main/scala/HWRegPool.scala b/generator/src/main/scala/HWRegPool.scala
|
||||||
|
index de2ad8d..864bcc4 100644
|
||||||
|
--- a/generator/src/main/scala/HWRegPool.scala
|
||||||
|
+++ b/generator/src/main/scala/HWRegPool.scala
|
||||||
|
@@ -86,7 +86,7 @@ trait PoolsMaster extends HWRegPool
|
||||||
|
|
||||||
|
class XRegsPool extends ScalarRegPool
|
||||||
|
{
|
||||||
|
- val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "ld", "sd")
|
||||||
|
+ val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "lw", "sw")
|
||||||
|
|
||||||
|
hwregs += new HWReg("x0", true, false)
|
||||||
|
for (i <- 1 to 31)
|
||||||
|
diff --git a/generator/src/main/scala/Prog.scala b/generator/src/main/scala/Prog.scala
|
||||||
|
index 6fb49e2..685c2f8 100644
|
||||||
|
--- a/generator/src/main/scala/Prog.scala
|
||||||
|
+++ b/generator/src/main/scala/Prog.scala
|
||||||
|
@@ -385,7 +385,7 @@ class Prog(memsize: Int, veccfg: Map[String,String], run_twice: Boolean)
|
||||||
|
"\n" +
|
||||||
|
(if (using_vec) "RVTEST_RV64UV\n"
|
||||||
|
else if (using_fpu) "RVTEST_RV64UF\n"
|
||||||
|
- else "RVTEST_RV64U\n") +
|
||||||
|
+ else "RVTEST_RV32U\n") +
|
||||||
|
"RVTEST_CODE_BEGIN\n" +
|
||||||
|
(if (using_vec) init_vector() else "") +
|
||||||
|
"\n" +
|
||||||
|
diff --git a/generator/src/main/scala/Rand.scala b/generator/src/main/scala/Rand.scala
|
||||||
|
index a677d2d..ec0745f 100644
|
||||||
|
--- a/generator/src/main/scala/Rand.scala
|
||||||
|
+++ b/generator/src/main/scala/Rand.scala
|
||||||
|
@@ -15,7 +15,7 @@ object Rand
|
||||||
|
low + Random.nextInt(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
- def rand_shamt() = rand_range(0, 63)
|
||||||
|
+ def rand_shamt() = rand_range(0, 31)
|
||||||
|
def rand_shamtw() = rand_range(0, 31)
|
||||||
|
def rand_seglen() = rand_range(0, 7)
|
||||||
|
def rand_imm() = rand_range(-2048, 2047)
|
||||||
|
diff --git a/generator/src/main/scala/SeqALU.scala b/generator/src/main/scala/SeqALU.scala
|
||||||
|
index a1f27a5..e8957bf 100644
|
||||||
|
--- a/generator/src/main/scala/SeqALU.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqALU.scala
|
||||||
|
@@ -68,15 +68,15 @@ class SeqALU(xregs: HWRegPool, use_mul: Boolean, use_div: Boolean) extends InstS
|
||||||
|
candidates += seq_src1_immfn(SRAI, rand_shamt)
|
||||||
|
candidates += seq_src1_immfn(ORI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(ANDI, rand_imm)
|
||||||
|
- candidates += seq_src1_immfn(ADDIW, rand_imm)
|
||||||
|
- candidates += seq_src1_immfn(SLLIW, rand_shamtw)
|
||||||
|
- candidates += seq_src1_immfn(SRLIW, rand_shamtw)
|
||||||
|
- candidates += seq_src1_immfn(SRAIW, rand_shamtw)
|
||||||
|
+ // candidates += seq_src1_immfn(ADDIW, rand_imm)
|
||||||
|
+ // candidates += seq_src1_immfn(SLLIW, rand_shamtw)
|
||||||
|
+ // candidates += seq_src1_immfn(SRLIW, rand_shamtw)
|
||||||
|
+ // candidates += seq_src1_immfn(SRAIW, rand_shamtw)
|
||||||
|
|
||||||
|
val oplist = new ArrayBuffer[Opcode]
|
||||||
|
|
||||||
|
oplist += (ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND)
|
||||||
|
- oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
|
||||||
|
+ // oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
|
||||||
|
if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU, MULW)
|
||||||
|
if (use_div) oplist += (DIV, DIVU, REM, REMU, DIVW, DIVUW, REMW, REMUW)
|
||||||
|
|
||||||
|
diff --git a/generator/src/main/scala/SeqBranch.scala b/generator/src/main/scala/SeqBranch.scala
|
||||||
|
index bba9895..0d257d7 100644
|
||||||
|
--- a/generator/src/main/scala/SeqBranch.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqBranch.scala
|
||||||
|
@@ -75,7 +75,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
- insts += SLL(reg_one, reg_one, Imm(63))
|
||||||
|
+ insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src, reg_mask)
|
||||||
|
@@ -95,7 +95,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
- insts += SLL(reg_one, reg_one, Imm(63))
|
||||||
|
+ insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src1, reg_mask)
|
||||||
|
diff --git a/generator/src/main/scala/SeqMem.scala b/generator/src/main/scala/SeqMem.scala
|
||||||
|
index 3c180ed..1feb1d3 100644
|
||||||
|
--- a/generator/src/main/scala/SeqMem.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqMem.scala
|
||||||
|
@@ -51,7 +51,7 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
|
||||||
|
|
||||||
|
def getRandOpAndAddr (dw_addr: Int, is_store: Boolean): (Opcode, Int) =
|
||||||
|
{
|
||||||
|
- val typ = AccessType.values.toIndexedSeq(rand_range(0,6))
|
||||||
|
+ val typ = AccessType.values.toIndexedSeq(rand_range(0,4))
|
||||||
|
if (is_store)
|
||||||
|
{
|
||||||
|
if (typ == byte || typ ==ubyte) (SB, dw_addr + rand_addr_b(8))
|
||||||
|
@@ -110,13 +110,13 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
|
||||||
|
candidates += seq_load_addrfn(LH, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LHU, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LW, rand_addr_w)
|
||||||
|
- candidates += seq_load_addrfn(LWU, rand_addr_w)
|
||||||
|
- candidates += seq_load_addrfn(LD, rand_addr_d)
|
||||||
|
+ // candidates += seq_load_addrfn(LWU, rand_addr_w)
|
||||||
|
+ // candidates += seq_load_addrfn(LD, rand_addr_d)
|
||||||
|
|
||||||
|
candidates += seq_store_addrfn(SB, rand_addr_b)
|
||||||
|
candidates += seq_store_addrfn(SH, rand_addr_h)
|
||||||
|
candidates += seq_store_addrfn(SW, rand_addr_w)
|
||||||
|
- candidates += seq_store_addrfn(SD, rand_addr_d)
|
||||||
|
+ // candidates += seq_store_addrfn(SD, rand_addr_d)
|
||||||
|
|
||||||
|
if (use_amo)
|
||||||
|
{
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef RISCV_TEST_H
|
||||||
|
#define RISCV_TEST_H
|
||||||
|
|
||||||
|
#define RVTEST_RV32U
|
||||||
|
#define RVTEST_CODE_BEGIN
|
||||||
|
#define RVTEST_CODE_END
|
||||||
|
#define RVTEST_DATA_BEGIN
|
||||||
|
#define RVTEST_DATA_END
|
||||||
|
|
||||||
|
#define RVTEST_FAIL sbreak
|
||||||
|
#define RVTEST_PASS sbreak
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,9 @@
|
||||||
|
SECTIONS {
|
||||||
|
.memory : {
|
||||||
|
. = 0x000000;
|
||||||
|
*(.text);
|
||||||
|
*(*);
|
||||||
|
end = .;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
|
||||||
|
## Generate test case
|
||||||
|
|
||||||
|
if ! test -f test.S; then
|
||||||
|
cd riscv-torture
|
||||||
|
./sbt generator/run
|
||||||
|
cp output/test.S ../test.S
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
## Compile test case and create reference
|
||||||
|
|
||||||
|
riscv32-unknown-elf-gcc -m32 -ffreestanding -nostdlib -Wl,-Bstatic,-T,sections.lds -o test.elf test.S
|
||||||
|
LD_LIBRARY_PATH="./riscv-isa-sim:./riscv-fesvr" ./riscv-isa-sim/spike test.elf > test.ref
|
||||||
|
riscv32-unknown-elf-objcopy -O binary test.elf test.bin
|
||||||
|
python3 ../../firmware/makehex.py test.bin 4096 > test.hex
|
||||||
|
|
||||||
|
|
||||||
|
## Run test
|
||||||
|
|
||||||
|
iverilog -o test.vvp testbench.v ../../picorv32.v
|
||||||
|
vvp test.vvp +hex=test.hex +ref=test.ref
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
module testbench (
|
||||||
|
`ifdef VERILATOR
|
||||||
|
input clk
|
||||||
|
`endif
|
||||||
|
);
|
||||||
|
`ifndef VERILATOR
|
||||||
|
reg clk = 1;
|
||||||
|
always #5 clk = ~clk;
|
||||||
|
`endif
|
||||||
|
reg resetn = 0;
|
||||||
|
wire trap;
|
||||||
|
|
||||||
|
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 )
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [1023:0] hex_filename;
|
||||||
|
reg [1023:0] ref_filename;
|
||||||
|
|
||||||
|
reg [31:0] memory [0:4095];
|
||||||
|
reg [31:0] memory_ref [0:4095];
|
||||||
|
integer i, errcount;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
if ($value$plusargs("hex=%s", hex_filename)) $readmemh(hex_filename, memory);
|
||||||
|
if ($value$plusargs("ref=%s", ref_filename)) $readmemh(ref_filename, memory_ref);
|
||||||
|
// $dumpfile("testbench.vcd");
|
||||||
|
// $dumpvars(0, testbench);
|
||||||
|
|
||||||
|
repeat (10) @(posedge clk);
|
||||||
|
resetn <= 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
mem_ready <= 0;
|
||||||
|
mem_rdata <= 'bx;
|
||||||
|
|
||||||
|
if (!trap || !resetn) begin
|
||||||
|
if (mem_valid && !mem_ready && resetn) begin
|
||||||
|
mem_ready <= 1;
|
||||||
|
if (mem_wstrb) begin
|
||||||
|
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
|
||||||
|
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
|
||||||
|
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
|
||||||
|
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
|
||||||
|
end else begin
|
||||||
|
mem_rdata <= memory[mem_addr >> 2];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
errcount = 0;
|
||||||
|
for (i=0; i < 4096; i=i+1) begin
|
||||||
|
if (memory[i] !== memory_ref[i]) begin
|
||||||
|
$display("Signature check failed at %04x: mem=%08x ref=%08x", i << 2, memory[i], memory_ref[i]);
|
||||||
|
errcount = errcount + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (errcount)
|
||||||
|
$display("FAILED: Got %1d errors for %1s/%1s!", errcount, hex_filename, ref_filename);
|
||||||
|
else
|
||||||
|
$display("PASSED %1s/%1s.", hex_filename, ref_filename);
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
Loading…
Reference in New Issue