[broken]Moved test benches to test/vhdl
authorStaf Verhaegen <staf@stafverhaegen.be>
Sun, 15 Dec 2019 13:55:36 +0000 (14:55 +0100)
committerStaf Verhaegen <staf@stafverhaegen.be>
Mon, 16 Dec 2019 12:28:29 +0000 (13:28 +0100)
test/vhdl will be for test benches of the vhdl code; test/nmigen for the
nmigen code.
This just moves the files. They will be fixed in next commit.

14 files changed:
test/cocotb/controller/Makefile [deleted file]
test/cocotb/controller/test.py [deleted file]
test/cocotb/dual_parallel/Makefile [deleted file]
test/cocotb/dual_parallel/dual_parallel.vhdl [deleted file]
test/cocotb/dual_parallel/test.py [deleted file]
test/ghdl/idcode/bench_idcode.sh [deleted file]
test/ghdl/idcode/idcode.vhdl [deleted file]
test/vhdl/cocotb/controller/Makefile [new file with mode: 0644]
test/vhdl/cocotb/controller/test.py [new file with mode: 0644]
test/vhdl/cocotb/dual_parallel/Makefile [new file with mode: 0644]
test/vhdl/cocotb/dual_parallel/dual_parallel.vhdl [new file with mode: 0644]
test/vhdl/cocotb/dual_parallel/test.py [new file with mode: 0644]
test/vhdl/ghdl/idcode/bench_idcode.sh [new file with mode: 0755]
test/vhdl/ghdl/idcode/idcode.vhdl [new file with mode: 0644]

diff --git a/test/cocotb/controller/Makefile b/test/cocotb/controller/Makefile
deleted file mode 100644 (file)
index f4e9721..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-CURDIR=$(realpath .)
-TOPDIR=$(realpath ../../..)
-
-ifeq ($(PYTHONPATH),)
-  PYTHONPATH := $(TOPDIR)
-else
-  PYTHONPATH := $(TOPDIR):$(PYTHONPATH)
-endif
-export PYTHONPATH
-
-VHDLDIR=$(TOPDIR)/c4m/vhdl/jtag
-VHDL_SOURCES = \
-  $(VHDLDIR)/c4m_jtag_pkg.vhdl \
-  $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
-  $(VHDLDIR)/c4m_jtag_irblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_iocell.vhdl \
-  $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_idblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_tap_controller.vhdl
-TOPLEVEL=c4m_jtag_tap_controller
-TOPLEVEL_LANG=vhdl
-MODULE=test
-SIM=ghdl
-GPI_IMPL=vhpi
-GHDL_ARGS=--std=08
-SIM_ARGS=--wave=test.ghw
-
-COCOTBMAKEFILESDIR=$(shell cocotb-config --makefiles)
-
-include $(COCOTBMAKEFILESDIR)/Makefile.inc
-include $(COCOTBMAKEFILESDIR)/Makefile.sim
diff --git a/test/cocotb/controller/test.py b/test/cocotb/controller/test.py
deleted file mode 100644 (file)
index 4772194..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, 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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, 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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
-
-
-    dut._log.info("Load SAMPLEPRELOAD command")
-    yield master.load_ir(master.SAMPLEPRELOAD)
-
-    data_in.binstr = "011"
-    dut._log.info("  preloading data {}".format(data_in.binstr))
-
-    # Set the ios pins
-    dut.core_out = 0
-    dut.core_en = 0
-    dut.pad_in = 1
-    yield master.shift_data(data_in)
-    dut._log.info("  output: {}".format(master.result.binstr))
-    assert(master.result.binstr == "100")
-
-
-    dut._log.info("Load EXTEST command")
-    yield master.load_ir(master.EXTEST)
-
-    data_in.binstr = "100"
-    dut._log.info("  input data {}".format(data_in.binstr))
-    
-    # Set the ios pins
-    dut.core_out = 1
-    dut.core_en = 1
-    dut.pad_in = 0
-    yield master.shift_data(data_in)
-    dut._log.info("  output: {}".format(master.result.binstr))
-    assert(master.result.binstr == "011")
-
-    dut._log.info("Do a capture of the last loaded data")
-    yield master.shift_data([])
-
diff --git a/test/cocotb/dual_parallel/Makefile b/test/cocotb/dual_parallel/Makefile
deleted file mode 100644 (file)
index 8929ddb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-CURDIR=$(realpath .)
-TOPDIR=$(realpath ../../..)
-
-ifeq ($(PYTHONPATH),)
-  PYTHONPATH := $(TOPDIR)
-else
-  PYTHONPATH := $(TOPDIR):$(PYTHONPATH)
-endif
-export PYTHONPATH
-
-VHDLDIR=$(TOPDIR)/c4m/vhdl/jtag
-VHDL_SOURCES = \
-  $(VHDLDIR)/c4m_jtag_pkg.vhdl \
-  $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
-  $(VHDLDIR)/c4m_jtag_irblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_iocell.vhdl \
-  $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_idblock.vhdl \
-  $(VHDLDIR)/c4m_jtag_tap_controller.vhdl \
-  $(CURDIR)/dual_parallel.vhdl
-TOPLEVEL=dual_parallel
-TOPLEVEL_LANG=vhdl
-MODULE=test
-SIM=ghdl
-GPI_IMPL=vhpi
-GHDL_ARGS=--std=08
-SIM_ARGS=--wave=test.ghw
-
-COCOTBMAKEFILESDIR=$(shell cocotb-config --makefiles)
-
-include $(COCOTBMAKEFILESDIR)/Makefile.inc
-include $(COCOTBMAKEFILESDIR)/Makefile.sim
diff --git a/test/cocotb/dual_parallel/dual_parallel.vhdl b/test/cocotb/dual_parallel/dual_parallel.vhdl
deleted file mode 100644 (file)
index 870ea10..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
--- Top cell with two instantiations of the tap_controller with parallel scan chains
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity dual_parallel is
-  port (
-    -- Instance 1
-    -- ==========
-    -- JTAG
-    I1_TCK:     in std_logic;
-    I1_TMS:     in std_logic;
-    I1_TDI:     in std_logic;
-    I1_TDO:     out std_logic;
-    I1_TRST_N:  in std_logic;
-
-    -- Instance 2
-    -- ==========
-    -- JTAG
-    I2_TCK:     in std_logic;
-    I2_TMS:     in std_logic;
-    I2_TDI:     in std_logic;
-    I2_TDO:     out std_logic;
-    I2_TRST_N:  in std_logic
-  );
-end dual_parallel;
-
-architecture rtl of dual_parallel is
-  signal I1_PAD_IN:     std_logic;
-  signal I1_PAD_EN:     std_logic;
-  signal I1_PAD_OUT:    std_logic;
-  signal I2_PAD_IN:     std_logic;
-  signal I2_PAD_EN:     std_logic;
-  signal I2_PAD_OUT:    std_logic;
-begin
-  CTRL1: c4m_jtag_tap_controller
-    port map (
-      TCK => I1_TCK,
-      TMS => I1_TMS,
-      TDI => I1_TDI,
-      TDO => I1_TDO,
-      TRST_N => I1_TRST_N,
-      RESET => open,
-      CAPTURE => open,
-      SHIFT => open,
-      UPDATE => open,
-      IR => open,
-      CORE_IN => open,
-      CORE_EN => "1",
-      CORE_OUT => "1",
-      PAD_IN(0) => I1_PAD_IN,
-      PAD_EN(0) => I1_PAD_EN,
-      PAD_OUT(0) => I1_PAD_OUT
-    );
-
-  CTRL2: c4m_jtag_tap_controller
-    port map (
-      TCK => I2_TCK,
-      TMS => I2_TMS,
-      TDI => I2_TDI,
-      TDO => I2_TDO,
-      TRST_N => I2_TRST_N,
-      RESET => open,
-      CAPTURE => open,
-      SHIFT => open,
-      UPDATE => open,
-      IR => open,
-      CORE_IN => open,
-      CORE_EN => "1",
-      CORE_OUT => "0",
-      PAD_IN(0) => I2_PAD_IN,
-      PAD_EN(0) => I2_PAD_EN,
-      PAD_OUT(0) => I2_PAD_OUT
-    );
-
-  I1_PAD_IN <= I2_PAD_OUT when I2_PAD_EN = '1' else
-               'Z';
-  I2_PAD_IN <= I1_PAD_OUT when I1_PAD_EN = '1' else
-               'Z';
-end rtl;
diff --git a/test/cocotb/dual_parallel/test.py b/test/cocotb/dual_parallel/test.py
deleted file mode 100644 (file)
index 77e225d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import cocotb
-from cocotb.utils import get_sim_steps
-
-from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
-
-@cocotb.test()
-def test01_dual(dut):
-    """
-    Test the IDCODE command
-    """
-
-    # TODO: Allow parallel operation of the JTAG chains
-
-    # Run @ 1MHz
-    clk_period = get_sim_steps(1, "us")
-    master1 = JTAG_Master(dut.i1_tck, dut.i1_tms, dut.i1_tdi, dut.i1_tdo, dut.i1_trst_n, clk_period)
-    master2 = JTAG_Master(dut.i2_tck, dut.i2_tms, dut.i2_tdi, dut.i2_tdo, dut.i2_trst_n, clk_period)
-
-    dut._log.info("Set command to SAMPLEPRELOAD")
-    yield master1.load_ir(master1.SAMPLEPRELOAD)
-    yield master2.load_ir(master2.SAMPLEPRELOAD)
-    
-    dut._log.info("Load data, scan out first sample")
-    yield master1.shift_data([0, 0, 0])
-    dut._log.info("  master1 scan_out: {}".format(master1.result.binstr))
-    assert(master1.result.binstr == "011")
-    yield master2.shift_data([1, 1, 1])
-    dut._log.info("  master2 scan_out: {}".format(master2.result.binstr))
-    assert(master2.result.binstr == "101")
-    
-    dut._log.info("Set command to EXTEST")
-    yield master1.load_ir(master1.EXTEST)
-    yield master2.load_ir(master2.EXTEST)
-
-    dut._log.info("Second scan")
-    yield master1.shift_data([0, 0, 0])
-    dut._log.info("  master1 scan_out: {}".format(master1.result.binstr))
-    assert(master1.result.binstr == "111")
-    yield master2.shift_data([1, 1, 1])
-    dut._log.info("  master2 scan_out: {}".format(master2.result.binstr))
-    assert(master2.result.binstr == "Z01")
diff --git a/test/ghdl/idcode/bench_idcode.sh b/test/ghdl/idcode/bench_idcode.sh
deleted file mode 100755 (executable)
index 253efed..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-vhdldir=`realpath ../../../c4m/vhdl/jtag`
-opts=--std=08
-ghdl -a $opts $vhdldir/c4m_jtag_pkg.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_tap_fsm.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_irblock.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_idblock.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_iocell.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_ioblock.vhdl
-ghdl -a $opts $vhdldir/c4m_jtag_tap_controller.vhdl
-ghdl -a $opts ./idcode.vhdl
-ghdl -r $opts bench_idcode --wave=bench_idcode.ghw
diff --git a/test/ghdl/idcode/idcode.vhdl b/test/ghdl/idcode/idcode.vhdl
deleted file mode 100644 (file)
index cc7d167..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
--- reset JTAG interface and then IDCODE should be shifted out
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity bench_idcode is
-end bench_idcode;
-
-architecture rtl of bench_idcode is
-  signal TCK:   std_logic;
-  signal TMS:   std_logic;
-  signal TDI:   std_logic;
-  signal TDO:   std_logic;
-  signal TRST_N: std_logic;
-
-  constant CLK_PERIOD:  time := 10 ns;
-
-  procedure ClkCycle(
-    signal CLK: out std_logic;
-    CLK_PERIOD: time
-  ) is
-  begin
-    CLK <= '0';
-    wait for CLK_PERIOD/4;
-    CLK <= '1';
-    wait for CLK_PERIOD/2;
-    CLK <= '0';
-    wait for CLK_PERIOD/4;
-  end ClkCycle;
-
-  procedure ClkCycles(
-    N:  integer;
-    signal CLK: out std_logic;
-    CLK_PERIOD: time
-  ) is
-  begin
-    for i in 1 to N loop
-      ClkCycle(CLK, CLK_PERIOD);
-    end loop;
-  end ClkCycles;
-begin
-  JTAG_BLOCK: c4m_jtag_tap_controller
-    -- Use default values
-    port map (
-      TCK => TCK,
-      TMS => TMS,
-      TDI => TDI,
-      TDO => TDO,
-      TRST_N => TRST_N,
-      RESET => open,
-      CAPTURE => open,
-      SHIFT => open,
-      UPDATE => open,
-      IR => open,
-      CORE_OUT => "0",
-      CORE_IN => open,
-      CORE_EN => "0",
-      PAD_OUT => open,
-      PAD_IN => "0",
-      PAD_EN => open
-    );
-
-  SIM: process
-  begin
-    -- Reset
-    TCK <= '0';
-    TMS <= '1';
-    TDI <= '0';
-    TRST_N <= '0';
-    wait for 10*CLK_PERIOD;
-
-    TRST_N <= '1';
-    wait for CLK_PERIOD;
-
-    -- Enter RunTestIdle
-    TMS <= '0';
-    ClkCycle(TCK, CLK_PERIOD);
-    -- Enter SelectDRScan
-    TMS <= '1';
-    ClkCycle(TCK, CLK_PERIOD);
-    -- Enter Capture
-    TMS <= '0';
-    ClkCycle(TCK, CLK_PERIOD);
-    -- Enter Shift, run for 35 CLK cycles
-    TMS <= '0';
-    ClkCycles(35, TCK, CLK_PERIOD);
-    -- Enter Exit1
-    TMS <= '1';
-    ClkCycle(TCK, CLK_PERIOD);
-    -- Enter Update
-    TMS <= '1';
-    ClkCycle(TCK, CLK_PERIOD);
-    -- To TestLogicReset
-    TMS <= '1';
-    ClkCycles(4, TCK, CLK_PERIOD);
-
-    -- end simulation
-    wait;
-  end process;
-end rtl;
diff --git a/test/vhdl/cocotb/controller/Makefile b/test/vhdl/cocotb/controller/Makefile
new file mode 100644 (file)
index 0000000..f4e9721
--- /dev/null
@@ -0,0 +1,31 @@
+CURDIR=$(realpath .)
+TOPDIR=$(realpath ../../..)
+
+ifeq ($(PYTHONPATH),)
+  PYTHONPATH := $(TOPDIR)
+else
+  PYTHONPATH := $(TOPDIR):$(PYTHONPATH)
+endif
+export PYTHONPATH
+
+VHDLDIR=$(TOPDIR)/c4m/vhdl/jtag
+VHDL_SOURCES = \
+  $(VHDLDIR)/c4m_jtag_pkg.vhdl \
+  $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
+  $(VHDLDIR)/c4m_jtag_irblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_iocell.vhdl \
+  $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_idblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_tap_controller.vhdl
+TOPLEVEL=c4m_jtag_tap_controller
+TOPLEVEL_LANG=vhdl
+MODULE=test
+SIM=ghdl
+GPI_IMPL=vhpi
+GHDL_ARGS=--std=08
+SIM_ARGS=--wave=test.ghw
+
+COCOTBMAKEFILESDIR=$(shell cocotb-config --makefiles)
+
+include $(COCOTBMAKEFILESDIR)/Makefile.inc
+include $(COCOTBMAKEFILESDIR)/Makefile.sim
diff --git a/test/vhdl/cocotb/controller/test.py b/test/vhdl/cocotb/controller/test.py
new file mode 100644 (file)
index 0000000..4772194
--- /dev/null
@@ -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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, 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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, 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.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
+
+
+    dut._log.info("Load SAMPLEPRELOAD command")
+    yield master.load_ir(master.SAMPLEPRELOAD)
+
+    data_in.binstr = "011"
+    dut._log.info("  preloading data {}".format(data_in.binstr))
+
+    # Set the ios pins
+    dut.core_out = 0
+    dut.core_en = 0
+    dut.pad_in = 1
+    yield master.shift_data(data_in)
+    dut._log.info("  output: {}".format(master.result.binstr))
+    assert(master.result.binstr == "100")
+
+
+    dut._log.info("Load EXTEST command")
+    yield master.load_ir(master.EXTEST)
+
+    data_in.binstr = "100"
+    dut._log.info("  input data {}".format(data_in.binstr))
+    
+    # Set the ios pins
+    dut.core_out = 1
+    dut.core_en = 1
+    dut.pad_in = 0
+    yield master.shift_data(data_in)
+    dut._log.info("  output: {}".format(master.result.binstr))
+    assert(master.result.binstr == "011")
+
+    dut._log.info("Do a capture of the last loaded data")
+    yield master.shift_data([])
+
diff --git a/test/vhdl/cocotb/dual_parallel/Makefile b/test/vhdl/cocotb/dual_parallel/Makefile
new file mode 100644 (file)
index 0000000..8929ddb
--- /dev/null
@@ -0,0 +1,32 @@
+CURDIR=$(realpath .)
+TOPDIR=$(realpath ../../..)
+
+ifeq ($(PYTHONPATH),)
+  PYTHONPATH := $(TOPDIR)
+else
+  PYTHONPATH := $(TOPDIR):$(PYTHONPATH)
+endif
+export PYTHONPATH
+
+VHDLDIR=$(TOPDIR)/c4m/vhdl/jtag
+VHDL_SOURCES = \
+  $(VHDLDIR)/c4m_jtag_pkg.vhdl \
+  $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
+  $(VHDLDIR)/c4m_jtag_irblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_iocell.vhdl \
+  $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_idblock.vhdl \
+  $(VHDLDIR)/c4m_jtag_tap_controller.vhdl \
+  $(CURDIR)/dual_parallel.vhdl
+TOPLEVEL=dual_parallel
+TOPLEVEL_LANG=vhdl
+MODULE=test
+SIM=ghdl
+GPI_IMPL=vhpi
+GHDL_ARGS=--std=08
+SIM_ARGS=--wave=test.ghw
+
+COCOTBMAKEFILESDIR=$(shell cocotb-config --makefiles)
+
+include $(COCOTBMAKEFILESDIR)/Makefile.inc
+include $(COCOTBMAKEFILESDIR)/Makefile.sim
diff --git a/test/vhdl/cocotb/dual_parallel/dual_parallel.vhdl b/test/vhdl/cocotb/dual_parallel/dual_parallel.vhdl
new file mode 100644 (file)
index 0000000..870ea10
--- /dev/null
@@ -0,0 +1,82 @@
+-- Top cell with two instantiations of the tap_controller with parallel scan chains
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity dual_parallel is
+  port (
+    -- Instance 1
+    -- ==========
+    -- JTAG
+    I1_TCK:     in std_logic;
+    I1_TMS:     in std_logic;
+    I1_TDI:     in std_logic;
+    I1_TDO:     out std_logic;
+    I1_TRST_N:  in std_logic;
+
+    -- Instance 2
+    -- ==========
+    -- JTAG
+    I2_TCK:     in std_logic;
+    I2_TMS:     in std_logic;
+    I2_TDI:     in std_logic;
+    I2_TDO:     out std_logic;
+    I2_TRST_N:  in std_logic
+  );
+end dual_parallel;
+
+architecture rtl of dual_parallel is
+  signal I1_PAD_IN:     std_logic;
+  signal I1_PAD_EN:     std_logic;
+  signal I1_PAD_OUT:    std_logic;
+  signal I2_PAD_IN:     std_logic;
+  signal I2_PAD_EN:     std_logic;
+  signal I2_PAD_OUT:    std_logic;
+begin
+  CTRL1: c4m_jtag_tap_controller
+    port map (
+      TCK => I1_TCK,
+      TMS => I1_TMS,
+      TDI => I1_TDI,
+      TDO => I1_TDO,
+      TRST_N => I1_TRST_N,
+      RESET => open,
+      CAPTURE => open,
+      SHIFT => open,
+      UPDATE => open,
+      IR => open,
+      CORE_IN => open,
+      CORE_EN => "1",
+      CORE_OUT => "1",
+      PAD_IN(0) => I1_PAD_IN,
+      PAD_EN(0) => I1_PAD_EN,
+      PAD_OUT(0) => I1_PAD_OUT
+    );
+
+  CTRL2: c4m_jtag_tap_controller
+    port map (
+      TCK => I2_TCK,
+      TMS => I2_TMS,
+      TDI => I2_TDI,
+      TDO => I2_TDO,
+      TRST_N => I2_TRST_N,
+      RESET => open,
+      CAPTURE => open,
+      SHIFT => open,
+      UPDATE => open,
+      IR => open,
+      CORE_IN => open,
+      CORE_EN => "1",
+      CORE_OUT => "0",
+      PAD_IN(0) => I2_PAD_IN,
+      PAD_EN(0) => I2_PAD_EN,
+      PAD_OUT(0) => I2_PAD_OUT
+    );
+
+  I1_PAD_IN <= I2_PAD_OUT when I2_PAD_EN = '1' else
+               'Z';
+  I2_PAD_IN <= I1_PAD_OUT when I1_PAD_EN = '1' else
+               'Z';
+end rtl;
diff --git a/test/vhdl/cocotb/dual_parallel/test.py b/test/vhdl/cocotb/dual_parallel/test.py
new file mode 100644 (file)
index 0000000..77e225d
--- /dev/null
@@ -0,0 +1,41 @@
+import cocotb
+from cocotb.utils import get_sim_steps
+
+from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
+
+@cocotb.test()
+def test01_dual(dut):
+    """
+    Test the IDCODE command
+    """
+
+    # TODO: Allow parallel operation of the JTAG chains
+
+    # Run @ 1MHz
+    clk_period = get_sim_steps(1, "us")
+    master1 = JTAG_Master(dut.i1_tck, dut.i1_tms, dut.i1_tdi, dut.i1_tdo, dut.i1_trst_n, clk_period)
+    master2 = JTAG_Master(dut.i2_tck, dut.i2_tms, dut.i2_tdi, dut.i2_tdo, dut.i2_trst_n, clk_period)
+
+    dut._log.info("Set command to SAMPLEPRELOAD")
+    yield master1.load_ir(master1.SAMPLEPRELOAD)
+    yield master2.load_ir(master2.SAMPLEPRELOAD)
+    
+    dut._log.info("Load data, scan out first sample")
+    yield master1.shift_data([0, 0, 0])
+    dut._log.info("  master1 scan_out: {}".format(master1.result.binstr))
+    assert(master1.result.binstr == "011")
+    yield master2.shift_data([1, 1, 1])
+    dut._log.info("  master2 scan_out: {}".format(master2.result.binstr))
+    assert(master2.result.binstr == "101")
+    
+    dut._log.info("Set command to EXTEST")
+    yield master1.load_ir(master1.EXTEST)
+    yield master2.load_ir(master2.EXTEST)
+
+    dut._log.info("Second scan")
+    yield master1.shift_data([0, 0, 0])
+    dut._log.info("  master1 scan_out: {}".format(master1.result.binstr))
+    assert(master1.result.binstr == "111")
+    yield master2.shift_data([1, 1, 1])
+    dut._log.info("  master2 scan_out: {}".format(master2.result.binstr))
+    assert(master2.result.binstr == "Z01")
diff --git a/test/vhdl/ghdl/idcode/bench_idcode.sh b/test/vhdl/ghdl/idcode/bench_idcode.sh
new file mode 100755 (executable)
index 0000000..253efed
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+vhdldir=`realpath ../../../c4m/vhdl/jtag`
+opts=--std=08
+ghdl -a $opts $vhdldir/c4m_jtag_pkg.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_tap_fsm.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_irblock.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_idblock.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_iocell.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_ioblock.vhdl
+ghdl -a $opts $vhdldir/c4m_jtag_tap_controller.vhdl
+ghdl -a $opts ./idcode.vhdl
+ghdl -r $opts bench_idcode --wave=bench_idcode.ghw
diff --git a/test/vhdl/ghdl/idcode/idcode.vhdl b/test/vhdl/ghdl/idcode/idcode.vhdl
new file mode 100644 (file)
index 0000000..cc7d167
--- /dev/null
@@ -0,0 +1,102 @@
+-- reset JTAG interface and then IDCODE should be shifted out
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity bench_idcode is
+end bench_idcode;
+
+architecture rtl of bench_idcode is
+  signal TCK:   std_logic;
+  signal TMS:   std_logic;
+  signal TDI:   std_logic;
+  signal TDO:   std_logic;
+  signal TRST_N: std_logic;
+
+  constant CLK_PERIOD:  time := 10 ns;
+
+  procedure ClkCycle(
+    signal CLK: out std_logic;
+    CLK_PERIOD: time
+  ) is
+  begin
+    CLK <= '0';
+    wait for CLK_PERIOD/4;
+    CLK <= '1';
+    wait for CLK_PERIOD/2;
+    CLK <= '0';
+    wait for CLK_PERIOD/4;
+  end ClkCycle;
+
+  procedure ClkCycles(
+    N:  integer;
+    signal CLK: out std_logic;
+    CLK_PERIOD: time
+  ) is
+  begin
+    for i in 1 to N loop
+      ClkCycle(CLK, CLK_PERIOD);
+    end loop;
+  end ClkCycles;
+begin
+  JTAG_BLOCK: c4m_jtag_tap_controller
+    -- Use default values
+    port map (
+      TCK => TCK,
+      TMS => TMS,
+      TDI => TDI,
+      TDO => TDO,
+      TRST_N => TRST_N,
+      RESET => open,
+      CAPTURE => open,
+      SHIFT => open,
+      UPDATE => open,
+      IR => open,
+      CORE_OUT => "0",
+      CORE_IN => open,
+      CORE_EN => "0",
+      PAD_OUT => open,
+      PAD_IN => "0",
+      PAD_EN => open
+    );
+
+  SIM: process
+  begin
+    -- Reset
+    TCK <= '0';
+    TMS <= '1';
+    TDI <= '0';
+    TRST_N <= '0';
+    wait for 10*CLK_PERIOD;
+
+    TRST_N <= '1';
+    wait for CLK_PERIOD;
+
+    -- Enter RunTestIdle
+    TMS <= '0';
+    ClkCycle(TCK, CLK_PERIOD);
+    -- Enter SelectDRScan
+    TMS <= '1';
+    ClkCycle(TCK, CLK_PERIOD);
+    -- Enter Capture
+    TMS <= '0';
+    ClkCycle(TCK, CLK_PERIOD);
+    -- Enter Shift, run for 35 CLK cycles
+    TMS <= '0';
+    ClkCycles(35, TCK, CLK_PERIOD);
+    -- Enter Exit1
+    TMS <= '1';
+    ClkCycle(TCK, CLK_PERIOD);
+    -- Enter Update
+    TMS <= '1';
+    ClkCycle(TCK, CLK_PERIOD);
+    -- To TestLogicReset
+    TMS <= '1';
+    ClkCycles(4, TCK, CLK_PERIOD);
+
+    -- end simulation
+    wait;
+  end process;
+end rtl;