2016-07-11 18 views
1

Dies ist meine erste Zeitbuchung, also werde ich versuchen, so spezifisch wie möglich zu sein.Verwenden von "For-Loop" für Adressierungsmethode in generischem VHDL-Code

In dem Teil des Codes, den ich posten werde, versuche ich in generischer Weise den Code in der "Case" -ausdruck, die ich auskommentiert habe zu implementieren. Dieser Code ist Teil einer größeren Implementierung und ich habe nur die Signale behalten, die derzeit in diesem Code verwendet werden.

So ist das, was ich meine Ausgaben „kin“ und „din“ sein generisch und nach dem, was kommt „BUS_A“, die richtigen Worte in dem Adreßbus als Eingabe wollen (2 - Byte lang) der Register "kin_2" und "din_2" sollte zu diesem Zeitpunkt mit dem Wert "bus_di" eingegeben werden.

Für mein Beispiel hier, ich werde die ursprünglichen Längen für „kin“ und „din“ verwenden, die jeweils 128 Bit sind. Also für 128-Bit-Länge, N = 16 (16 * 8-Bit = 128bit) und K = 8.

library IEEE; 
use IEEE.NUMERIC_STD.ALL; 
use IEEE.STD_LOGIC_1164.ALL; 

entity stck_if is 
    generic (N: integer:=16; K: integer:=8); 

    port ( -------------- Clock and Reset 
     clk: in std_logic; 
     rst: in std_logic; 


     bus_a: in std_logic_vector (15 downto 0); -- Address 
     bus_di: in std_logic_vector (15 downto 0); --Data In 

     kin: out std_logic_vector (8*N-1 downto 0); 
     din: out std_logic_vector (8*N-1 downto 0));  

end stck_if; 

architecture stck_if_arch of stck_if is 

     signal kin_2: std_logic_vector (8*N-1 downto 0); 
     signal din_2: std_logic_vector (8*N-1 downto 0); 
     signal encdec_2: std_logic; 

     signal trig_wr: std_logic; 

     begin 

      proc1: process(clk,rst) 
       variable int_add: integer:=0; 
       variable add: std_logic_vector (15 downto 0); 
       variable bit_add: std_logic_vector (15 downto 0); 
       begin 
        if rst='1' then 
         encdec_2<='0'; 
         kin_2<=(others =>'0'); 
         din_2<=(others =>'0'); 
        elsif (clk'event and clk='1') then 
         if (trig_wr = '1') then 

          if (bus_a = "0000000000001100") then 
            encdec_2 <= bus_di(0); 
          end if; 

          for i in 0 to K-1 loop 
           bit_add:="0000000100000000"; 
           int_add:= 2*i; 
           add:=std_logic_vector(to_unsigned(int_add, 16)); 
           bit_add:= std_logic_vector(unsigned(bit_add) + unsigned(add)); 
           if (bus_a = bit_add) then 
             kin_2((8*(N-int_add)-1) downto 8*(N-int_add)) <= bus_di; 
           end if;        
          end loop; 


          for i in 0 to K-1 loop 
           bit_add:="0000000101000000"; 
           int_add:= 2*i; 
           add:=std_logic_vector(to_unsigned(int_add, 16)); 
           bit_add:= std_logic_vector(unsigned(bit_add) + unsigned(add)); 
           if (bus_a = bit_add) then 
             din_2((8*(N-int_add)-1) downto 8*(N-int_add)) <= bus_di; 
           end if;        
          end loop; 



          --case bus_a is 
          -- when "0000000000001100"=> encdec_2 <= bus_di(0); --bus_a = 000C hex 
          -- when "0000000100000000"=> kin_2(127 downto 112) <= bus_di; --bus_a = 0100 hex 
          -- when "0000000100000010"=> kin_2(111 downto 96) <= bus_di; --bus_a = 0102 hex 
          -- when "0000000100000100"=> kin_2(95 downto 80) <= bus_di; --bus_a = 0104 hex 
          -- when "0000000100000110"=> kin_2(79 downto 64) <= bus_di; --bus_a = 0106 hex                   
          -- when "0000000100001000"=> kin_2(63 downto 48) <= bus_di; --bus_a = 0108 hex 
          -- when "0000000100001010"=> kin_2(47 downto 32) <= bus_di; --bus_a = 010A hex 
          -- when "0000000100001100"=> kin_2(31 downto 16) <= bus_di; --bus_a = 010C hex 
          -- when "0000000100001110"=> kin_2(15 downto 0) <= bus_di; --bus_a = 010E hex 

          -- when "0000000101000000"=> din_2(127 downto 112) <= bus_di; --bus_a = 0140 hex 
          -- when "0000000101000010"=> din_2(111 downto 96) <= bus_di; --bus_a = 0142 hex 
          -- when "0000000101000100"=> din_2(95 downto 80) <= bus_di; --bus_a = 0144 hex 
          -- when "0000000101000110"=> din_2(79 downto 64) <= bus_di; --bus_a = 0146 hex                   
          -- when "0000000101001000"=> din_2(63 downto 48) <= bus_di; --bus_a = 0148 hex 
          -- when "0000000101001010"=> din_2(47 downto 32) <= bus_di; --bus_a = 014A hex 
          -- when "0000000101001100"=> din_2(31 downto 16) <= bus_di; --bus_a = 014C hex 
          -- when "0000000101001110"=> din_2(15 downto 0) <= bus_di; --bus_a = 014E hex 
          -- when others => null;      
          --end case; 
         end if; 
        end if; 
      end process; 



      kin <= kin_2; 
      din <= din_2; 

end stck_if_arch; 

I ModelSim PE Student Edition 10.4a verwenden. Um den Betrieb der Implementierung zu simulieren, habe ich den folgenden Code in der Befehlszeile von ModelSim: kompiliert

restart -f 

//clock period 20ns 
force -freeze sim:/stck_if/clk 1 0, 0 {10 ns} -r 20 


//Activate reset 
force -freeze sim:/stck_if/rst 1 0 
run 

//activate wr 
force -freeze sim:/stck_if/trig_wr 1 0 

force -freeze sim:/stck_if/rst 0 0 
run 

force -freeze sim:/stck_if/bus_a 16'h0100 0 
force -freeze sim:/stck_if/bus_di 16'h1111 0 
run 
run 


force -freeze sim:/stck_if/bus_a 16'h0102 0 
run 
run 

force -freeze sim:/stck_if/bus_a 16'h0104 0 
run 
run 

force -freeze sim:/stck_if/bus_a 16'h0106 0 
run 
run 

force -freeze sim:/stck_if/bus_a 16'h0108 0 
run 
run 

etc. 

Obwohl der Code ohne einen Fehler zu geben, während der Simulation ModelSim die folgenden Fehler gibt:

  • Kann wegen eines schwerwiegenden Fehlers nicht fortgesetzt werden. HDL Aufrufsequenz: bei C Gestoppt: /Modeltech_pe_edu_10.4a/examples/stack.vhd 53 ForLoop Schleife

Von dem, was ich verstehe, ist das Problem bei der Verwendung von „For-Schleife“ und von dem, was ich davon ausgehen, es muss sein, dass VHDL den folgenden Ausdruck nicht übersetzen kann:

kin_2((8*(N-int_add)-1) downto 8*(N-int_add)) <= bus_di; 

in eine tatsächliche Schaltung.

Bin ich richtig mit meiner Hypothese? Irgendwelche Ideen, wie man dieses Problem löst, oder irgendwelche Vorschläge, wo ich schauen/lesen sollte, um meine Antworten zu finden, wäre wirklich hilfreich!

+0

Beachten Sie, dass der Bereich "n-1 downto n" ein Nullbereich ist: Er wird als Teilbereich innerhalb eines Vektors verwendet und beschreibt einen Vektor ohne Elemente. Aber das ist kein fataler Fehler. Irgendwelche Nachrichten über die Breite stimmen nicht darin überein? –

+0

@BrianDrummond Sie hatten Recht mit dem Bereich! Ich habe wieder am Anfang der Fehlermeldungen überprüft und der erste Fehler, der auftaucht (in blauer Farbe ?!) sagt: ** Fatal: (vsim-3420) Array-Längen stimmen nicht überein. Links ist 0 (127 bis 128 (Null-Array)). Richtig ist 16 (15 abwärts zu 0). ** Ich reparierte es, indem ich ein "+2" am zweiten "int_add" hinzufüge. Jetzt ist der Befehl der folgende: ** kin_2 ((8 * (N-int_add) -1) bis 8 * (N- (int_add + 2))) <= bus_di; ** Ich muss wirklich müde gewesen sein. Jetzt funktioniert der Code wie ein Zauber. Irgendwelche Optimierungen oder Ratschläge wären willkommen! Vielen Dank! –

Antwort

0

Die folgende Version sollte funktionell zu Ihrer, kürzer, und - meiner bescheidenen Meinung nach - einfacher zu lesen sein. Ich weiß jedoch nicht, wie das Syntheseergebnis aussehen wird. Ich finde es schwierig, sich vorzustellen, welche der abgeleiteten Primitive in Einzelprozessbeschreibungen mit Variablen sein werden.

architecture stck_if_arch of stck_if is 
    signal kin_2: std_logic_vector (8*N-1 downto 0); 
    signal din_2: std_logic_vector (8*N-1 downto 0); 
    signal encdec_2: std_logic; 
    signal trig_wr: std_logic; 
begin 
    proc1: process(clk,rst) 
    variable high: unsigned(9 downto 0); 
    variable bid: integer range 0 to N-1; 
    variable left, right: integer range 0 to 8*N-1; 
    begin 
    if rst='1' then 
     encdec_2<='0'; 
     kin_2<=(others =>'0'); 
     din_2<=(others =>'0'); 
    elsif (clk'event and clk='1') then 
     if (trig_wr = '1') then 

     high := unsigned(bus_a(15 downto 6)); 
     bid := to_integer(unsigned(bus_a(5 downto 1))); 
     left := 16*(8-bid)-1; 
     right := 16*(7-bid); 

     if bus_a="0000000000001100" then 
      encdec_2 <= bus_di(0); 
     elsif bus_a(0)='0' then 
      if high=4 then 
      kin_2(left downto right) <= bus_di; 
      elsif high=5 then 
      din_2(left downto right) <= bus_di; 
      end if; 
     end if; 

     end if; 
    end if; 
    end process; 

kin <= kin_2; 
din <= din_2; 

end stck_if_arch; 
0

hatte ich die gleiche Idee U.Martinez-Corral mit ein bisschen einem Twist hatte:

architecture foo of stck_if is 
    type N_array is array (0 to K - 1) of std_logic_vector(N - 1 downto 0); 
    signal kin_2: N_array; 
    signal din_2: N_array; 
    signal encdec_2: std_logic; 
    signal trig_wr: std_logic := '1'; -- ; -- FOR TESTING without FORCE 
begin 

proc1: 
    process(clk,rst) 
     variable high: unsigned(9 downto 0); 
     variable Kidx: integer range 0 to K-1; 
    begin 
     if rst = '1' then 
      encdec_2 <= '0'; 
      kin_2 <= (others => (others => '0')); 
      din_2 <= (others => (others => '0')); 
     elsif rising_edge(clk) then 
      if trig_wr = '1' then 
       high := unsigned(bus_a (15 downto 6)); 
       Kidx := to_integer(unsigned(bus_a(3 downto 1))); 
       if bus_a = "0000000000001100" then 
        encdec_2 <= bus_di(0); 
       elsif bus_a(0) = '0' then 
        if high = 4 then 
         kin_2(kidx) <= bus_di; 
        elsif high = 5 then 
         din_2(kidx) <= bus_di; 
        end if; 
       end if; 
      end if; 
     end if; 
    end process; 

UNION: 
    if K = 8 generate 
     kin <= kin_2(0) & kin_2(1) & kin_2(2) & kin_2(3) & 
       kin_2(4) & kin_2(5) & kin_2(6) & kin_2(7); 
     din <= din_2(0) & din_2(1) & din_2(2) & din_2(3) & 
       din_2(4) & din_2(5) & din_2(6) & din_2(7); 
    end generate; -- GENERATE statement for every usable K value 

end architecture foo; 

Dies wäre eine für jeden nützlichen Wert von K-Anweisung erzeugen erfordern aufgrund des Fehlens von Gewerkschaften in VHDL.Es ist der hässliche Teil davon.

Ansonsten besteht die Idee darin, keine Bit- (Elementindex-) Bereiche zu verwenden.

Und ein Prüfstand für diejenigen von uns, die nicht Modelsim Lizenzinhaber/Benutzer sind:

library ieee; 
use ieee.std_logic_1164.all; 

entity stck_if_tb is 
end entity; 

architecture foo of stck_if_tb is 
    constant K:  integer := 8; 
    constant N:  integer := 16; 
    signal clk:  std_logic := '0'; 
    signal rst:  std_logic; 

    signal bus_a: std_logic_vector (15 downto 0); 
    signal bus_di: std_logic_vector (15 downto 0); 

    signal kin:  std_logic_vector (8 * N - 1 downto 0); 
    signal din:  std_logic_vector (8 * N - 1 downto 0); 
begin 
DUT: 
    entity work.stck_if 
     generic map (
      N => N, 
      K => K 
     ) 
     port map (
      clk => clk, 
      rst => rst, 
      bus_a => bus_a, 
      bus_di => bus_di, 
      kin => kin, 
      din => din 
     ); 
CLOCK: 
    process 
    begin 
     wait for 10 ns; 
     clk <= not clk; 
     if now > 240 ns then 
      wait; 
     end if; 
    end process; 
STIMULI: 
    process 
    begin 
     wait for 20 ns; 
     rst <= '1'; 
     wait for 20 ns; 
     rst <= '0'; 
     bus_a <= x"0100"; 
     bus_di <= x"1111"; 
     wait for 20 ns; 
     wait for 20 ns; 
     bus_a <= x"0102"; 
     wait for 20 ns; 
     wait for 20 ns; 
     bus_a <= x"0104"; 
     wait for 20 ns; 
     wait for 20 ns; 
     bus_a <= x"0106"; 
     wait for 20 ns; 
     wait for 20 ns; 
     bus_a <= x"0108"; 
     wait for 20 ns; 
     wait for 20 ns; 
     wait; 
    end process; 
end architecture; 

Und das gibt:

stck_if_tb_foo.png

Beachten Sie, dass ich das addierte trig_wr Standardwert, wenn sie nicht mit einer Kraft.

Nachtrag

U. Martinez-Corral kommentiert, was zeigt, wieder wir tun Index Arithmetik im Allgemeinen schlecht sind, während die Verwendung eines darauf hindeutet Erklärung für generieren. (IEEE Std 1076-2008, 11,8 Generieren Anweisungen)

Dies zeigt, das Verfahren mit den Schleifengrenzen korrigiert, um den Kommentar gesetzt Case-Anweisung in der ursprünglichen Frage entsprechen:

UNION: 
    for x in K - 1 downto 0 generate 
     kin(N * (x + 1) - 1 downto N * x) <= kin_2(K - 1 - x); 
     din(N * (x + 1) - 1 downto N * x) <= din_2(K - 1 - x); 
    end generate; 

Es erzeugt die gleiche Wellenform mit der Prüfstand.

+0

Ich denke, dass Sie ein for-generate als die 'Union' verwenden könnten, die Sie erwähnen:' UNION: für x in K downto 0 erzeugt kin (N * (x + 1) -1 abwärts N * x) <= kin_2 (x); din (N * (x + 1) -1 abwärts N * x) <= din_2 (x); Ende erzeugen; '. –

+1

Die Idee war Slice-Arithmetik zu vermeiden, aber eine generate-Anweisung mit einem for-Schema wäre Elaboration Zeit Berechnung und scheint bis auf ein kleines Problem zu funktionieren K downto 0 ist 9 Scheiben Din und Kin (K - 1 downto 0?), Es ist auch falsch endian (siehe den kommentierten Fall im Original des OP, sollte <= kin_2 (K - 1 - x) sein? Ein kurzer Check zeigt, dass das funktioniert). (Wir sind im Allgemeinen schwach, diese Art von Abstraktion anzuwenden, vielleicht brauchen wir ein Konstrukt auf der rechten Seite, um Mengenlösungen zu verkürzen und zu verallgemeinern.) – user1155120