From: Luke Kenneth Casson Leighton Date: Sat, 17 Apr 2021 12:22:06 +0000 (+0100) Subject: add verilator post-pnr cocotb sim X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7f48acb82d2fac42763d5700a967c996d914244f;p=soc-cocotb-sim.git add verilator post-pnr cocotb sim --- diff --git a/ls180/post_pnr/cocotb_v/Makefile b/ls180/post_pnr/cocotb_v/Makefile new file mode 100644 index 0000000..b62b2b9 --- /dev/null +++ b/ls180/post_pnr/cocotb_v/Makefile @@ -0,0 +1,15 @@ +ifeq ($(SIM),) + $(error Use one of the run_*.sh scripts to run cocotb test bench) +endif + +TOPLEVEL_LANG := verilog + +# copy chip.v from post_pnr ghdl "make chip" +VERILOG_SOURCES := \ + chip.v \ +# END VERILOG_SOURCES + +MODULE := test + +include $(shell cocotb-config --makefiles)/Makefile.sim + diff --git a/ls180/post_pnr/cocotb_v/idcode.svf b/ls180/post_pnr/cocotb_v/idcode.svf new file mode 100644 index 0000000..994e9c8 --- /dev/null +++ b/ls180/post_pnr/cocotb_v/idcode.svf @@ -0,0 +1,4 @@ +!Loading device with 'idcode' instruction. +SIR 4 TDI (1); +SDR 32 TDI (00000000) TDO (000018FF) ; + diff --git a/ls180/post_pnr/cocotb_v/run_verilator_chip.sh b/ls180/post_pnr/cocotb_v/run_verilator_chip.sh new file mode 100755 index 0000000..674cb24 --- /dev/null +++ b/ls180/post_pnr/cocotb_v/run_verilator_chip.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# create dummy memory files +yes 0 | head -128 > mem_1.init +yes 0 | head -32 > mem_1.init +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=verilator \ + TOPLEVEL=chip \ + COCOTB_RESULTS_FILE=results_iverilator_chip.xml \ + COCOTB_HDL_TIMEUNIT=1ns \ + COCOTB_HDL_TIMEPRECISION=1ps \ + TESTCASE="idcode_reset,idcodesvf_reset,boundary_scan_reset,idcode_run" \ + VERILATOR_TRACE="1" \ + NOTUSEDCOMPILE_ARGS="--hierarchical " \ + NOTUSEDCOMPILE_ARGS="--unroll-count 256 \ + --output-split 5000 \ + --output-split-cfuncs 500 \ + --output-split-ctrace 500 \ + --prefix Vtop -o chip" \ + EXTRA_ARGS="--trace --trace-structs -Wno-fatal \ + -Wno-BLKANDNBLK \ + -Wno-TIMESCALEMOD \ + -Wno-WIDTH" \ + MODULE="test" \ + SIM_BUILD=sim_build_iverilator_chip + + + diff --git a/ls180/post_pnr/cocotb_v/test.py b/ls180/post_pnr/cocotb_v/test.py new file mode 100644 index 0000000..a96846c --- /dev/null +++ b/ls180/post_pnr/cocotb_v/test.py @@ -0,0 +1,269 @@ +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 + +from itertools import chain + +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.nmigen.jtag.tap import IOType +from c4m.cocotb.jtag.c4m_jtag import JTAG_Master +from c4m.cocotb.jtag.c4m_jtag_svfcocotb import SVF_Executor + +from soc.config.pinouts import get_pinspecs +from soc.debug.jtag import Pins + +# +# 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.vdd <= 1 + dut.vss <= 0 + dut.iovdd <= 1 + dut.iovss <= 0 + dut.sys_rst <= 1 + dut.sys_clk <= 0 + # adder test (ignore this) + #dut.a <= 3 + #dut.b <= 2 + + 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) + clk_steps = get_sim_steps(tck_period, "ns") + return JTAG_Master(dut.jtag_tck, dut.jtag_tms, + dut.jtag_tdi, dut.jtag_tdo, + clk_period=clk_steps, + ir_width=4) + +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_svf(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") + + +@cocotb.test() +def wishbone_basic(dut): + """ + Test of an added Wishbone interface + """ + clk_period = 100 # 100MHz + tck_period = 3000 # 0.3MHz + + data_in = BinaryValue() + # these have to match with soc.debug.jtag.JTAG ircodes + cmd_MEMADDRESS = BinaryValue("0101") # 5 + cmd_MEMREAD = BinaryValue("0110") # 6 + cmd_MEMREADWRITE = BinaryValue("0111") # 7 + + info = "Running Wishbone basic test" + yield from setup_sim(dut, clk_period=clk_period, run=True) + master = yield from setup_jtag(dut, tck_period = tck_period) + + # Load the memory address + yield master.load_ir(cmd_MEMADDRESS) + dut._log.info("Loading address") + + data_in.binstr = "000000000000000000000000000001" + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + + # Do write + yield master.load_ir(cmd_MEMREADWRITE) + dut._log.info("Writing memory") + + data_in.binstr = "01010101" * 4 + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + + data_in.binstr = "10101010" * 4 + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + + # Load the memory address + yield master.load_ir(cmd_MEMADDRESS) + dut._log.info("Loading address") + + data_in.binstr = "000000000000000000000000000001" + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "000000000000000000000000000011" + + # Do read and write + yield master.load_ir(cmd_MEMREADWRITE) + dut._log.info("Reading and writing memory") + + data_in.binstr = "10101010" * 4 + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "01010101" * 4 + + data_in.binstr = "01010101" * 4 + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "10101010" * 4 + + # Load the memory address + yield master.load_ir(cmd_MEMADDRESS) + dut._log.info("Loading address") + + data_in.binstr = "000000000000000000000000000001" + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "000000000000000000000000000011" + + # Do read + yield master.load_ir(cmd_MEMREAD) + dut._log.info("Reading memory") + data_in.binstr = "00000000" * 4 + + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "10101010" * 4 + + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "01010101" * 4 + + # Load the memory address + yield master.load_ir(cmd_MEMADDRESS) # MEMADDR + dut._log.info("Loading address") + + data_in.binstr = "000000000000000000000000000001" + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "000000000000000000000000000011" + + # Do read + yield master.load_ir(cmd_MEMREAD) # MEMREAD + dut._log.info("Reading memory") + data_in.binstr = "00000000" * 4 + + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "10101010" * 4 + + dut._log.info(" input: {}".format(data_in.binstr)) + yield master.shift_data(data_in) + dut._log.info(" output: {}".format(master.result.binstr)) + assert master.result.binstr == "01010101" * 4 + + #dut._log.info("{!r}".format(wbmem)) + + +# demo / debug how to get boundary scan names. run "python3 test.py" +if __name__ == '__main__': + pinouts = get_jtag_boundary() + for pin in pinouts: + # example: ('eint', '2', , 'eint_2', 125) + print (pin)