www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Modelsim Problem- bidirektionaler Bus


Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

habe ein Problem bei meiner Simulation mit Modelsim:
Habe einen bidirektionalen Bus (16Bit) der vom I/O-Pad aus mit einem
IBUF16 + IBUFT16 meinen Eingangsbus treibt und meinen Ausgangsbus
arbeitet mittels eines OBUFT16 auf das selbe I/O-PAD.
Wenn ich nun in der Simulation (beide Buffer tristate) irgendwelche
Daten auf den BUS lege, so zeigt mir die Simulation jedoch immer
z-state, obwohl ich sicher Signale auf dem Bus habe. Ich lasse mir
explizit die Signale direkt am (Pad-)Bus anzeigen, also eingansseitig
"vor" den Buffern.
Hier müßte eigentlich das, in der Testbench erzeugt Datum, sichtbar
werden. Es ist aber immer z-State, außer ich enable den Ausgangstreiber
(OBUF). Dann wird der Ausgangsbus sichtbar durchgeschaltet.
Woran mag das liegen und wie kann ich das umgehen?
Danke, Daniel

Autor: Joachim Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Komisch, keine Antwort?
Scheint wohl niemand das Problem zu haben.
Ich jedenfalls habe dasselbe Problem.
Alle Eingangsdaten auf einen Tristatebus, welche ich in der Testbench
erzeuge, werden nur als Z-State dargestellt, also quasi ignoriert.
Bin Anfänger.
Habe das Problem provisorisch umgangen, indem ich den Eingangstreiber
durchschalte und mir die Daten HINTER dem Eingangstreiber anzeigen
lasse.

Autor: Jörn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Postet mal euren Code bzw. Schaltpläne und macht am besten noch einen
Screenshot vom Modelsim-Wavefenster.

@Daniel: Warum hast du den IBUF und OBUF als Tristate ausgelegt (wenn
ich das richtig verstanden habe)? Es ist wichtig, dass der OBUF
Tristate fähig ist.

Gruß Jörn

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welch Ironie: Ich hänge gerade an einem ähnlichen Problem, weshalb ich
(erstmal) keinen neuen Thread aufmache.

Das Problem: Der TB funktioniert für Lese- und Schreib-Operationen
getrennt (jeweils andere sukommentiert), erst wenn ich die im TB
zusammen scharf mache, kollieren die beiden rd/wr Operationen, sprich
es gibt 'nen Kurzen ('X'):
entity la_register is
   generic (
      BIT_WIDTH      : natural   := 16;
      ...
   port (
      rd               : in    std_logic;
      wr               : in    std_logic;
      address          : in    addr_t;
      data             : inout std_logic_vector(BIT_WIDTH-1 downto 0);
   ...
end entity la_register;

architecture behaviorial of la_register is
begin
   ....
   translate : process (clk, reset) is
   begin    
      if (reset = RESET_ACTIVE) then
         ....
         data                            <= (others => 'Z');
      elsif rising_edge(clk) then
         if (wr = '1') and (rd = '0') then
            case address
              ....
              a_register <= data;
         elsif (rd = '1') and (wr = '0') then
            case address
               ...
               data <= a_register;
         else
            data <= (others => 'Z');
         end if;
      end if;
   end process translate;
end architecture behaviorial;

Habe ich hier irgendwo einen Denkfehler?

Viele Grüße
Olaf

Autor: Jörn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Olaf,

wie sieht die TB dazu aus?

Gruß Jörn

Autor: ope (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
recht harmlos =)  Ich hänge ihn mal komplett ran. In den packages sind
viele Konstanten und Records drinnen. Konstanten sind gross
geschrieben, wie zB. Adressen und Addressoffsets bzw. Bits.

Interessant sind evtl. die trigger records:
package pkg_trigger is

   type pattern_edge_comb_t is (
      unknown,
      and_comb,
      or_comb,
      xor_comb);

   constant LA_HIT_LENGTH : positive := 8;

   type trigger_cond_t is
   record
      -- pattern trigger config registers
      pattern_value     : la_vector_t;
      pattern_mask      : la_vector_t;
      -- edge trigger config registers
      edge_rising       : la_vector_t;
      edge_falling      : la_vector_t;
      edge_mask         : la_vector_t;
      -- internal trigger extensions
      pattern_edge_comb : pattern_edge_comb_t;
      length_value      : unsigned(LA_HIT_LENGTH-1 downto 0);
      invert            : std_logic;
   end record;

   type trigger_match_t is record -- list what matched
      pattern : std_logic;
      edge    : std_logic;
      length  : std_logic;
   end record trigger_match_t;

   type ext_trigger_cond_t is
   record
      active_level : std_logic;
   end record;
   
end package pkg_trigger;

Viele Grüße
Olaf

Autor: ope (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
und hier das komplette file.

Autor: ope (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
ok, da das Problem anscheinend öfter mal auftaucht, hier ein kurzes Bsp.
wie es funktioniert. Bei meinem TB muss der Wurm also irgendwo noch
versteckt sein. Also ein ganz gewöhlicher, gemeiner und hinterhältiger,
fieser Fehler :/

Viele Grüße
Olaf
library ieee;
use ieee.std_logic_1164.all;

entity bus_test is
end entity bus_test;

architecture behaviorial of bus_test is
   signal   done       : boolean                         := false;
   signal   clk, reset : std_logic                       := '0';
   signal   address    : std_logic_vector(7 downto 0);
   signal   data       : std_logic_vector(7 downto 0);
   signal   my_data    : std_logic_vector(data'range);
   signal   rd, wr     : std_logic;
   signal   m_register : std_logic_vector(data'range);
   constant MY_ADDRESS : std_logic_vector(address'range) :=
b"10000000";
   constant TST_DATA   : std_logic_vector(data'range)    :=
b"10101010";
begin

   clk_proc : process is
      constant PERIOD : time := 10 ns;
   begin
      clk <= '0';
      if done then wait; end if;
      wait for PERIOD/2;
      clk <= '1';
      wait for PERIOD/2;
   end process clk_proc;

   rst : reset <= '1', '0' after 15 ns;

   rdwr_proc : process (clk, reset) is
   begin
      if (reset = '1') then
         data <= (others => 'Z');
      elsif rising_edge(clk) then
         if (wr = '1') and (rd = '0') then
            case address is
               when MY_ADDRESS => m_register <= data;
               when others     => null;
            end case;
         elsif (wr = '0') and (rd = '1') then
            case address is
               when MY_ADDRESS => data <= m_register;
               when others     => null;
            end case;
         else
            data <= (others => 'Z');
         end if;
      end if;
   end process rdwr_proc;

   TB : process
      is

      procedure tic is
      begin
         wait until rising_edge(clk);
      end procedure tic;

      procedure do_wr is
      begin
         wr      <= '1';
         address <= MY_ADDRESS;
         data    <= TST_DATA;
         tic;
         wr      <= '0';
      end procedure do_wr;

      procedure do_rd is
      begin
         rd      <= '1';
         address <= MY_ADDRESS;
         tic;
         my_data <= data;
         rd      <= '0';
      end procedure do_rd;
      
   begin
      my_data <= (others => '0');
      rd      <= '0';
      wr      <= '0';
      wait until (reset = '0');
      tic;
      tic;

      do_wr;
      tic;
      do_rd;
      assert (my_data = TST_DATA) report "* shit *" severity error;
      tic;
      done <= true;

   end process TB;
end architecture behaviorial;

Autor: Jörn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
???

Ich seh in deinem Screenshot nur, dass du mache Signal nicht
initialisierst ('U'). Die Ursache liegt in deinem Design.Die Signal
werden nicht vom Reset in einen definierten Zustand gebracht.

Gruß Jörn

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das ist richtig, Address-, Datenbus und das Register sind uninitialized.
Im richtigen Design sollten sie einen def. Wert erhalten. Hier werden
sie im Prozess des schreibens/lesens sukzessive mit Werten befüllt. Ich
habe sie extra frei gelassen um die Zuweisung 'augenfällig' zu
bekommen, für die Funktion des rd/wr tut's aber keinen Abbruch (darauf
kam es mir bei dem Testfile an).

Viele Grüße
Olaf

Autor: ope (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
OK, noch eine Lösung mit mehreren Registern ohne Kollision:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bus_test is
end entity bus_test;

architecture behaviorial of bus_test is
   signal   done        : boolean    := false;
   signal   clk, reset  : std_logic  := '0';
   signal   address     : unsigned(7 downto 0);
   signal   data        : std_logic_vector(7 downto 0);
   signal   my_data     : std_logic_vector(data'range);
   signal   rd, wr      : std_logic;
   constant MY_ADDRESS1 : unsigned(address'range) := b"1000_0000";
   constant MY_ADDRESS2 : unsigned(address'range) := b"1001_0000";
   constant TST_DATA1   : std_logic_vector(data'range)
      := b"10101010";
   constant TST_DATA2   : std_logic_vector(data'range)
      := b"01010101";
begin

   clk_proc : process is
      constant PERIOD : time := 10 ns;
   begin
      clk <= '0';
      if done then wait; end if;
      wait for PERIOD/2;
      clk <= '1';
      wait for PERIOD/2;
   end process clk_proc;

   rst : reset <= '1', '0' after 15 ns;

   register_set : block is
      signal m_register1 : std_logic_vector(data'range);
      signal m_register2 : std_logic_vector(data'range);
   begin
      rdwr_proc : process (clk, reset) is
      begin
         if (reset = '1') then
            data <= (others => 'Z');
         elsif rising_edge(clk) then
            if (wr = '1') and (rd = '0') then
               case address is
                  when MY_ADDRESS1 => m_register1 <= data;
                  when MY_ADDRESS2 => m_register2 <= data;
                  when others      => null;
               end case;
            elsif (wr = '0') and (rd = '1') then
               case address is
                  when MY_ADDRESS1 => data <= m_register1;
                  when MY_ADDRESS2 => data <= m_register2;
                  when others      => null;
               end case;
            else
               data <= (others => 'Z');
            end if;
         end if;
      end process rdwr_proc;
   end block register_set;

   TB : process is
      ------------------------------------------
      procedure tic is
      begin
         wait until rising_edge(clk);
      end procedure tic;
      ------------------------------------------
      procedure do_wr (
         constant addr : in unsigned;
         constant dat  : in std_logic_vector) is
      begin
         wr      <= '1';
         address <= addr;
         data    <= dat;
         tic;
         wr      <= '0';
         data    <= (others => 'Z'); 
      end procedure do_wr;
      ------------------------------------------
      procedure do_rd (
         constant addr : in  unsigned;
         signal   dat  : out std_logic_vector) is
      begin
         rd      <= '1';
         address <= addr;
         tic;tic;
         dat     <= data;
         rd      <= '0';
      end procedure do_rd;
      ------------------------------------------
   begin
      my_data <= (others => '0');
      rd      <= '0';
      wr      <= '0';
      address <= (others => '0');
      data    <= (others => '0');
      wait until (reset = '0');
      tic; tic;

      do_wr(MY_ADDRESS1, TST_DATA1);
      do_wr(MY_ADDRESS2, TST_DATA2);

      do_rd(MY_ADDRESS1, my_data);
      do_rd(MY_ADDRESS2, my_data);

      assert (my_data = TST_DATA1)
         report "* missmatch 1 *" severity error;
      tic;
      assert (my_data = TST_DATA2)
         report "* missmatch 2 *" severity error;

      tic;
      done <= true;

   end process TB;
end architecture behaviorial;

Allerdings wird damit die Leserate halbiert. Gibt's einen schnelleren
Weg des Lesens?

Viele Grüße
Olaf

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.