Support for different IO types in VHDL code.
authorStaf Verhaegen <staf@stafverhaegen.be>
Mon, 6 Jan 2020 17:05:06 +0000 (18:05 +0100)
committerStaf Verhaegen <staf@stafverhaegen.be>
Mon, 6 Jan 2020 17:05:06 +0000 (18:05 +0100)
IO cells can now be input, output, tri-state output, tri-state
inout. Update tests and added separate test for c4m_jtag_ioblock.

12 files changed:
c4m/vhdl/jtag/c4m_jtag_ioblock.vhdl
c4m/vhdl/jtag/c4m_jtag_iocell.vhdl
c4m/vhdl/jtag/c4m_jtag_pkg.vhdl
c4m/vhdl/jtag/c4m_jtag_tap_controller.vhdl
test/vhdl/cocotb/controller/Makefile
test/vhdl/cocotb/controller/controller.vhdl [new file with mode: 0644]
test/vhdl/cocotb/controller/test.py
test/vhdl/cocotb/dual_parallel/dual_parallel.vhdl
test/vhdl/cocotb/ioblock/Makefile [new file with mode: 0644]
test/vhdl/cocotb/ioblock/ioblock.vhdl [new file with mode: 0644]
test/vhdl/cocotb/ioblock/test.py [new file with mode: 0644]
test/vhdl/ghdl/idcode/idcode.vhdl

index 10a592c8cc3bea9e495a809c668582ca4aed365a..7b58d2d5b98dcdaa8003e26dd64ae3cd22584f58 100644 (file)
@@ -8,7 +8,7 @@ use work.c4m_jtag.ALL;
 entity c4m_jtag_ioblock is
   generic (
     IR_WIDTH:   integer := 2;
-    IOS:        integer := 1
+    IOTYPES:    IOTYPE_VECTOR
   );
   port (
     -- needed TAP signals
@@ -26,14 +26,14 @@ entity c4m_jtag_ioblock is
     UPDATE:     in std_logic;
 
     -- 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);
+    CORE_OUT:   in std_logic_vector(IOTYPES'range);
+    CORE_IN:    out std_logic_vector(IOTYPES'range);
+    CORE_EN:    in std_logic_vector(IOTYPES'range);
 
     -- 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)
+    PAD_OUT:    out std_logic_vector(IOTYPES'range);
+    PAD_IN:     in std_logic_vector(IOTYPES'range);
+    PAD_EN:     out std_logic_vector(IOTYPES'range)
   );
 end c4m_jtag_ioblock;
 
@@ -42,16 +42,20 @@ architecture rtl of c4m_jtag_ioblock is
   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);
+  signal BDSR_IN:       std_logic_vector(0 to IOTYPES'length-1);
+  signal BDSR_OUT:      std_logic_vector(0 to IOTYPES'length-1);
   
   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
+  IOGEN: for i in IOTYPES'low to IOTYPES'high generate
   begin
     IOCELL: c4m_jtag_iocell
+      generic map (
+        IOTYPE => IOTYPES(i)
+      )
       port map (
         CORE_IN => CORE_IN(i),
         CORE_OUT => CORE_OUT(i),
@@ -59,23 +63,25 @@ begin
         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),
+        BDSR_IN => BDSR_IN(i-IOTYPES'low),
+        BDSR_OUT => BDSR_OUT(i-IOTYPES'low),
         IOMODE => IOMODE,
         SAMPLEMODE => SAMPLEMODE,
         TCK => TCK
       );
   end generate;
-  BDSRCONN: for i in 0 to IOS-2 generate
+  BDSRCONN: for i in 0 to BDSR_IN'length-2 generate
   begin
     BDSR_IN(i+1) <= BDSR_OUT(i);
   end generate;
-  BDSR_IN(0) <= TDI;
+  BDSR_IN(BDSR_IN'low) <= TDI;
 
   -- Set IOMODE
-  -- Currently SR_2Core or SR_Z are not used
+  -- Currently SR_2Pad, SR_2Core or SR_Z are not used
+  -- We cheat by letting CMD_EXTEST handle both connection
+  -- to pad and core.
   -- TODO: Handle more IOMODEs
-  IOMODE <= SR_2Pad when IR = CMD_EXTEST else
+  IOMODE <= SR_2PadCore when IR = CMD_EXTEST else
             SR_Through;
 
   -- Set SAMPLEMODE
@@ -85,7 +91,7 @@ begin
                 SR_Shift when ISSAMPLECMD and SHIFT = '1' else
                 SR_Normal;
 
-  TDO <= BDSR_OUT(IOS-1) when ISSAMPLECMD and SHIFT = '1' else
+  TDO <= BDSR_OUT(BDSR_IN'high) when ISSAMPLECMD and SHIFT = '1' else
          '0';
   TDO_EN <= '1' when ISSAMPLECMD and SHIFT = '1' else
             '0';
index 6a218a6e2071d07059b510a1cdc3192da10b2657..b37c62622d1fbedcb4006de02b0b5d0bdb65fbf8 100644 (file)
@@ -7,7 +7,7 @@ use work.c4m_jtag.ALL;
 
 entity c4m_jtag_iocell is
   generic (
-    IR_WIDTH:   integer := 2
+    IOTYPE:     IOTYPE_TYPE
   );
   port (
     -- core connections
@@ -35,67 +35,127 @@ architecture rtl of c4m_jtag_iocell is
   signal SR_IOIN: std_logic;
   signal SR_IOOUT: std_logic;
   signal SR_IOEN: std_logic;
+  signal SR_IOIN_next: std_logic;
+  signal SR_IOOUT_next: std_logic;
+  signal SR_IOEN_next: 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;
+  --
+  -- CORE_* and PAD_* signals
+  --
+  INPUT_gen: if IOTYPE = IO_IN or IOTYPE = IO_INOUT3 generate
+    with IOMODE select
+    CORE_IN <=
+      PAD_IN when SR_Through | SR_Z,
+      PAD_IN when SR_2Pad,
+      CORE_IN_BD when SR_2Core | SR_2PadCore,
+      'X' when others;
+  end generate INPUT_gen;
+  NOINPUT_gen: if IOTYPE /= IO_IN and IOTYPE /= IO_INOUT3 generate
+    CORE_IN <= 'X';
+  end generate NOINPUT_gen;
+
+  OUTPUT_gen: if IOTYPE /= IO_IN generate
+    with IOMODE select
+    PAD_OUT <=
+      CORE_OUT when SR_Through,
+      PAD_OUT_BD when SR_2Pad | SR_2PadCore,
+      '0' when SR_2Core | SR_Z,
+      'X' when others;
+  end generate OUTPUT_gen;
+  NOOUTPUT_gen: if IOTYPE = IO_IN generate
+    PAD_OUT <= 'X';
+  end generate NOOUTPUT_gen;
+
+  ENABLE_gen: if IOTYPE = IO_OUT3 or IOTYPE = IO_INOUT3 generate
+    with IOMODE select
+    PAD_EN <=
+      CORE_EN when SR_Through,
+      PAD_EN_BD when SR_2Pad | SR_2PadCore,
+      '0' when SR_2Core | SR_Z,
+      'X' when others;
+  end generate ENABLE_gen;
+  NOENABLE_gen: if IOTYPE /= IO_OUT3 and IOTYPE /= IO_INOUT3 generate
+    PAD_EN <= 'X';
+  end generate NOENABLE_gen;
+
+
+  --
+  -- SR_* signals
+  --
+  IOIN_WITHIN_gen: if IOTYPE = IO_IN or IOTYPE = IO_INOUT3 generate
+    with SAMPLEMODE select
+      SR_IOIN_next <=
+        PAD_IN when SR_Sample,
+        BDSR_IN when SR_Shift,
+        SR_IOIN when others;
+  end generate IOIN_WITHIN_gen;
+  IOIN_NOIN_gen: if IOTYPE /= IO_IN and IOTYPE /= IO_INOUT3 generate
+    SR_IOIN_next <= 'X';
+  end generate IOIN_NOIN_gen;
+
+  IOOUT_NOINWITHOUT_gen: if IOTYPE = IO_OUT or IOTYPE = IO_OUT3 generate
+    with SAMPLEMODE select
+      SR_IOOUT_next <=
+        CORE_OUT when SR_Sample,
+        BDSR_IN when SR_Shift,
+        SR_IOOUT when others;
+  end generate IOOUT_NOINWITHOUT_gen;
+  IOOUT_WITHINOUT_gen: if IOTYPE = IO_INOUT3 generate
+    with SAMPLEMODE select
+      SR_IOOUT_next <=
+        CORE_OUT when SR_Sample,
+        SR_IOIN when SR_Shift,
+        SR_IOOUT when others;
+  end generate IOOUT_WITHINOUT_gen;
+  IOOUT_NOOUT_gen: if IOTYPE = IO_IN generate
+    SR_IOOUT_next <= 'X';
+  end generate IOOUT_NOOUT_gen;
+
+  IOEN_WITHOUT3_gen: if IOTYPE = IO_OUT3 or IOTYPE = IO_INOUT3 generate
+    with SAMPLEMODE select
+      SR_IOEN_next <=
+        CORE_EN when SR_Sample,
+        SR_IOOUT when SR_Shift,
+        SR_IOEN when others;
+  end generate IOEN_WITHOUT3_gen;
+  IOEN_NOOUT3_gen: if IOTYPE /= IO_OUT3 and IOTYPE /= IO_INOUT3 generate
+    SR_IOEN_next <= 'X';
+  end generate IOEN_NOOUT3_gen;
 
   process (TCK)
   begin
     -- Sampling of inputs and shifting of boundary scan SR needs to be done on
-    -- rising edge of TCK
+    -- 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;
+      SR_IOIN <= SR_IOIN_next;
+      SR_IOOUT <= SR_IOOUT_next;
+      SR_IOEN <= SR_IOEN_next;
     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;
+    if falling_edge(TCK) and SAMPLEMODE = SR_Update then
+      CORE_IN_BD <= SR_IOIN;
+      PAD_OUT_BD <= SR_IOOUT;
+      PAD_EN_BD <= SR_IOEN;
     end if;
   end process;
 
-  BDSR_OUT <= SR_IOEN;
+
+  --
+  -- BDSR_OUT signal
+  --
+  BDSROUT_NOOUT_gen: if IOTYPE = IO_IN generate
+    BDSR_OUT <= SR_IOIN;
+  end generate BDSROUT_NOOUT_gen;
+  BDSROUT_WITHOUT_gen: if IOTYPE = IO_OUT generate
+    BDSR_OUT <= SR_IOOUT;
+  end generate BDSROUT_WITHOUT_gen;
+  BDSROUT_WITHOUT3_gen: if IOTYPE = IO_OUT3 or IOTYPE = IO_INOUT3 generate
+    BDSR_OUT <= SR_IOEN;
+  end generate BDSROUT_WITHOUT3_gen;
 end rtl;
index 443a07c1561e9c4bdd1d33cade2652c8c7325e6d..7912914b41aa0bac1abecf6790a6fbf563aeb282 100644 (file)
@@ -7,6 +7,7 @@ package c4m_jtag is
     SR_Through, -- Connect core signal to pad signals
     SR_2Pad,    -- Connect BD to pad
     SR_2Core,   -- Connect BD to core
+    SR_2PadCore, -- Connect BD to pad and core
     SR_Z        -- pad is high impedance
   );
   type SRSAMPLEMODE_TYPE is (
@@ -15,11 +16,21 @@ package c4m_jtag is
     SR_Update,  -- Update BD from SR on falling edge of TCK
     SR_Shift    -- Shift the BD SR
   );
+  type IOTYPE_TYPE is (
+    IO_IN,      -- Input only
+    IO_OUT,     -- Output only, without tristate
+    IO_OUT3,    -- Output only, with tristate
+    IO_INOUT3   -- Input and output with tristate
+  );
+  type IOTYPE_VECTOR is array ( natural range <> ) of IOTYPE_TYPE;
+
+  constant IOTYPES_NULL: IOTYPE_VECTOR(1 to 0) := (others => IO_INOUT3);
 
   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;
+  function gen_iotypes(count: integer; iotype: IOTYPE_TYPE := IO_INOUT3) return IOTYPE_VECTOR;
 
   component c4m_jtag_tap_fsm is
     port (
@@ -88,6 +99,9 @@ package c4m_jtag is
   end component c4m_jtag_idblock;
 
   component c4m_jtag_iocell is
+    generic (
+      IOTYPE:   IOTYPE_TYPE
+    );
     port (
       -- core connections
       CORE_IN:  out std_logic;
@@ -113,7 +127,7 @@ package c4m_jtag is
   component c4m_jtag_ioblock is
     generic (
       IR_WIDTH: integer := 2;
-      IOS:      integer := 1
+      IOTYPES:  IOTYPE_VECTOR
     );
     port (
       -- needed TAP signals
@@ -125,20 +139,20 @@ package c4m_jtag is
       -- The instruction
       IR:       in std_logic_vector(IR_WIDTH-1 downto 0);
 
-      -- What action to perform
+      -- actions
       CAPTURE:  in std_logic;
       SHIFT:    in std_logic;
       UPDATE:   in std_logic;
 
       -- 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);
+      CORE_OUT: in std_logic_vector(IOTYPES'range);
+      CORE_IN:  out std_logic_vector(IOTYPES'range);
+      CORE_EN:  in std_logic_vector(IOTYPES'range);
 
       -- 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)
+      PAD_OUT:  out std_logic_vector(IOTYPES'range);
+      PAD_IN:   in std_logic_vector(IOTYPES'range);
+      PAD_EN:   out std_logic_vector(IOTYPES'range)
     );
   end component c4m_jtag_ioblock;
 
@@ -147,7 +161,7 @@ package c4m_jtag is
       DEBUG:            boolean := false;
 
       IR_WIDTH:         integer := 2;
-      IOS:              integer := 1;
+      IOTYPES:          IOTYPE_VECTOR := IOTYPES_NULL;
 
       -- The default MANUFACTURING ID is not representing a valid
       -- manufacturer according to the JTAG standard
@@ -171,15 +185,16 @@ package c4m_jtag is
       CAPTURE:  out std_logic; -- In DR_Capture state
       SHIFT:    out std_logic; -- In DR_Shift state
       UPDATE:   out std_logic; -- In DR_Update state
+
       -- 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);
+      CORE_IN:  out std_logic_vector(IOTYPES'range);
+      CORE_EN:  in std_logic_vector(IOTYPES'range);
+      CORE_OUT: in std_logic_vector(IOTYPES'range);
 
       -- 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)
+      PAD_IN:   in std_logic_vector(IOTYPES'range);
+      PAD_EN:   out std_logic_vector(IOTYPES'range);
+      PAD_OUT:  out std_logic_vector(IOTYPES'range)
     );
   end component c4m_jtag_tap_controller;
 end c4m_jtag;
@@ -212,4 +227,11 @@ package body c4m_jtag is
     return_vector := (others => '0');
     return return_vector;
   end;
+
+  function gen_iotypes(count: integer; iotype: IOTYPE_TYPE := IO_INOUT3) return IOTYPE_VECTOR is
+    variable return_vector: IOTYPE_VECTOR(0 to count-1);
+  begin
+    return_vector := (others => iotype);
+    return return_vector;
+  end function gen_iotypes;
 end package body;
index f29c8f86f3aa1cacf6e09b05c916e6277428df6a..cfdf2f99a37029ba96e18bdc973880ecbccdb29e 100644 (file)
@@ -11,7 +11,7 @@ entity c4m_jtag_tap_controller is
     DEBUG:              boolean := false;
 
     IR_WIDTH:           integer := 2;
-    IOS:                integer := 1;
+    IOTYPES:            IOTYPE_VECTOR := IOTYPES_NULL;
 
     MANUFACTURER:       std_logic_vector(10 downto 0) := "10001111111";
     PART_NUMBER:        std_logic_vector(15 downto 0) := "0000000000000001";
@@ -35,18 +35,20 @@ entity c4m_jtag_tap_controller is
     UPDATE:     out std_logic;
 
     -- 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);
+    CORE_IN:    out std_logic_vector(IOTYPES'range);
+    CORE_EN:    in std_logic_vector(IOTYPES'range);
+    CORE_OUT:   in std_logic_vector(IOTYPES'range);
 
     -- 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)
+    PAD_IN:     in std_logic_vector(IOTYPES'range);
+    PAD_EN:     out std_logic_vector(IOTYPES'range);
+    PAD_OUT:    out std_logic_vector(IOTYPES'range)
   );
 end c4m_jtag_tap_controller;
 
 architecture rtl of c4m_jtag_tap_controller is
+  constant null_logic_vector: std_logic_vector(1 to 0) := (others => 'X');
+
   signal S_RESET:       std_logic;
   signal S_ISIR:        std_logic;
   signal S_ISDR:        std_logic;
@@ -117,29 +119,38 @@ begin
       SHIFT => S_SHIFT and S_ISDR,
       UPDATE => S_UPDATE and S_ISDR
     );
-  
-  -- The IOS
-  IOBLOCK: c4m_jtag_ioblock
-    generic map (
-      IR_WIDTH => IR_WIDTH,
-      IOS => IOS
-    )
-    port map (
-      TCK => TCK,
-      TDI => TDI,
-      TDO => IO_TDO,
-      TDO_EN => IO_TDO_EN,
-      IR => S_IR,
-      CAPTURE => S_CAPTURE and S_ISDR,
-      SHIFT => S_SHIFT and S_ISDR,
-      UPDATE => S_UPDATE and S_ISDR,
-      CORE_OUT => CORE_OUT,
-      CORE_IN => CORE_IN,
-      CORE_EN => CORE_EN,
-      PAD_OUT => PAD_OUT,
-      PAD_IN => PAD_IN,
-      PAD_EN => PAD_EN
-    );
+
+  -- The IOs
+  IOBLOCK_gen: if IOTYPES'length > 0 generate
+    IOBLOCK: c4m_jtag_ioblock
+      generic map (
+        IR_WIDTH => IR_WIDTH,
+        IOTYPES => IOTYPES
+      )
+      port map (
+        TCK => TCK,
+        TDI => TDI,
+        TDO => IO_TDO,
+        TDO_EN => IO_TDO_EN,
+        IR => S_IR,
+        CAPTURE => S_CAPTURE and S_ISDR,
+        SHIFT => S_SHIFT and S_ISDR,
+        UPDATE => S_UPDATE and S_ISDR,
+        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 generate IOBLOCK_gen;
+  NOIOBLOCK_gen: if IOTYPES'length = 0 generate
+    IO_TDO <= '0';
+    IO_TDO_EN <= '0';
+    CORE_IN <= null_logic_vector;
+    PAD_EN <= null_logic_vector;
+    PAD_OUT <= null_logic_vector;
+  end generate NOIOBLOCK_gen;
 
   TDO <= IR_TDO when IR_TDO_EN = '1' else
          ID_TDO when ID_TDO_EN = '1' else
@@ -155,5 +166,3 @@ begin
       severity ERROR;
   end generate CHECK_EN;
 end rtl;
-
-
index 05b570de247c2a0b771e538002635d23db3be8ea..836f3114fba4c5a28240fb9012606e27f863f579 100644 (file)
@@ -16,8 +16,10 @@ VHDL_SOURCES = \
   $(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
+  $(VHDLDIR)/c4m_jtag_tap_controller.vhdl \
+  $(CURDIR)/controller.vhdl
+#VHDL_SOURCES end
+TOPLEVEL=controller
 TOPLEVEL_LANG=vhdl
 MODULE=test
 SIM=ghdl
diff --git a/test/vhdl/cocotb/controller/controller.vhdl b/test/vhdl/cocotb/controller/controller.vhdl
new file mode 100644 (file)
index 0000000..35be680
--- /dev/null
@@ -0,0 +1,76 @@
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+package controller_pkg is
+  constant IOTYPES:     IOTYPE_VECTOR(0 to 3) := (
+    0 => IO_IN,
+    1 => IO_OUT,
+    2 => IO_OUT3,
+    3 => IO_INOUT3
+  );
+end package controller_pkg;
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+use work.controller_pkg.ALL;
+
+entity controller is
+  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 Instruction Register
+    IR:         out std_logic_vector(1 downto 0);
+
+    -- The FSM state indicators
+    RESET:      out std_logic;
+    CAPTURE:    out std_logic;
+    SHIFT:      out std_logic;
+    UPDATE:     out std_logic;
+
+    -- The I/O access ports
+    CORE_IN:    out std_logic_vector(IOTYPES'range);
+    CORE_EN:    in std_logic_vector(IOTYPES'range);
+    CORE_OUT:   in std_logic_vector(IOTYPES'range);
+
+    -- The pad connections
+    PAD_IN:     in std_logic_vector(IOTYPES'range);
+    PAD_EN:     out std_logic_vector(IOTYPES'range);
+    PAD_OUT:    out std_logic_vector(IOTYPES'range)
+  );
+end controller;
+
+architecture rtl of controller is
+begin
+  ctrl: c4m_jtag_tap_controller
+    generic map (
+      DEBUG => true,
+      IOTYPES => IOTYPES
+    )
+    port map (
+      TCK => TCK,
+      TMS => TMS,
+      TDI => TDI,
+      TDO => TDO,
+      TRST_N => TRST_N,
+      IR => IR,
+      RESET => RESET,
+      CAPTURE => CAPTURE,
+      SHIFT => SHIFT,
+      UPDATE => UPDATE,
+      CORE_IN => CORE_IN,
+      CORE_EN => CORE_EN,
+      CORE_OUT => CORE_OUT,
+      PAD_IN => PAD_IN,
+      PAD_EN => PAD_EN,
+      PAD_OUT => PAD_OUT
+    );
+end architecture rtl;
index 477219438f263cce6998cac9af256d6ff37dfe14..fc83b197ab16860134d2f8d0f500ab4b71613b6f 100644 (file)
@@ -63,31 +63,31 @@ def test03_sample(dut):
     dut._log.info("Load SAMPLEPRELOAD command")
     yield master.load_ir(master.SAMPLEPRELOAD)
 
-    data_in.binstr = "011"
+    data_in.binstr = "0101110"
     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
+    dut.core_out = BinaryValue("X010")
+    dut.core_en = BinaryValue("XX01")
+    dut.pad_in = BinaryValue("1XX0")
     yield master.shift_data(data_in)
     dut._log.info("  output: {}".format(master.result.binstr))
-    assert(master.result.binstr == "100")
+    assert(master.result.binstr == "1010001")
 
 
     dut._log.info("Load EXTEST command")
     yield master.load_ir(master.EXTEST)
 
-    data_in.binstr = "100"
+    data_in.binstr = "1010001"
     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
+    dut.core_out = BinaryValue("X101")
+    dut.core_en = BinaryValue("XX10")
+    dut.pad_in = BinaryValue("0XX1")
     yield master.shift_data(data_in)
     dut._log.info("  output: {}".format(master.result.binstr))
-    assert(master.result.binstr == "011")
+    assert(master.result.binstr == "0101110")
 
     dut._log.info("Do a capture of the last loaded data")
     yield master.shift_data([])
index 870ea102070086a7ed2a86d365d73b367389927e..836c42fe3b79f8ede0a6772c768fa74d38d1396a 100644 (file)
@@ -5,6 +5,17 @@ use ieee.std_logic_1164.ALL;
 
 use work.c4m_jtag.ALL;
 
+package dual_parallel_pkg is
+  constant IOTYPES:     IOTYPE_VECTOR(0 to 0) := (0 => IO_INOUT3);
+end package dual_parallel_pkg;
+
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+use work.dual_parallel_pkg.ALL;
+
 entity dual_parallel is
   port (
     -- Instance 1
@@ -36,6 +47,10 @@ architecture rtl of dual_parallel is
   signal I2_PAD_OUT:    std_logic;
 begin
   CTRL1: c4m_jtag_tap_controller
+    generic map (
+      DEBUG => true,
+      IOTYPES => IOTYPES
+    )
     port map (
       TCK => I1_TCK,
       TMS => I1_TMS,
@@ -56,6 +71,10 @@ begin
     );
 
   CTRL2: c4m_jtag_tap_controller
+    generic map (
+      DEBUG => true,
+      IOTYPES => IOTYPES
+    )
     port map (
       TCK => I2_TCK,
       TMS => I2_TMS,
diff --git a/test/vhdl/cocotb/ioblock/Makefile b/test/vhdl/cocotb/ioblock/Makefile
new file mode 100644 (file)
index 0000000..5b9dbba
--- /dev/null
@@ -0,0 +1,26 @@
+CURDIR=$(realpath .)
+TOPDIR=$(realpath ../../../..)
+
+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)/ioblock.vhdl \
+#end VHDL_SOURCES
+TOPLEVEL=ioblock
+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/ioblock/ioblock.vhdl b/test/vhdl/cocotb/ioblock/ioblock.vhdl
new file mode 100644 (file)
index 0000000..e3bf078
--- /dev/null
@@ -0,0 +1,69 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.c4m_jtag.all;
+
+package ioblock_pkg is
+  constant IOTYPES: IOTYPE_VECTOR(0 to 3) := (
+    0 => IO_IN,
+    1 => IO_OUT,
+    2 => IO_OUT3,
+    3 => IO_INOUT3
+  );
+  constant IR_WIDTH: integer := 2;
+end package ioblock_pkg;
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.c4m_jtag.all;
+use work.ioblock_pkg.all;
+
+entity ioblock is
+  port (
+    TCK:        in std_logic;
+    TDI:        in std_logic;
+    TDO:        out std_logic;
+    TDO_EN:     out std_logic;
+
+    IR:         in std_logic_vector(IR_WIDTH-1  downto 0);
+
+    CAPTURE:    in std_logic;    
+    SHIFT:      in std_logic;
+    UPDATE:     in std_logic;
+
+    CORE_OUT:   in std_logic_vector(IOTYPES'range);
+    CORE_IN:    out std_logic_vector(IOTYPES'range);
+    CORE_EN:    in std_logic_vector(IOTYPES'range);
+
+    PAD_OUT:    out std_logic_vector(IOTYPES'range);
+    PAD_IN:     in std_logic_vector(IOTYPES'range);
+    PAD_EN:     out std_logic_vector(IOTYPES'range)
+  );
+end entity ioblock;
+
+architecture rtl of ioblock is
+begin
+  blck: c4m_jtag_ioblock
+    generic map (
+      IR_WIDTH => IR_WIDTH,
+      IOTYPES => IOTYPES
+    )
+    port map (
+      TCK => TCK,
+      TDI => TDI,
+      TDO => TDO,
+      TDO_EN => TDO_EN,
+      IR => IR,
+      CAPTURE => CAPTURE,
+      SHIFT => SHIFT,    
+      UPDATE => UPDATE,
+      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 architecture rtl;
diff --git a/test/vhdl/cocotb/ioblock/test.py b/test/vhdl/cocotb/ioblock/test.py
new file mode 100644 (file)
index 0000000..d9e386e
--- /dev/null
@@ -0,0 +1,94 @@
+import cocotb
+from cocotb.utils import get_sim_steps
+from cocotb.binary import BinaryValue
+from cocotb.triggers import Timer
+
+def report_bdsr(dut):
+    for handle in dut.blck:
+        if handle._name.startswith("iogen"):
+            for handle2 in handle:
+                if handle2._name == "iocell":
+                    values = {}
+                    for handle3 in handle2:
+                        if handle3._name in ("bdsr_in", "bdsr_out", "sr_ioin", "sr_ioout", "sr_ioen"):
+                            values[handle3._name] = handle3.value.binstr
+                    dut._log.info("{}: {!r}".format(handle2._path, values))
+
+@cocotb.test()
+def test01_boundaryscan(dut):
+    """
+    Check initialization
+    """
+    dut.ir = 0
+    dut.tck = 0
+    dut.tdi = 1
+    dut.capture = 0
+    dut.shift = 0
+    dut.update = 0
+
+    # Boundary scan: IN > OUT > OUT3 > INOUT3
+    # Length: 1 + 1 + 2 + 3 = 7
+
+    yield Timer(1)
+
+    report_bdsr(dut)
+
+    assert dut.core_in.value.binstr == "UXXU"
+    assert dut.pad_out.value.binstr == "XUUU"
+    assert dut.pad_en.value.binstr == "XXUU"
+
+    dut.ir = BinaryValue("10") # SAMPLEPRELOAD
+    dut.core_out = BinaryValue("0000")
+    dut.core_en = BinaryValue("0000")
+    dut.pad_in = BinaryValue("0000")
+    yield Timer(1)
+
+    assert dut.core_in.value.binstr == "0XX0"
+    assert dut.pad_out.value.binstr == "X000"
+    assert dut.pad_en.value.binstr == "XX00"
+
+    dut.capture = 1
+    yield Timer(1)
+    dut.tck = 1
+    yield Timer(1)
+    dut.capture = 0
+    dut.tck = 0
+    yield Timer(1)
+
+    assert dut.core_in.value.binstr == "0XX0"
+    assert dut.pad_out.value.binstr == "X000"
+    assert dut.pad_en.value.binstr == "XX00"
+
+    dut.shift = 1
+    yield Timer(1)
+    for i in range(7):
+        dut._log.info("Cycle {}".format(i))
+        report_bdsr(dut)
+        assert dut.tdo.value.binstr == "0"
+        dut.tck = 1
+        yield Timer(1)
+        dut.tck = 0
+        yield Timer(1)
+    dut._log.info("Cycle 7")
+    report_bdsr(dut)
+    assert dut.tdo.value.binstr == "1"
+
+    dut.shift = 0
+    dut.update = 1
+    yield Timer(1)
+    dut.tck = 1
+    yield Timer(1)
+    dut.update = 0
+    dut.tck = 0
+    yield Timer(1)
+
+    assert dut.core_in.value.binstr == "0XX0"
+    assert dut.pad_out.value.binstr == "X000"
+    assert dut.pad_en.value.binstr == "XX00"
+
+    dut.ir = BinaryValue("00") # EXTEST
+    yield Timer(1)
+    
+    assert dut.core_in.value.binstr == "0XX0"
+    assert dut.pad_out.value.binstr == "X111"
+    assert dut.pad_en.value.binstr == "XX11"
index cc7d167852ab062340e6f51ee96b7886d7982251..05848b3ec5d800d65656ba14649297a35446da8b 100644 (file)
@@ -16,6 +16,7 @@ architecture rtl of bench_idcode is
   signal TRST_N: std_logic;
 
   constant CLK_PERIOD:  time := 10 ns;
+  constant NULL_STDVECTOR: std_logic_vector(1 to 0) := (others => 'X');
 
   procedure ClkCycle(
     signal CLK: out std_logic;
@@ -54,11 +55,11 @@ begin
       SHIFT => open,
       UPDATE => open,
       IR => open,
-      CORE_OUT => "0",
+      CORE_OUT => NULL_STDVECTOR,
       CORE_IN => open,
-      CORE_EN => "0",
+      CORE_EN => NULL_STDVECTOR,
       PAD_OUT => open,
-      PAD_IN => "0",
+      PAD_IN => NULL_STDVECTOR,
       PAD_EN => open
     );