First setup for cocotb test run.
authorStaf Verhaegen <staf@stafverhaegen.be>
Thu, 1 Apr 2021 11:23:04 +0000 (13:23 +0200)
committerStaf Verhaegen <staf@stafverhaegen.be>
Thu, 1 Apr 2021 11:23:04 +0000 (13:23 +0200)
Currently only test bench is using Icarus Verilog on pre-layout design
without SRAMs.

cocotb/Makefile [new file with mode: 0644]
cocotb/README.md [new file with mode: 0644]
cocotb/clean.sh [new file with mode: 0755]
cocotb/idcode.svf [new file with mode: 0644]
cocotb/run_iverilog.sh [new file with mode: 0755]
cocotb/test.py [new file with mode: 0644]

diff --git a/cocotb/Makefile b/cocotb/Makefile
new file mode 100644 (file)
index 0000000..7d96e42
--- /dev/null
@@ -0,0 +1,16 @@
+ifeq ($(SIM),)
+  $(error Use one of the run_*.sh scripts to run cocotb test bench)
+endif
+
+TOPLEVEL_LANG := verilog
+
+VERILOG_SOURCES := \
+  ../libresoc.v \
+  ../ls180.v \
+# END VERILOG_SOURCES
+
+TOPLEVEL := ls180
+MODULE := test
+
+include $(shell cocotb-config --makefiles)/Makefile.sim
+
diff --git a/cocotb/README.md b/cocotb/README.md
new file mode 100644 (file)
index 0000000..f239ecc
--- /dev/null
@@ -0,0 +1,16 @@
+# Usage
+
+Cocotb is Makefile based. In order to support different configuration and
+simulators, run scripts are provided that call the Makefile:
+
+* run_iverilator.sh: Run pre-layout testbench with Icarus Verilog.
+* clean.sh: clean up all outputs.
+
+# Dependency
+
+* cocotb: `pip install cocotb`
+* iverilog: `apt install iverilog`
+* `../libresoc.v`, `../ls180.v`: run `make ls180_verilog` in soc directory,
+  `make ls180` in parent directory.  
+  Version with SRAMs is currently not supported.
+
diff --git a/cocotb/clean.sh b/cocotb/clean.sh
new file mode 100755 (executable)
index 0000000..04882ff
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+rm -fr results_*.xml sim_build_*
+
diff --git a/cocotb/idcode.svf b/cocotb/idcode.svf
new file mode 100644 (file)
index 0000000..a9548a1
--- /dev/null
@@ -0,0 +1,7 @@
+HIR 5 TDI (1f) SMASK (1f) ;
+TDR 0 ;
+
+!Loading device with 'idcode' instruction.
+SIR 4 TDI (1) SMASK (f) ;
+SDR 32 TDI (00000000) TDO (000018ff) ;
+
diff --git a/cocotb/run_iverilog.sh b/cocotb/run_iverilog.sh
new file mode 100755 (executable)
index 0000000..147dc60
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+touch mem.init mem_1.init mem_2.init mem_3.init mem_4.init
+# Only run test in reset state as running CPU takes too much time to simulate
+make \
+  SIM=icarus \
+  COCOTB_RESULTS_FILE=results_iverilog.xml \
+  COCOTB_HDL_TIMEUNIT=100ps \
+  TESTCASE="idcode_reset,idcodesvf_reset" \
+  SIM_BUILD=sim_build_iverilog
+
+
diff --git a/cocotb/test.py b/cocotb/test.py
new file mode 100644 (file)
index 0000000..0c1a083
--- /dev/null
@@ -0,0 +1,115 @@
+import cocotb
+from cocotb.clock import Clock
+from cocotb.triggers import Timer
+from cocotb.utils import get_sim_steps
+from cocotb.binary import BinaryValue
+
+from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
+from c4m.cocotb.jtag.c4m_jtag_svfcocotb import SVF_Executor
+
+#
+# Helper functions
+#
+
+def setup_sim(dut, *, clk_period, run):
+    """Initialize CPU and setup clock"""
+
+    clk_steps = get_sim_steps(clk_period, "ns")
+    cocotb.fork(Clock(dut.sys_clk, clk_steps).start())
+
+    dut.sys_rst <= 1
+    dut.sys_clk <= 0
+    if run:
+        yield Timer(int(10.5*clk_steps))
+        dut.sys_rst <= 0
+        yield Timer(int(5*clk_steps))
+
+def setup_jtag(dut, *, tck_period):
+    # Make this a generator
+    if False:
+        yield Timer(0)
+    return JTAG_Master(dut.jtag_tck, dut.jtag_tms, dut.jtag_tdi, dut.jtag_tdo, clk_period=tck_period)
+
+def execute_svf(dut, *, jtag, svf_filename):
+    jtag_svf = SVF_Executor(jtag)
+    with open(svf_filename, "r") as f:
+        svf_deck = f.read()
+    yield jtag_svf.run(svf_deck, p=dut._log.info)
+    
+#
+# IDCODE using JTAG_master
+#
+
+def idcode(dut, *, jtag):
+    jtag.IDCODE = [0, 0, 0, 1]
+    yield jtag.idcode()
+    result1 = jtag.result
+    dut._log.info("IDCODE1: {}".format(result1))
+    assert(result1 == BinaryValue("00000000000000000001100011111111"))
+
+    yield jtag.idcode()
+    result2 = jtag.result
+    dut._log.info("IDCODE2: {}".format(result2))
+
+    assert(result1 == result2)
+
+@cocotb.test()
+def idcode_reset(dut):
+    dut._log.info("Running IDCODE test; cpu in reset...")
+
+    clk_period = 100 # 10MHz
+    tck_period = 300 # 3MHz
+
+    yield from setup_sim(dut, clk_period=clk_period, run=False)
+    jtag = yield from setup_jtag(dut, tck_period = tck_period)
+
+    yield from idcode(dut, jtag=jtag)
+
+    dut._log.info("IDCODE test completed")
+
+@cocotb.test()
+def idcode_run(dut):
+    dut._log.info("Running IDCODE test; cpu running...")
+
+    clk_period = 100 # 10MHz
+    tck_period = 300 # 3MHz
+
+    yield from setup_sim(dut, clk_period=clk_period, run=True)
+    jtag = yield from setup_jtag(dut, tck_period = tck_period)
+
+    yield from idcode(dut, jtag=jtag)
+
+    dut._log.info("IDCODE test completed")
+
+#
+# Read IDCODE from SVF file
+#
+
+@cocotb.test()
+def idcodesvf_reset(dut):
+    dut._log.info("Running IDCODE through SVF test; cpu in reset...")
+
+    clk_period = 100 # 10MHz
+    tck_period = 300 # 3MHz
+
+    yield from setup_sim(dut, clk_period=clk_period, run=False)
+    jtag = yield from setup_jtag(dut, tck_period = tck_period)
+
+    yield from execute_svf(dut, jtag=jtag, svf_filename="idcode.svf")
+
+    dut._log.info("IDCODE test completed")
+
+@cocotb.test()
+def idcode_run(dut):
+    dut._log.info("Running IDCODE through test; cpu running...")
+
+    clk_period = 100 # 10MHz
+    tck_period = 300 # 3MHz
+
+    yield from setup_sim(dut, clk_period=clk_period, run=True)
+    jtag = yield from setup_jtag(dut, tck_period = tck_period)
+
+    yield from execute_svf(dut, jtag=jtag, svf_filename="idcode.svf")
+
+    dut._log.info("IDCODE test completed")
+