From 493ecad3a8956d5296d6593b5970867cd67f9bae Mon Sep 17 00:00:00 2001 From: Staf Verhaegen Date: Sun, 27 Aug 2017 22:05:24 +0200 Subject: [PATCH] Import the JTAG interface code as used for the Chips4Maker pilot Retro-uC This code has currently been tested in FPGA through a buspirate so should already be functional. --- .gitignore | 7 + bench/vhdl/idcode.vhdl | 99 +++++++++ bench/vhdl/sampleshift.vhdl | 50 +++++ rtl/vhdl/c4m_jtag_idblock.vhdl | 69 +++++++ rtl/vhdl/c4m_jtag_ioblock.vhdl | 88 ++++++++ rtl/vhdl/c4m_jtag_iocell.vhdl | 101 ++++++++++ rtl/vhdl/c4m_jtag_irblock.vhdl | 61 ++++++ rtl/vhdl/c4m_jtag_pkg.vhdl | 213 ++++++++++++++++++++ rtl/vhdl/c4m_jtag_tap_controller.vhdl | 128 ++++++++++++ rtl/vhdl/c4m_jtag_tap_fsm.vhdl | 140 +++++++++++++ sim/cocotb/c4m_jtag.py | 201 ++++++++++++++++++ sim/cocotb/controller/Makefile | 19 ++ sim/cocotb/controller/c4m_jtag.py | 1 + sim/cocotb/controller/test.py | 95 +++++++++ sim/cocotb/dual_parallel/Makefile | 20 ++ sim/cocotb/dual_parallel/c4m_jtag.py | 1 + sim/cocotb/dual_parallel/dual_parallel.vhdl | 78 +++++++ sim/cocotb/dual_parallel/test.py | 43 ++++ sim/cocotb/dual_serial/TODO | 0 sim/ghdl/bench_idcode.sh | 5 + 20 files changed, 1419 insertions(+) create mode 100644 .gitignore create mode 100644 bench/vhdl/idcode.vhdl create mode 100644 bench/vhdl/sampleshift.vhdl create mode 100644 rtl/vhdl/c4m_jtag_idblock.vhdl create mode 100644 rtl/vhdl/c4m_jtag_ioblock.vhdl create mode 100644 rtl/vhdl/c4m_jtag_iocell.vhdl create mode 100644 rtl/vhdl/c4m_jtag_irblock.vhdl create mode 100644 rtl/vhdl/c4m_jtag_pkg.vhdl create mode 100644 rtl/vhdl/c4m_jtag_tap_controller.vhdl create mode 100644 rtl/vhdl/c4m_jtag_tap_fsm.vhdl create mode 100644 sim/cocotb/c4m_jtag.py create mode 100644 sim/cocotb/controller/Makefile create mode 120000 sim/cocotb/controller/c4m_jtag.py create mode 100644 sim/cocotb/controller/test.py create mode 100644 sim/cocotb/dual_parallel/Makefile create mode 120000 sim/cocotb/dual_parallel/c4m_jtag.py create mode 100644 sim/cocotb/dual_parallel/dual_parallel.vhdl create mode 100644 sim/cocotb/dual_parallel/test.py create mode 100644 sim/cocotb/dual_serial/TODO create mode 100755 sim/ghdl/bench_idcode.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d703adb --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o +*work-*.cf +*~ +*.pyc +results.xml +*.ghw +sim/ghdl/bench_idcode diff --git a/bench/vhdl/idcode.vhdl b/bench/vhdl/idcode.vhdl new file mode 100644 index 0000000..d9c718f --- /dev/null +++ b/bench/vhdl/idcode.vhdl @@ -0,0 +1,99 @@ +-- 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, + STATE => 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/bench/vhdl/sampleshift.vhdl b/bench/vhdl/sampleshift.vhdl new file mode 100644 index 0000000..62ec28b --- /dev/null +++ b/bench/vhdl/sampleshift.vhdl @@ -0,0 +1,50 @@ +-- Test JTAG in the following way: +-- * reset JTAG interface +-- * load samplepreload command +-- * shift in/out sampled inputs + wanted outputs +-- * load extest command +-- * execute + + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity bench_sampleshift is +end bench_sampleshift; + +architecture rtl of bench_sampleshift 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; + + procedure LoadIR( diff --git a/rtl/vhdl/c4m_jtag_idblock.vhdl b/rtl/vhdl/c4m_jtag_idblock.vhdl new file mode 100644 index 0000000..d4353c1 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_idblock.vhdl @@ -0,0 +1,69 @@ +-- The JTAG id and bypass handling block + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_idblock is + generic ( + IR_WIDTH: integer := 2; + + PART_NUMBER: std_logic_vector(15 downto 0); + VERSION: std_logic_vector(3 downto 0) := "0100"; + MANUFACTURER: std_logic_vector(10 downto 0) + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + DRSTATE: in std_logic; + + -- The instruction + IR: in std_logic_vector(IR_WIDTH-1 downto 0) + ); +end c4m_jtag_idblock; + +architecture rtl of c4m_jtag_idblock is + constant IDCODE: std_logic_vector(31 downto 0) := VERSION & PART_NUMBER & MANUFACTURER & "1"; + + signal SR_ID: std_logic_vector(31 downto 0); + signal EN_TDO: boolean; + + constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH); + constant CMD_BYPASS: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_bypass(IR_WIDTH); +begin + process (TCK) + begin + if rising_edge(TCK) then + if DRSTATE = '1' then + case STATE is + when Capture => + SR_ID <= IDCODE; + + when Shift => + if IR = CMD_IDCODE then + SR_ID(30 downto 0) <= SR_ID(31 downto 1); + SR_ID(31) <= TDI; + elsif IR = CMD_BYPASS then + SR_ID(0) <= TDI; + else + null; + end if; + + when others => + null; + end case; + end if; + end if; + end process; + + EN_TDO <= STATE = Shift and DRSTATE = '1' and (IR = CMD_IDCODE or IR = CMD_BYPASS); + TDO <= SR_ID(0) when EN_TDO else + 'Z'; +end rtl; diff --git a/rtl/vhdl/c4m_jtag_ioblock.vhdl b/rtl/vhdl/c4m_jtag_ioblock.vhdl new file mode 100644 index 0000000..ec63440 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_ioblock.vhdl @@ -0,0 +1,88 @@ +-- The block of io cells with JTAG boundary scan support + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_ioblock is + generic ( + IR_WIDTH: integer := 2; + IOS: integer := 1 + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + DRSTATE: in std_logic; + + -- The instruction + IR: in std_logic_vector(IR_WIDTH-1 downto 0); + + -- The I/O access ports + CORE_OUT: in std_logic_vector(IOS-1 downto 0); + CORE_IN: out std_logic_vector(IOS-1 downto 0); + CORE_EN: in std_logic_vector(IOS-1 downto 0); + + -- The pad connections + PAD_OUT: out std_logic_vector(IOS-1 downto 0); + PAD_IN: in std_logic_vector(IOS-1 downto 0); + PAD_EN: out std_logic_vector(IOS-1 downto 0) + ); +end c4m_jtag_ioblock; + +architecture rtl of c4m_jtag_ioblock is + signal IOMODE: SRIOMODE_TYPE; + signal SAMPLEMODE: SRSAMPLEMODE_TYPE; + signal ISSAMPLECMD: boolean; + + signal BDSR_IN: std_logic_vector(IOS-1 downto 0); + signal BDSR_OUT: std_logic_vector(IOS-1 downto 0); + + constant CMD_SAMPLEPRELOAD: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_samplepreload(IR_WIDTH); + constant CMD_EXTEST: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_extest(IR_WIDTH); +begin + -- JTAG baundary scan IO cells + IOGEN: for i in 0 to IOS-1 generate + begin + IOCELL: c4m_jtag_iocell + port map ( + CORE_IN => CORE_IN(i), + CORE_OUT => CORE_OUT(i), + CORE_EN => CORE_EN(i), + PAD_IN => PAD_IN(i), + PAD_OUT => PAD_OUT(i), + PAD_EN => PAD_EN(i), + BDSR_IN => BDSR_IN(i), + BDSR_OUT => BDSR_OUT(i), + IOMODE => IOMODE, + SAMPLEMODE => SAMPLEMODE, + TCK => TCK + ); + end generate; + BDSRCONN: for i in 0 to IOS-2 generate + begin + BDSR_IN(i) <= BDSR_OUT(i+1); + end generate; + BDSR_IN(IOS-1) <= TDI; + + -- Set IOMODE + -- Currently SR_2Core or SR_Z are not used + IOMODE <= SR_2Pad when IR = CMD_EXTEST else + SR_Through; + + -- Set SAMPLEMODE + ISSAMPLECMD <= (IR = CMD_SAMPLEPRELOAD or IR = CMD_EXTEST) and DRSTATE = '1'; + SAMPLEMODE <= SR_Sample when ISSAMPLECMD and STATE = Capture else + SR_Update when ISSAMPLECMD and STATE = Update else + SR_Shift when ISSAMPLECMD and STATE = Shift else + SR_Normal; + + TDO <= BDSR_OUT(0) when ISSAMPLECMD and STATE = Shift else + 'Z'; +end rtl; diff --git a/rtl/vhdl/c4m_jtag_iocell.vhdl b/rtl/vhdl/c4m_jtag_iocell.vhdl new file mode 100644 index 0000000..6a218a6 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_iocell.vhdl @@ -0,0 +1,101 @@ +-- An JTAG boundary scan for bidirectional I/O + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_iocell is + generic ( + IR_WIDTH: integer := 2 + ); + port ( + -- core connections + CORE_IN: out std_logic; + CORE_OUT: in std_logic; + CORE_EN: in std_logic; + + -- pad connections + PAD_IN: in std_logic; + PAD_OUT: out std_logic; + PAD_EN: out std_logic; + + -- BD shift register + BDSR_IN: in std_logic; + BDSR_OUT: out std_logic; + + -- Mode of I/O cell + IOMODE: in SRIOMODE_TYPE; + SAMPLEMODE: in SRSAMPLEMODE_TYPE; + TCK: in std_logic + ); +end c4m_jtag_iocell; + +architecture rtl of c4m_jtag_iocell is + signal SR_IOIN: std_logic; + signal SR_IOOUT: std_logic; + signal SR_IOEN: std_logic; + + signal CORE_IN_BD: std_logic; + signal PAD_OUT_BD: std_logic; + signal PAD_EN_BD: std_logic; +begin + with IOMODE select + CORE_IN <= + PAD_IN when SR_Through | SR_Z, + PAD_IN when SR_2Pad, + CORE_IN_BD when SR_2Core, + 'X' when others; + + with IOMODE select + PAD_OUT <= + CORE_OUT when SR_Through, + PAD_OUT_BD when SR_2Pad, + '0' when SR_2Core | SR_Z, + 'X' when others; + + with IOMODE select + PAD_EN <= + CORE_EN when SR_Through, + PAD_EN_BD when SR_2Pad, + '0' when SR_2Core | SR_Z, + 'X' when others; + + process (TCK) + begin + -- Sampling of inputs and shifting of boundary scan SR needs to be done on + -- rising edge of TCK + if rising_edge(TCK) then + case SAMPLEMODE is + when SR_Sample => + SR_IOIN <= PAD_IN; + SR_IOOUT <= CORE_OUT; + SR_IOEN <= CORE_EN; + + when SR_Shift => + SR_IOIN <= BDSR_IN; + SR_IOOUT <= SR_IOIN; + SR_IOEN <= SR_IOOUT; + + when others => + null; + end case; + end if; + + -- Update of output from boundary scan SR needs to be done on falling edge + -- of TCK + if falling_edge(TCK) then + case SAMPLEMODE is + when SR_Update => + CORE_IN_BD <= SR_IOIN; + PAD_OUT_BD <= SR_IOOUT; + PAD_EN_BD <= SR_IOEN; + + when others => + null; + end case; + end if; + end process; + + BDSR_OUT <= SR_IOEN; +end rtl; diff --git a/rtl/vhdl/c4m_jtag_irblock.vhdl b/rtl/vhdl/c4m_jtag_irblock.vhdl new file mode 100644 index 0000000..e8b34a5 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_irblock.vhdl @@ -0,0 +1,61 @@ +-- Handle the instruction register for the JTAG controller + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_irblock is + generic ( + IR_WIDTH: integer := 2 + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + IRSTATE: in std_logic; + + -- instruction register + IR: out std_logic_vector(IR_WIDTH-1 downto 0) + ); +end c4m_jtag_irblock; + +architecture rtl of c4m_jtag_irblock is + signal SHIFT_IR: std_logic_vector(IR_WIDTH-1 downto 0); + + constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH); +begin + process (TCK, STATE) + begin + if STATE = TestLogicReset then + SHIFT_IR <= (others => '0'); + IR <= CMD_IDCODE; + elsif rising_edge(TCK) then + if IRSTATE = '1' then + case STATE is + when Capture => + SHIFT_IR(1) <= '0'; + SHIFT_IR(0) <= '1'; + + when Shift => + SHIFT_IR(IR_WIDTH-2 downto 0) <= SHIFT_IR(IR_WIDTH-1 downto 1); + SHIFT_IR(IR_WIDTH-1) <= TDI; + + when Update => + IR <= SHIFT_IR; + + when others => + null; + end case; + end if; + end if; + end process; + + TDO <= SHIFT_IR(0) when STATE = Shift and IRSTATE = '1' else + 'Z'; +end rtl; diff --git a/rtl/vhdl/c4m_jtag_pkg.vhdl b/rtl/vhdl/c4m_jtag_pkg.vhdl new file mode 100644 index 0000000..87771f2 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_pkg.vhdl @@ -0,0 +1,213 @@ +-- Package of jtag support code from the Chips4Makers project +library ieee; +use ieee.std_logic_1164.ALL; + +package c4m_jtag is + type TAPSTATE_TYPE is ( + TestLogicReset, + RunTestIdle, + SelectDRScan, + SelectIRScan, + Capture, + Shift, + Exit1, + Pause, + Exit2, + Update + ); + type SRIOMODE_TYPE is ( + SR_Through, -- Connect core signal to pad signals + SR_2Pad, -- Connect BD to pad + SR_2Core, -- Connect BD to core + SR_Z -- pad is high impedance + ); + type SRSAMPLEMODE_TYPE is ( + SR_Normal, -- No sampling or shifting + SR_Sample, -- Sample IO state in BD SR on rising edge of TCK + SR_Update, -- Update BD from SR on falling edge of TCK + SR_Shift -- Shift the BD SR + ); + + component c4m_jtag_tap_fsm is + port ( + -- The TAP signals + TCK: in std_logic; + TMS: in std_logic; + TRST_N: in std_logic; + + -- The state outputs + STATE: out TAPSTATE_TYPE; + NEXT_STATE: out TAPSTATE_TYPE; + DRSTATE: out std_logic; + IRSTATE: out std_logic + ); + end component c4m_jtag_tap_fsm; + + component c4m_jtag_irblock is + generic ( + IR_WIDTH: integer := 2 + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + IRSTATE: in std_logic; + + -- instruction register + IR: out std_logic_vector(IR_WIDTH-1 downto 0) + ); + end component c4m_jtag_irblock; + + component c4m_jtag_idblock is + generic ( + IR_WIDTH: integer := 2; + + PART_NUMBER: std_logic_vector(15 downto 0); + VERSION: std_logic_vector(3 downto 0) := "0000"; + MANUFACTURER: std_logic_vector(10 downto 0) + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + DRSTATE: in std_logic; + + -- The instruction + IR: in std_logic_vector(IR_WIDTH-1 downto 0) + ); + end component c4m_jtag_idblock; + + component c4m_jtag_iocell is + port ( + -- core connections + CORE_IN: out std_logic; + CORE_OUT: in std_logic; + CORE_EN: in std_logic; + + -- pad connections + PAD_IN: in std_logic; + PAD_OUT: out std_logic; + PAD_EN: out std_logic; + + -- BD shift register + BDSR_IN: in std_logic; + BDSR_OUT: out std_logic; + + -- Mode of I/O cell + IOMODE: in SRIOMODE_TYPE; + SAMPLEMODE: in SRSAMPLEMODE_TYPE; + TCK: in std_logic + ); + end component c4m_jtag_iocell; + + component c4m_jtag_ioblock is + generic ( + IR_WIDTH: integer := 2; + IOS: integer := 1 + ); + port ( + -- needed TAP signals + TCK: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + + -- JTAG state + STATE: in TAPSTATE_TYPE; + NEXT_STATE: in TAPSTATE_TYPE; + DRSTATE: in std_logic; + + -- The instruction + IR: in std_logic_vector(IR_WIDTH-1 downto 0); + + -- The I/O access ports + CORE_OUT: in std_logic_vector(IOS-1 downto 0); + CORE_IN: out std_logic_vector(IOS-1 downto 0); + CORE_EN: in std_logic_vector(IOS-1 downto 0); + + -- The pad connections + PAD_OUT: out std_logic_vector(IOS-1 downto 0); + PAD_IN: in std_logic_vector(IOS-1 downto 0); + PAD_EN: out std_logic_vector(IOS-1 downto 0) + ); + end component c4m_jtag_ioblock; + + component c4m_jtag_tap_controller is + generic ( + IR_WIDTH: integer := 2; + IOS: integer := 1; + + VERSION: std_logic_vector(3 downto 0) := "0000" + ); + port ( + -- The TAP signals + TCK: in std_logic; + TMS: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + TRST_N: in std_logic; + + -- The FSM state indicators + STATE: out TAPSTATE_TYPE; + NEXT_STATE: out TAPSTATE_TYPE; + DRSTATE: out std_logic; + + -- The Instruction Register + IR: out std_logic_vector(IR_WIDTH-1 downto 0); + + -- The I/O access ports + CORE_IN: out std_logic_vector(IOS-1 downto 0); + CORE_EN: in std_logic_vector(IOS-1 downto 0); + CORE_OUT: in std_logic_vector(IOS-1 downto 0); + + -- The pad connections + PAD_IN: in std_logic_vector(IOS-1 downto 0); + PAD_EN: out std_logic_vector(IOS-1 downto 0); + PAD_OUT: out std_logic_vector(IOS-1 downto 0) + ); + end component c4m_jtag_tap_controller; + + function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector; + function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector; + function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector; + function c4m_jtag_cmd_extest(width: integer) return std_logic_vector; +end c4m_jtag; + +package body c4m_jtag is + function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector is + variable return_vector: std_logic_vector(width-1 downto 0); + begin + return_vector := (others => '1'); + return return_vector; + end; + + function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector is + variable return_vector: std_logic_vector(width-1 downto 0); + begin + return_vector := (0 => '1', others => '0'); + return return_vector; + end; + + function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector is + variable return_vector: std_logic_vector(width-1 downto 0); + begin + return_vector := (1 => '1', others => '0'); + return return_vector; + end; + + function c4m_jtag_cmd_extest(width: integer) return std_logic_vector is + variable return_vector: std_logic_vector(width-1 downto 0); + begin + return_vector := (others => '0'); + return return_vector; + end; +end package body; diff --git a/rtl/vhdl/c4m_jtag_tap_controller.vhdl b/rtl/vhdl/c4m_jtag_tap_controller.vhdl new file mode 100644 index 0000000..a6f0f15 --- /dev/null +++ b/rtl/vhdl/c4m_jtag_tap_controller.vhdl @@ -0,0 +1,128 @@ +-- A JTAG complient tap controller implementation +-- This is implemented based on the IEEE 1149.1 standard + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_tap_controller is + generic ( + IR_WIDTH: integer := 2; + IOS: integer := 1; + + VERSION: std_logic_vector(3 downto 0) + ); + port ( + -- The TAP signals + TCK: in std_logic; + TMS: in std_logic; + TDI: in std_logic; + TDO: out std_logic; + TRST_N: in std_logic; + + -- The FSM state indicators + STATE: out TAPSTATE_TYPE; + NEXT_STATE: out TAPSTATE_TYPE; + DRSTATE: out std_logic; + + -- The Instruction Register + IR: out std_logic_vector(IR_WIDTH-1 downto 0); + + -- The I/O access ports + CORE_IN: out std_logic_vector(IOS-1 downto 0); + CORE_EN: in std_logic_vector(IOS-1 downto 0); + CORE_OUT: in std_logic_vector(IOS-1 downto 0); + + -- The pad connections + PAD_IN: in std_logic_vector(IOS-1 downto 0); + PAD_EN: out std_logic_vector(IOS-1 downto 0); + PAD_OUT: out std_logic_vector(IOS-1 downto 0) + ); +end c4m_jtag_tap_controller; + +architecture rtl of c4m_jtag_tap_controller is + signal S_STATE: TAPSTATE_TYPE; + signal S_NEXT_STATE: TAPSTATE_TYPE; + signal S_IRSTATE: std_logic; + signal S_DRSTATE: std_logic; + signal S_IR: std_logic_vector(IR_WIDTH-1 downto 0); + + -- TODO: Automate PART_NUMBER generation + constant PART_NUMBER: std_logic_vector(15 downto 0) := "0000000010001001"; + -- TODO: Get manufacturer ID + constant MANUFACTURER: std_logic_vector(10 downto 0) := "00000000000"; +begin + STATE <= S_STATE; + NEXT_STATE <= S_NEXT_STATE; + DRSTATE <= S_DRSTATE; + IR <= S_IR; + + -- JTAG state machine + FSM: c4m_jtag_tap_fsm + port map ( + TCK => TCK, + TMS => TMS, + TRST_N => TRST_N, + STATE => S_STATE, + NEXT_STATE => S_NEXT_STATE, + DRSTATE => S_DRSTATE, + IRSTATE => S_IRSTATE + ); + + -- The instruction register + IRBLOCK: c4m_jtag_irblock + generic map ( + IR_WIDTH => IR_WIDTH + ) + port map ( + TCK => TCK, + TDI => TDI, + TDO => TDO, + STATE => S_STATE, + NEXT_STATE => S_NEXT_STATE, + IRSTATE => S_IRSTATE, + IR => S_IR + ); + + -- The ID + IDBLOCK: c4m_jtag_idblock + generic map ( + IR_WIDTH => IR_WIDTH, + PART_NUMBER => PART_NUMBER, + MANUFACTURER => MANUFACTURER + ) + port map ( + TCK => TCK, + TDI => TDI, + TDO => TDO, + STATE => S_STATE, + NEXT_STATE => S_NEXT_STATE, + DRSTATE => S_DRSTATE, + IR => S_IR + ); + + -- The IOS + IOBLOCK: c4m_jtag_ioblock + generic map ( + IR_WIDTH => IR_WIDTH, + IOS => IOS + ) + port map ( + TCK => TCK, + TDI => TDI, + TDO => TDO, + STATE => S_STATE, + NEXT_STATE => S_NEXT_STATE, + DRSTATE => S_DRSTATE, + IR => S_IR, + CORE_OUT => CORE_OUT, + CORE_IN => CORE_IN, + CORE_EN => CORE_EN, + PAD_OUT => PAD_OUT, + PAD_IN => PAD_IN, + PAD_EN => PAD_EN + ); +end rtl; + + diff --git a/rtl/vhdl/c4m_jtag_tap_fsm.vhdl b/rtl/vhdl/c4m_jtag_tap_fsm.vhdl new file mode 100644 index 0000000..005eccb --- /dev/null +++ b/rtl/vhdl/c4m_jtag_tap_fsm.vhdl @@ -0,0 +1,140 @@ +-- The JTAG state machine +-- This is implemented based on the IEEE 1149.1 standard + +library ieee; +use ieee.std_logic_1164.ALL; + +use work.c4m_jtag.ALL; + +entity c4m_jtag_tap_fsm is + port ( + -- The TAP signals + TCK: in std_logic; + TMS: in std_logic; + TRST_N: in std_logic; + + -- The state outputs + STATE: out TAPSTATE_TYPE; + NEXT_STATE: out TAPSTATE_TYPE; + DRSTATE: out std_logic; + IRSTATE: out std_logic + ); +end c4m_jtag_tap_fsm; + +architecture rtl of c4m_jtag_tap_fsm is + signal S_STATE: TAPSTATE_TYPE; + signal S_NEXT_STATE: TAPSTATE_TYPE; + signal S_DRSTATE: std_logic; + signal S_IRSTATE: std_logic; + signal NEXT_DRSTATE: std_logic; + signal NEXT_IRSTATE: std_logic; +begin + STATE <= S_STATE; + NEXT_STATE <= S_NEXT_STATE; + DRSTATE <= S_DRSTATE; + IRSTATE <= S_IRSTATE; + + process (TCK, TRST_N) + begin + if TRST_N = '0' then + S_DRSTATE <= '0'; + S_IRSTATE <= '0'; + S_STATE <= TestLogicReset; + elsif rising_edge(TCK) then + S_STATE <= S_NEXT_STATE; + S_DRSTATE <= NEXT_DRSTATE; + S_IRSTATE <= NEXT_IRSTATE; + end if; + end process; + + NEXT_DRSTATE <= + '0' when S_NEXT_STATE = TestLogicReset else + '0' when S_NEXT_STATE = RunTestIdle else + '1' when S_NEXT_STATE = SelectDRScan else + '0' when S_NEXT_STATE = SelectIRScan else + S_DRSTATE; + NEXT_IRSTATE <= + '0' when S_NEXT_STATE = TestLogicReset else + '0' when S_NEXT_STATE = RunTestIdle else + '0' when S_NEXT_STATE = SelectDRScan else + '1' when S_NEXT_STATE = SelectIRScan else + S_IRSTATE; + + process (S_STATE, TMS) + begin + case S_STATE is + when TestLogicReset => + if (TMS = '0') then + S_NEXT_STATE <= RunTestIdle; + else + S_NEXT_STATE <= TestLogicReset; + end if; + + when RunTestIdle => + if (TMS = '0') then + S_NEXT_STATE <= RunTestIdle; + else + S_NEXT_STATE <= SelectDRScan; + end if; + + when SelectDRScan => + if (TMS = '0') then + S_NEXT_STATE <= Capture; + else + S_NEXT_STATE <= SelectIRScan; + end if; + + when SelectIRScan => + if (TMS = '0') then + S_NEXT_STATE <= Capture; + else + S_NEXT_STATE <= TestLogicReset; + end if; + + when Capture => + if (TMS = '0') then + S_NEXT_STATE <= Shift; + else + S_NEXT_STATE <= Exit1; + end if; + + when Shift => + if (TMS = '0') then + S_NEXT_STATE <= Shift; + else + S_NEXT_STATE <= Exit1; + end if; + + when Exit1 => + if (TMS = '0') then + S_NEXT_STATE <= Pause; + else + S_NEXT_STATE <= Update; + end if; + + when Pause => + if (TMS = '0') then + S_NEXT_STATE <= Pause; + else + S_NEXT_STATE <= Exit2; + end if; + + when Exit2 => + if (TMS = '0') then + S_NEXT_STATE <= Shift; + else + S_NEXT_STATE <= Update; + end if; + + when Update => + if (TMS = '0') then + S_NEXT_STATE <= RunTestIdle; + else + S_NEXT_STATE <= SelectDRScan; + end if; + + when others => + S_NEXT_STATE <= TestLogicReset; + end case; + end process; +end rtl; diff --git a/sim/cocotb/c4m_jtag.py b/sim/cocotb/c4m_jtag.py new file mode 100644 index 0000000..5deb89a --- /dev/null +++ b/sim/cocotb/c4m_jtag.py @@ -0,0 +1,201 @@ +import cocotb +from cocotb.triggers import Timer +from cocotb.utils import get_sim_steps +from cocotb.binary import BinaryValue + +class JTAG_Clock(object): + """ + Class for the JTAG clock, run cycle by cycle + """ + def __init__(self, signal, period): + self.signal = signal + self.t = Timer(period/4) + + @cocotb.coroutine + def Cycle(self, cycles=1): + """ + Do one or more cycles + Cycle start in middle of 0 pulse of the clock + """ + for i in range(cycles): + self.signal <= 0 + yield self.t + self.signal <= 1 + yield self.t + yield self.t + self.signal <= 0 + yield self.t + +class JTAG_Master(object): + """ + Class that will run JTAG commands, shift in and out data + """ + #TODO: Handle a JTAG chain with more than one device + + def __init__(self, tck, tms, tdi, tdo, trst_n=None, clk_period=1000): + self.tck = tck + self.clkgen = JTAG_Clock(tck, clk_period) + tck <= 0 + self.tms = tms + tms <= 1 + self.tdi = tdi + tdi <= 0 + self.tdo = tdo + self.trst_n = trst_n + trst_n <= 1 + self.period = Timer(clk_period) + + # Standard commands + # TODO: make IR length configurable; now 2 is assumed + self.BYPASS = [1, 1] + self.IDCODE = [0, 1] + self.SAMPLEPRELOAD = [1, 0] + self.EXTEST = [0, 0] + + # After command we always leave the controller in reset or runidle state + # If value is None we will always reset the interface + self.state = None + + # The methods of this class are coroutines. The results will be stored + # in the result field + self.result = None + + @cocotb.coroutine + def cycle_clock(self, cycles=1): + if self.state == "Run" and self.tms: + self.state = "Scan" + yield self.clkgen.Cycle(cycles) + + @cocotb.coroutine + def reset(self): + if not self.trst_n is None: + # Enable reset signal for one clock period + self.trst_n <= 0 + yield self.period + self.trst_n <= 1 + else: + # 5 cycles with tms on 1 should reset the JTAG TAP controller + self.tms <= 1 + yield self.cycle_clock(5) + + self.state = "Reset" + + self.result = None + + @cocotb.coroutine + def change_state(self, tms_list): + tms_copy = list(tms_list) + while tms_copy: + self.tms <= tms_copy.pop() + yield self.cycle_clock() + self.result = None + + @cocotb.coroutine + def change_to_run(self): + """ + Put TAP in RunTestIdle state + self.result is bool and true if TAP went through reset state + """ + isreset = False + if self.state is None: + yield self.reset() + if self.state is "Reset": + isreset = True + self.tms <= 0 + yield self.cycle_clock() + self.state = "Run" + assert(self.state == "Run") + self.result = isreset + + @cocotb.coroutine + def load_ir(self, cmd): + cmd_copy = list(cmd) + result = BinaryValue(bits=len(cmd_copy)) + l_result = list() + + yield self.change_to_run() + # Go to Capture/IR + yield self.change_state([0, 1, 1]) + + # Shift the two + self.tms <= 0 + while cmd_copy: + # In first iteration we enter SHIFT state and tdo is made active + yield self.cycle_clock() + # For the last iteration tdi will be shifted when entering next state + self.tdi <= cmd_copy.pop() + l_result.insert(0, str(self.tdo)) + + # Go to RunTestIdle + yield self.change_state([0, 1, 1]) + self.state = "Run" + + @cocotb.coroutine + def idcode(self): + """ + Get the IDCODE from the device + result will contain the 32 bit IDCODE of the device + """ + + result = BinaryValue(bits=32) + l_result = list() + + # Keep tdi 0 for the whole run + self.tdi <= 0 + + yield self.change_to_run() + if not self.result: + # If TAP was not reset we have to load IDCODE command + yield self.load_ir(self.IDCODE) + + # Should be again in RUN state + assert(self.state == "Run") + + # Go to Shift/DR + yield self.change_state([0, 0, 1]) + + # Enter Shift; run for 32 cycles + self.tms <= 0 + for i in range(32): + l_result.insert(0, str(self.tdo)) + yield self.cycle_clock() + result.binstr = "".join(l_result) + + # Go to RunTestIdle + yield self.change_state([0, 1, 1]) + self.state = "Run" + + self.result = result + + @cocotb.coroutine + def shift_data(self, data_in): + """ + Shift data in through the JTAG and capture the output + Input can be of type BinaryValue or an iterable value of 0 and 1s. + Last bit will be shifted in first. + result will contain the sample TDO with the same number of bits as the input + """ + if isinstance(data_in, BinaryValue): + data_copy = [int(c) for c in data_in.binstr] + else: + data_copy = list(data_in) + result = BinaryValue() + l_result = list() + + yield self.change_to_run() + # Go to Capture/DR + yield self.change_state([0, 1]) + + # Shift data through + self.tms <= 0 + while data_copy: + yield self.cycle_clock() + self.tdi <= data_copy.pop() + l_result.insert(0, str(self.tdo)) + result.binstr = "".join(l_result) + + # Go to RunTestIdle + yield self.change_state([0, 1, 1]) + self.state = "Run" + + self.result = result diff --git a/sim/cocotb/controller/Makefile b/sim/cocotb/controller/Makefile new file mode 100644 index 0000000..336d7e5 --- /dev/null +++ b/sim/cocotb/controller/Makefile @@ -0,0 +1,19 @@ +COCOTB=$(HOME)/eda/code/cocotb +VHDLDIR=$(HOME)/eda/code/c4m_jtag/rtl/vhdl +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 +SIM_ARGS=--wave=test.ghw + +include $(COCOTB)/makefiles/Makefile.inc +include $(COCOTB)/makefiles/Makefile.sim diff --git a/sim/cocotb/controller/c4m_jtag.py b/sim/cocotb/controller/c4m_jtag.py new file mode 120000 index 0000000..f409baa --- /dev/null +++ b/sim/cocotb/controller/c4m_jtag.py @@ -0,0 +1 @@ +../c4m_jtag.py \ No newline at end of file diff --git a/sim/cocotb/controller/test.py b/sim/cocotb/controller/test.py new file mode 100644 index 0000000..c29d00e --- /dev/null +++ b/sim/cocotb/controller/test.py @@ -0,0 +1,95 @@ +import cocotb +from cocotb.triggers import Timer +from cocotb.utils import get_sim_steps +from cocotb.binary import BinaryValue + +from 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/sim/cocotb/dual_parallel/Makefile b/sim/cocotb/dual_parallel/Makefile new file mode 100644 index 0000000..f692e4f --- /dev/null +++ b/sim/cocotb/dual_parallel/Makefile @@ -0,0 +1,20 @@ +COCOTB=$(HOME)/eda/code/cocotb +VHDLDIR=$(HOME)/eda/code/c4m_jtag/rtl/vhdl +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 \ + $(PWD)/dual_parallel.vhdl +TOPLEVEL=dual_parallel +TOPLEVEL_LANG=vhdl +MODULE=test +SIM=ghdl +GPI_IMPL=vhpi +SIM_ARGS=--wave=test.ghw + +include $(COCOTB)/makefiles/Makefile.inc +include $(COCOTB)/makefiles/Makefile.sim diff --git a/sim/cocotb/dual_parallel/c4m_jtag.py b/sim/cocotb/dual_parallel/c4m_jtag.py new file mode 120000 index 0000000..f409baa --- /dev/null +++ b/sim/cocotb/dual_parallel/c4m_jtag.py @@ -0,0 +1 @@ +../c4m_jtag.py \ No newline at end of file diff --git a/sim/cocotb/dual_parallel/dual_parallel.vhdl b/sim/cocotb/dual_parallel/dual_parallel.vhdl new file mode 100644 index 0000000..0e99559 --- /dev/null +++ b/sim/cocotb/dual_parallel/dual_parallel.vhdl @@ -0,0 +1,78 @@ +-- 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, + STATE => open, + NEXT_STATE => 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, + STATE => open, + NEXT_STATE => 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/sim/cocotb/dual_parallel/test.py b/sim/cocotb/dual_parallel/test.py new file mode 100644 index 0000000..51f868d --- /dev/null +++ b/sim/cocotb/dual_parallel/test.py @@ -0,0 +1,43 @@ +import cocotb +from cocotb.triggers import Timer +from cocotb.utils import get_sim_steps +from cocotb.binary import BinaryValue + +from 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/sim/cocotb/dual_serial/TODO b/sim/cocotb/dual_serial/TODO new file mode 100644 index 0000000..e69de29 diff --git a/sim/ghdl/bench_idcode.sh b/sim/ghdl/bench_idcode.sh new file mode 100755 index 0000000..1717ae0 --- /dev/null +++ b/sim/ghdl/bench_idcode.sh @@ -0,0 +1,5 @@ +#!/bin/sh +ghdl -i ../../rtl/vhdl/c4m_jtag_*.vhdl +ghdl -i ../../bench/vhdl/idcode.vhdl +ghdl -m bench_idcode +./bench_idcode --wave=bench_idcode.ghw -- 2.30.2