From 51a2c618ed83fd8c69120e885d17f2e108e44ed4 Mon Sep 17 00:00:00 2001 From: Staf Verhaegen Date: Mon, 16 Dec 2019 11:00:04 +0100 Subject: [PATCH] Added test bench for nmigen TAP with cocotb. Based on vhdl controller test bench. --- .gitignore | 1 + test/nmigen/cocotb/controller/.gitignore | 2 + test/nmigen/cocotb/controller/Makefile | 80 +++++++++++++++++++ test/nmigen/cocotb/controller/generate.py | 62 +++++++++++++++ test/nmigen/cocotb/controller/test.py | 94 +++++++++++++++++++++++ 5 files changed, 239 insertions(+) create mode 100644 test/nmigen/cocotb/controller/.gitignore create mode 100644 test/nmigen/cocotb/controller/Makefile create mode 100755 test/nmigen/cocotb/controller/generate.py create mode 100644 test/nmigen/cocotb/controller/test.py diff --git a/.gitignore b/.gitignore index 7d37e8a..0cc5bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ results.xml *.ghw sim/ghdl/bench_idcode build +sim_build *.egg-info \ No newline at end of file diff --git a/test/nmigen/cocotb/controller/.gitignore b/test/nmigen/cocotb/controller/.gitignore new file mode 100644 index 0000000..edb2279 --- /dev/null +++ b/test/nmigen/cocotb/controller/.gitignore @@ -0,0 +1,2 @@ +code +top.vcd diff --git a/test/nmigen/cocotb/controller/Makefile b/test/nmigen/cocotb/controller/Makefile new file mode 100644 index 0000000..1257cb2 --- /dev/null +++ b/test/nmigen/cocotb/controller/Makefile @@ -0,0 +1,80 @@ +CURDIR=$(realpath .) +TOPDIR=$(realpath ../../../..) + +ifeq ($(PYTHONPATH),) + PYTHONPATH := $(TOPDIR) +else + PYTHONPATH := $(TOPDIR):$(PYTHONPATH) +endif +export PYTHONPATH + +TOPLEVEL := top + +CODEDIR := $(CURDIR)/code +TOPFILE := $(CODEDIR)/$(TOPLEVEL).v +TOPVCD := $(CURDIR)/$(TOPLEVEL).vcd + +# +# COCOTB +# +VHDL_SOURCES = \ + $(CODEDIR)/jtag/c4m_jtag_pkg.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_tap_fsm.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_irblock.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_iocell.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_ioblock.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_idblock.vhdl \ + $(CODEDIR)/jtag/c4m_jtag_tap_controller.vhdl \ + $(CODEDIR)/jtag/jtag_controller_i0.vhdl \ +#VHDL_SOURCES end +VERILOG_SOURCES = \ + $(TOPFILE) \ +#VERILOG_SOURCES end +ALL_SOURCES := $(VHDL_SOURCES) $(VERILOG_SOURCES) +TOPLEVEL_LANG := verilog +MODULE := test +SIM := modelsim +ARCH := i686 +VCOM_ARGS := -2008 +WAVES := 1 + +COCOTBMAKEFILESDIR=$(shell cocotb-config --makefiles) + +# Add top target to convert output to vcd +top: $(TOPVCD) + +include $(COCOTBMAKEFILESDIR)/Makefile.inc +include $(COCOTBMAKEFILESDIR)/Makefile.sim + + +# +# Code generation +# +.PHONY: rtl +rtl: $(ALL_SOURCES) +$(ALL_SOURCES): generate_once + +GENERATE := ./generate.py +TOPDEPS := \ + $(TOPDIR)/c4m/nmigen/jtag/tap.py \ +#TOPDEPS end + +.INTERMEDIATE: generate_once +generate_once: $(GENERATE) $(TOPDEPS) | $(CODEDIR)/jtag + @echo "Generating RTL" + @$(GENERATE) + +$(CODEDIR)/jtag: + @mkdir -p $@ + + +# +# Convert waveform +# +$(TOPVCD): sim + wlf2vcd -o $@ sim_build/vsim.wlf + + +.PHONY: clean +clean:: + @rm -fr code $(TOPVCD) diff --git a/test/nmigen/cocotb/controller/generate.py b/test/nmigen/cocotb/controller/generate.py new file mode 100755 index 0000000..fee62fe --- /dev/null +++ b/test/nmigen/cocotb/controller/generate.py @@ -0,0 +1,62 @@ +#!/bin/env python3 +import os + +from nmigen import * +from nmigen.back.verilog import convert +from nmigen.build import Platform + +from c4m.nmigen.jtag import TAP + +class DummyPlatform(Platform): + resources = [] + connectors = [] + required_tools = ["yosys"] + + def toolchain_prepare(self, fragment, name, **kwargs): + raise NotImplementedError + +class Top(Elaboratable): + def __init__(self, io_count): + self.tap = TAP(io_count) + self.core_i = Signal(io_count, name="top_corei") + self.core_o = Signal(io_count, name="top_coreo") + self.core_oe = Signal(io_count, name="top_coreoe") + self.pad_i = Signal(io_count, name="top_padi") + self.pad_o = Signal(io_count, name="top_pado") + self.pad_oe = Signal(io_count, name="top_padoe") + + def elaborate(self, platform): + m = Module() + + m.submodules.tap = self.tap + + m.d.comb += [ + self.core_i.eq(Cat(io.i for io in self.tap.core)), + Cat(io.o for io in self.tap.core).eq(self.core_o), + Cat(io.oe for io in self.tap.core).eq(self.core_oe), + Cat(io.i for io in self.tap.pad).eq(self.pad_i), + self.pad_o.eq(Cat(io.o for io in self.tap.pad)), + self.pad_oe.eq(Cat(io.oe for io in self.tap.pad)), + ] + + return m + +top = Top(2) + +p = DummyPlatform() + +ports = [top.tap.bus.tck, top.tap.bus.tms, top.tap.bus.tdi, top.tap.bus.tdo, + top.core_i, top.core_o, top.core_oe, top.pad_i, top.pad_o, top.pad_oe] +# for io in tap.core: +# ports += [io.i, io.o, io.oe] +# for io in tap.pad: +# ports += [io.i, io.o, io.oe] +top_code = convert(top, ports=ports, platform=p) +with open("code/top.v", "w") as f: + f.write(top_code) + +for filename, code in p.extra_files.items(): + with open("code"+ os.path.sep + filename, "w") as f: + f.write(code) + + diff --git a/test/nmigen/cocotb/controller/test.py b/test/nmigen/cocotb/controller/test.py new file mode 100644 index 0000000..7b465fb --- /dev/null +++ b/test/nmigen/cocotb/controller/test.py @@ -0,0 +1,94 @@ +import cocotb +from cocotb.utils import get_sim_steps +from cocotb.binary import BinaryValue + +from c4m.cocotb.jtag.c4m_jtag import JTAG_Master + +@cocotb.test() +def test01_idcode(dut): + """ + Test the IDCODE command + """ + + # Run @ 1MHz + clk_period = get_sim_steps(1, "us") + master = JTAG_Master(dut.tap_bus__tck, dut.tap_bus__tms, dut.tap_bus__tdi, dut.tap_bus__tdo, clk_period=clk_period) + + dut._log.info("Trying to get IDCODE...") + + yield master.idcode() + result1 = master.result + dut._log.info("IDCODE1: {}".format(result1)) + + yield master.idcode() + result2 = master.result + dut._log.info("IDCODE2: {}".format(result2)) + + assert(result1 == result2) + +@cocotb.test() +def test02_bypass(dut): + """ + Test of BYPASS mode + """ + + # Run @ 1MHz + clk_period = get_sim_steps(1, "us") + master = JTAG_Master(dut.tap_bus__tck, dut.tap_bus__tms, dut.tap_bus__tdi, dut.tap_bus__tdo, clk_period=clk_period) + + dut._log.info("Loading BYPASS command") + yield master.load_ir(master.BYPASS) + + dut._log.info("Sending data") + + data_in = BinaryValue() + data_in.binstr = "01001101" + yield master.shift_data(data_in) + + dut._log.info("bypass out: {}".format(master.result.binstr)) + assert(master.result.binstr[:-1] == data_in.binstr[1:]) + +@cocotb.test() +def test03_sample(dut): + """ + Test of SAMPLEPRELOAD and EXTEST + """ + data_in = BinaryValue() + + # Run @ 1MHz + clk_period = get_sim_steps(1, "us") + master = JTAG_Master(dut.tap_bus__tck, dut.tap_bus__tms, dut.tap_bus__tdi, dut.tap_bus__tdo, clk_period=clk_period) + + + dut._log.info("Load SAMPLEPRELOAD command") + yield master.load_ir(master.SAMPLEPRELOAD) + + data_in.binstr = "011000" + dut._log.info(" preloading data {}".format(data_in.binstr)) + + # Set the ios pins + dut.top_coreo = 2 + dut.top_coreoe = 0 + dut.top_padi = 1 + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert(master.result.binstr == "100010") + + + dut._log.info("Load EXTEST command") + yield master.load_ir(master.EXTEST) + + data_in.binstr = "100111" + dut._log.info(" input data {}".format(data_in.binstr)) + + # Set the ios pins + dut.top_coreo = 1 + dut.top_coreoe = 3 + dut.top_padi = 2 + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert(master.result.binstr == "011101") + + dut._log.info("Do a capture of the last loaded data") + yield master.shift_data([]) + -- 2.30.2