--- /dev/null
+*.o
+*work-*.cf
+*~
+*.pyc
+results.xml
+*.ghw
+sim/ghdl/bench_idcode
--- /dev/null
+-- 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;
--- /dev/null
+-- 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(
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
+
+
--- /dev/null
+-- 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;
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+../c4m_jtag.py
\ No newline at end of file
--- /dev/null
+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([])
+
--- /dev/null
+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
--- /dev/null
+../c4m_jtag.py
\ No newline at end of file
--- /dev/null
+-- 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;
--- /dev/null
+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")
--- /dev/null
+#!/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