【问题标题】:Bidirectional to bidirectional in VHDLVHDL中的双向到双向
【发布时间】:2015-12-01 18:50:36
【问题描述】:

所以我听说在不知道协议(或没有控制线)的情况下通过双向数据端口是不可能的。 (见tie two inout together vhdl

但是,我真的很想这样做,而且我真的不想知道协议。所以...

我想通过 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 驱动为低电平(即进入一些循环逻辑)

如果我应该追求这条途径或者我是否绝对需要了解协议,任何 cmets。如果是这样,我想我会开始研究:(

提前致谢, 库尔特

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

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 何时控制线路并优先考虑线路 1。所以你的cmets让我把我的想法正式化,这就是我得到的。为伪代码道歉,但我希望它能让事情更清楚,当我在脑海中编译它时它总是能很好地工作:)

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;

我会看看我今天是否可以模拟,但感谢您可能拥有的任何 cmet。

【问题讨论】:

  • 您对这些陈述有何期待:MOD_DATA &lt;= MOD_DATA;SIM_DATA &lt;= SIM_DATA;?能否请您发布实体声明和测试平台。
  • 对于那些代码行,我只想让行保持不变。但你是对的——当我更多地看它们时,我更喜欢选项 2 的 HIZ。
  • 还将我的实体声明添加到问题中。

标签: vhdl bidirectional


【解决方案1】:

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

拦截看起来像这样:IC1 &lt;--wire1--&gt; FPGA &lt;--wire2--&gt; IC2

如果至少可以做出以下假设,则解决方案是可能的:

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

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

该解决方案需要一个有限状态机,其中状态会跟踪哪一侧(IC1 或 IC2)实际拉低了线路。如果一个 IC 拉下他的线,FPGA 拉下另一个。如果 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;

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

【讨论】:

  • 非常感谢!你提供了一些很棒的专业知识,我真的很感激!
【解决方案2】:

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

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

拦截看起来像这样:IC1 &lt;--wire1--&gt; FPGA &lt;--wire2--&gt; 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;

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

【讨论】:

  • 非常感谢您提供这些信息 - 我已经更新了我的问题并进行了一些澄清。
  • 我同意你的 cmets 可能无法完成但想进一步充实我的想法。
猜你喜欢
  • 1970-01-01
  • 2012-06-13
  • 1970-01-01
  • 2019-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-22
  • 2014-07-29
相关资源
最近更新 更多