VHDL中的双向双向

时间:2015-12-01 18:50:36

标签: vhdl bidirectional

所以我听说无法通过双向数据端口而不知道协议(或没有控制线)。 (见tie two inout together vhdl

但是,我真的很喜欢这样做,我真的不想知道协议。 SO ...

我想从SIM智能卡(从手机)传递DATA线。目前一切都有效,除了DATA线,这是双向的。

我还没有确认这一点,但我的范围暗示该线被拉高,任何一方都可以根据需要将其拉下来。我想利用从外部拉高的线路。

我想尝试以下注释代码中列出的两个选项:

architecture Behavioral of SIM_Select_Test_A is

begin

process(MOD_CLK, MOD_RST)
begin
    SIM_RST     <= MOD_RST;
    SIM_CLK <= MOD_CLK;
end process;

-- OPTION ONE1
--  process(MOD_CLK, MOD_DATA, SIM_DATA)
--  begin
--      IF MOD_DATA = '0' THEN
--          SIM_DATA <= '0';
--      ELSE
--          IF SIM_DATA = '0' THEN
--              MOD_DATA <= '0';
--          ELSE
--              MOD_DATA <= MOD_DATA;
--              SIM_DATA <= SIM_DATA;
--          END IF;
--      END IF;
--  end process;

-- OPTION 2
--  process(MOD_CLK, MOD_DATA, SIM_DATA)
--  begin
--      IF MOD_DATA = '0' THEN
--          SIM_DATA <= '0';
--      ELSE
--          IF SIM_DATA = '0' THEN
--              MOD_DATA <= '0';
--          ELSE
--              MOD_DATA <= 'Z';
--              SIM_DATA <= 'Z';
--          END IF;
--      END IF;
--  end process;

end Behavioral;

有人可以确认,如果我将SIM_DATA驱动为低电平,我将不会进入第二个ELSE,因此将MOD_DATA驱动为低电平(即进入某个循环逻辑)

如果我应该追求这条道路,或者我绝对需要知道协议的任何评论。如果是这样,我想我会开始研究:(

提前致谢, 库尔特

编辑: 添加我的实体声明:

entity SIM_Select_Test_A is
Port ( SIM_VCC : OUT STD_LOGIC;
       SIM_DATA : inout  STD_LOGIC;
       SIM_RST : out  STD_LOGIC;
       SIM_CLK : out  STD_LOGIC;
          MOD_VCC : in STD_LOGIC;
       MOD_DATA : inout  STD_LOGIC;
       MOD_RST : in  STD_LOGIC;
       MOD_CLK : in  STD_LOGIC);
    attribute bufg : string;
    attribute bufg of MOD_CLK : signal is "CLK";
    attribute bufg of MOD_DATA : signal is "OE";
end SIM_Select_Test_A;

编辑2: 哇,谢谢你的详细回复。 是的,我可以看到你在说什么。我想我希望的是,我可以在代码中添加一些智能,以便在CPLD控制线路和优先考虑wire1时意识到这一点。所以你的评论让我正式化了我的想法,这就是我得到的。为伪代码道歉,但我希望它能使事情变得更清晰,当我把它编入脑中时,它总能很好地工作:)

IF (wire1 = '0' AND flag = '0') THEN
    wire2 <= '0' <--here wire1 gets priority and wire2 is controlled based on wire1.  My hope is that when it is at this point in the code then it does NOT fall into the else statement.
ELSE  <-- IF (wire1 is NOT low OR there is a flag) THEN check if wire2 is low (which in my head seems slightly different than elsif
    IF (wire2 = '0') THEN
       wire1 <= '0';
       flag  <= '1'; <-- I think this is where there might be a problem.  I am trying to use the flag to tell the outer IF that the CPLD holding wire1 low and to ignore it
    ELSE <--neither are being held low externally
       wire1 <= 'HIZ';
       wire2 <= 'HIZ';
       flag  <= '0';
    END IF
END IF;

我会看看今天是否可以模拟,但感谢您的任何评论。

2 个答案:

答案 0 :(得分:0)

编辑此答案仅适用于,如果无法对截获的总线上的数据传输做出任何假设。请查看my other answer

即使使用由电阻器上拉的漏极开路/集电极开路总线也无法做到这一点。实际上,电阻器可以集成到一个IC中,但它们总是放在焊盘和I / O驱动器之间,因此也可以放在总线上。

拦截看起来像这样:IC1 <--wire1--> FPGA <--wire2--> IC2

让我们假设在启动后截获的总线空闲,然后电阻将两条线拉高。如果IC1拉低wire1,则FPGA也会下拉wire2。但现在,FPGA还会读取wire2被拉下来,因此也会降低wire1。现在,两条线都被FPGA下拉。即使IC1禁用其输出驱动程序,也会保留此状态。

如果您不相信,请尝试使用此VHDL代码。

library ieee;
use ieee.std_logic_1164.all;

entity intercept_open_drain_bus is
  port (
    wire1 : inout std_logic;
    wire2 : inout std_logic);
end entity intercept_open_drain_bus;

architecture rtl of intercept_open_drain_bus is
begin
  -- Assume port is pulled-up externally.
  wire1 <= '0' when wire2 = '0' else 'Z';
  wire2 <= '0' when wire1 = '0' else 'Z';
end architecture rtl;

以下是运行上述场景的测试平台:

library ieee;
use ieee.std_logic_1164.all;

entity intercept_open_drain_bus_tb is
end entity intercept_open_drain_bus_tb;

architecture sim of intercept_open_drain_bus_tb is
  signal wire1 : std_logic;
  signal wire2 : std_logic;
begin
  DUT: entity work.intercept_open_drain_bus
    port map (
      wire1 => wire1,
      wire2 => wire2);

  -- external PULLUP resistor
  wire1 <= 'H';
  wire2 <= 'H';

  WaveGen_Proc: process
  begin
    -- both far-end ICs have their outputs disabled
    wire1 <= 'Z';
    wire2 <= 'Z';
    wait for 1 ns; 
    assert (wire1 = 'H') and (wire2 = 'H') report "initial pullup failed." severity error;

    -- IC 1 pulls down wire 1
    wire1 <= '0';
    wait for 1 ns; 
    assert (wire2 = '0') report "passing from wire1 failed." severity error;

    -- IC 1 disables its output again
    wire1 <= 'Z';
    wait for 1 ns; 
    assert (wire1 = 'H') and (wire2 = 'H') report "pullup after transfer failed." severity error;
    wait;
  end process WaveGen_Proc;
end architecture sim;

这是模拟器输出显示最后一个测试用例失败(在黄色标记的右侧):

waveform from testbench, just showing the scenario which has been desricbed above

答案 1 :(得分:0)

如果可以对截获的双向总线的数据传输做出至少一些假设,则该答案适用。如果不能做出任何假设,那么my other answer仍然是正确的。

拦截看起来像这样:IC1 <--wire1--> FPGA <--wire2--> IC2

如果可以做出至少这些假设,那么解决方案是可能的:

  • 总线在数据传输IC1 - > IC2和IC2 - > IC1之间空闲。

  • FPGA可以由一个时钟(来自外部振荡器)驱动,该时钟至少比总线的信号速率快10倍。

该解决方案需要一个有限状态机,其中状态跟踪哪一侧(IC1或IC2)实际上拉下线。如果一个IC拉下线,FPGA会拉低另一个IC。如果IC释放导线并且导线由电阻器上拉,则FPGA也会释放另一根导线。但是现在,我们必须等到另一根导线被自己的电阻上拉,然后再检查该导线以便向另一个方向传输数据。

以下是代码:

library ieee;
use ieee.std_logic_1164.all;

entity intercept_open_drain_bus2 is
  port (
    clock : in std_logic;
    wire1 : inout std_logic;
    wire2 : inout std_logic);
end entity intercept_open_drain_bus2;

architecture rtl of intercept_open_drain_bus2 is
  type state_t is (IDLE, PULLDOWN1, WAIT1, PULLDOWN2, WAIT2);
  signal state : state_t := IDLE;
begin

  -- Moore outputs from finite state machine
  wire1 <= '0' when state = PULLDOWN1 else 'Z';
  wire2 <= '0' when state = PULLDOWN2 else 'Z';

  -- finite state machine
  process(clock)
  begin
    if rising_edge(clock) then
      case state is
        when IDLE =>
          if wire2 = '0' then
            state <= PULLDOWN1;
          elsif wire1 = '0' then
            state <= PULLDOWN2;
          end if;

        when PULLDOWN1 =>
          if wire2 /= '0' then -- 'H' or '1'
            state <= WAIT1;
          end if;

        when WAIT1 => -- wait until wire1 is pulled-up by the resistor
          if wire1 /= '0' then
            state <= IDLE;
          end if;

        when PULLDOWN2 =>
          if wire1 /= '0' then -- 'H' or '1'
            state <= WAIT2;
          end if;

        when WAIT2 => -- wait until wire2 is pulled-up by the resistor
          if wire2 /= '0' then
            state <= IDLE;
          end if;
      end case;
    end if;
  end process;
end architecture rtl;

这是测试平台:

library ieee;
use ieee.std_logic_1164.all;

entity intercept_open_drain_bus2_tb is
end entity intercept_open_drain_bus2_tb;

architecture sim of intercept_open_drain_bus2_tb is
  signal clock   : std_logic := '1';
  signal wire1   : std_logic;
  signal wire2   : std_logic;
  signal STOPPED : boolean   := false;

begin
  DUT: entity work.intercept_open_drain_bus2
    port map (
      clock => clock,
      wire1 => wire1,
      wire2 => wire2);

  -- 100 MHz FPGA clock from external oscillator
  clock <= not clock after 5 ns when not STOPPED;

  -- external PULLUP resistor
  wire1 <= 'H';
  wire2 <= 'H';

  WaveGen_Proc: process
  begin
    -- both far-end ICs have their outputs disabled
    wire1 <= 'Z';
    wire2 <= 'Z';
    wait until rising_edge(clock);
    assert (wire1 = 'H') and (wire2 = 'H') report "initial pullup failed." severity error;

    -- IC 1 pulls down wire 1 for at least 10 FPGA clock cycles
    wire1 <= '0';
    wait until rising_edge(clock);
    -- wire2 is changing here in the real world
    for i in 2 to 10 loop
      wait until rising_edge(clock);
      assert (wire2 = '0') report "passing from wire1 failed." severity error;
    end loop;

    -- IC 1 disables its output again for at least 10 FPGA clock cycles
    wire1 <= 'Z';
    wait until rising_edge(clock);
    -- wire2 is changing here in the real world
    for i in 2 to 10 loop
      wait until rising_edge(clock);
      assert (wire1 = 'H') and (wire2 = 'H') report "pullup after transfer failed." severity error;
    end loop;

    -- IC 2 pulls down wire 1 for at least 10 FPGA clock cycles
    wire2 <= '0';
    wait until rising_edge(clock);
    -- wire1 is changing here in the real world
    for i in 2 to 10 loop
      wait until rising_edge(clock);
      assert (wire1 = '0') report "passing from wire2 failed." severity error;
    end loop;

    -- IC 2 disables its output again for at least 10 FPGA clock cycles
    wire2 <= 'Z';
    wait until rising_edge(clock);
    -- wire1 is changing here in the real world
    for i in 2 to 10 loop
      wait until rising_edge(clock);
      assert (wire2 = 'H') and (wire1 = 'H') report "pullup after transfer failed." severity error;
    end loop;

    STOPPED <= true;
    wait;
  end process WaveGen_Proc;
end architecture sim;

现在,模拟器输出看起来不错:

waveform from simulating the testbench