www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Array mit verschiedenen Adressen bestücken


Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte über 2 Array`s eine Adresse auswählen und beschreiben.

Das ganze klappt auch, solange ich jede Adresse nur 1mal in den Array 
belege.

Bsp:
constant tabelle: z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE);  
constant Werte:  w_array := (x"0008",x"0004",x"008A",x"0005",x"0005");

Wenn ich allerdings auf 1 Adresse nacheinander 2 Werte schreiben möchte, 
wird in der "Post-Rout" simulation das ganze mit "X" dargestellt.

Bsp:
constant tabelle: z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE,BOOT,BMODE,MMODE);  
constant Werte:  w_array := (x"0008",x"0004",x"008A",x"0005",x"0005",x"008D",x"0015",x"0005");

Gibt es eine andere Möglichkeit, das gabnze über Array`s zu bewältigen?

Danke

Neuling

Autor: Klaus Falser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem ist nicht das array, sondern die Art wie Du die Adresse 
beschreibst.
Zeige mal diesen Code.

Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ganze passiert über eine Statemaschine. Die StateMaschin selber ist 
unabhängig vom Takt, allerdings der Zustandswechsel ist Taktabhängig(da 
das aber nicht das Problem ist, hab ich es hier weggelassen).

Es gibt eine Variable h die hochgezählt wird um die einzelnen 
Zuweisungen deer Array`s abzuarbeiten. Dies wird in einen externen 
Process gemacht und mit "start" angestossen.
Wenn das Ende der Array`s erreicht ist, soll das ganze wieder in den 
Zustand "idle" zurückgesetzt werden.

Der entsprechende Codeteil, sieht wie folgt aus.

   when idle    => WE <= '0';
                      CS <= '0';
                      RD <= '0';
                      ADDR <="ZZZZ";
                      HDATA <= "ZZZZZZZZZZZZZZZZ";
                      start <= '0';
                      rstn_cnt <= '1';
                      next_state <= s1;
                      
      when s1   => if( h = 8 ) then
                       WE <= '0';
                       CS <= '0';
                       RD <= '0';
                       ADDR <="ZZZZ";
                       HDATA <= "ZZZZZZZZZZZZZZZZ";
                       start <= '0';
                       rstn_cnt <= '0';
                       next_state <= idle;
                  else
                       WE <= '1';
                       CS <= '1';
                       RD <= '1';
                       ADDR <= Tabelle(conv_integer(h));
                       HDATA <= Werte(conv_integer(h));
                       start <= '1';
                       next_state <= s2;
                       ENDE <= x"0000";
                   end if;      
      when s2      =>  WE <= '0';
                       CS <= '0';
                       RD <= '0';
                       ADDR <="ZZZZ";
                       HDATA <= "ZZZZZZZZZZZZZZZZ";
                       start <= '0';
                       rstn_cnt <= '0';
                       next_state <= s1;
                  

Autor: Mark (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

gib mal die Typdeklaration von den Arrays an.
Kann es sein dass der Wert von h undefinierte oder falsche Werte
annimmt? Mach mal ein Assert auf h!

Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also die Array`s sind wie folgt deklariert
type z_array is array (0 to 7) of std_logic_vector (3 downto 0);
  type w_array is array (0 to 7) of std_logic_vector (15 downto 0);

Das h ist ein Signal, welches nicht direkt hochgezählt wird. Es wir 
vielmehr eine variable i in einen anderen Prozess hochgezählt und 
dauerhaft auf h übergeben.
Addr_cnt: process(clk,start,rstn_cnt)
variable i: std_logic_vector (3 downto 0):="0000";-- 0 to 5 :=0;

  begin
  if (rstn_cnt = '1') then
    i := "0000";
    
  elsif rising_edge(clk) then
    if start = '1'  then
       i := i+1; 
    end if;
  end if;
    
  h <= i;
  end process; 

Ich hab das gaanze jetzt mal mit der Variante getestet, dass sich die 
Adresse nicht wiederholt.

Die Array`s sehen dann wie folgt aus:
constant tabelle  :  z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE,x"0",x"1",x"2");
  constant Werte    :  w_array := (x"0008",x"0004",x"008A",x"0005",x"0005",x"FFFF",x"FFFF",x"FFFF");

Dann funktioniert das ganze,jede Adresse liegt an und wird entsprechend 
beschrieben.
Was mich allerdings wundert, das hochgezählte h bzw. i gibt als letzte 
Zahl nicht 8 sondern -8 aus.

Ich hab dann geschaut und ich binde diese Bibliothek ein.
use IEEE.std_logic_unsigned.all;
Daher wundere ich mich das am Ende -8 ausgegeben wird, kann das der 
Fehler sein?

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Neuling,

wo wird denn -8 ausgegeben?
In Modelsim? Dort kannst du
ja die Zahlendarstellung selbst wählen.

Gruß

Ralf

Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja unter ModelSim....wenn ich die Darstellung auf dezimal stelle wird 
wie folgt gezählt: 0->1->2->3->4->5->6->7->-8

Das könnte der Grund meines Problemes sein, weiss aber nicht warum der 
Fehler auftritt bzw. wie ich ihn beheben kann.

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich nehme mal an das h als std_logic_vector
definiert ist. Schau doch mal nur die
einzelnen bits an und nicht den Wert selbst.
Zudem ist es schlecht
use IEEE.std_logic_unsigned.all;

einzubinden.

Ich nehme fast immer nur die Bibliotheken
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

Vielleicht kannst du ja mal den ganzen Sourccode zeigen.


Gruß

Ralf

Autor: Mark (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Neuling,

mach mal folgendes:
1) deklariere eine Konstante ARRAY_LENGTH vom Typ integer und setze sie
auf z.B. 8
2) deklariere die Arrays abh. von dieser Konstanten,also z.B. so:
type z_array is array (0 to ARRAY_LENGTH-1) of std_logic_vector (3 
downto 0);

damit sind beide Arrays immer gleich lang und wenn Du die Länge ändern 
willst musst Du nur ARRAY_LENGTH anpassen und die Konstenten hinzufügen.

3)in dem Prozess wo Du mit der Variablen i arbeitest:
ersetze i durch ein SIGNAL mit einem sinnvollen Namen, mach die 
Deklaration wieder von ARRAY_LENGTH abhängig, also zb.
signal addr_index : integer range 0 to ARRAY_LENGTH-1;

Damit es keinen Überlauf gibt, schreibst Du die Sache so:
if addr_index = ARRAY_LENGTH-1 then
   addr_index <= 0;
else
   addr_index <= addr_index +1;
end if;

Mit diesem Signal addr_index gehst Du jetzt direkt in die Statemachine 
rein.
Du hast einen Integer, also kannst Du dieses Signal direkt zur 
Indizierung des Arrays verwenden. Schreib mir mal, ob sich jetzt was 
verbessert hat.

NOCHWAS:
die -8 kommt sicher von Deiner Integer-Konvertierung.
Du musst schreiben :
conv_integer(unsigned(h));
sonst wird das MSB von h als Vorzeichen interpretiert und Du bekommst 
zwangsläufig die -8!

Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Mark,

besten Dank dein Vorschlag hat das Problem eigentlich gelöst. Ich kann 
jetzt ohne weiteres die Adressen am Stück , bis adress_index = 8, 
beschreiben, auch wenn eine Adresse doppelt vorkommt.

Nun wollte ich, einen Wartezustand einfügen und das Problem tritt wieder 
auf.

Es soll wie folgt laufen.

Zunächst werden die ertsten 2 Adressen beschrieben, danach wird in den 
Zustand "s_wait" gegangen und bis zum Wert ENDE in einen anderen Process 
gezählt,um danach weitere Adressen zu beschreiben.

Das ganze würde so aussehen:
when idle    => WE <= '0';
                  CS <= '0';
                  RD <= '0';
                  ADDR <="ZZZZ";
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
                  start <= '0';
                  zaehl <= '0';
                  rstn_cnt <= '1';
                  next_state <= s1;
                  ENDE <= x"0000";
      when s1      =>  if( addr_index = 2 ) then    
                    WE <= '0';
                    CS <= '0';
                    RD <= '0';
                    ADDR <="ZZZZ";
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
                    start <= '0';
                    zaehl <= '0';
                    rstn_cnt <= '0';
                    ENDE <= x"0000";
                    next_state <= s_wait;
                  else
                    WE <= '1';
                    CS <= '1';
                    RD <= '1';
                    ADDR <= Tabelle(conv_integer(addr_index));
                    HDATA <= Werte(conv_integer(addr_index));
                    start <= '1';
                    zaehl <= '0';
                    rstn_cnt <= '0';
                    next_state <= s2;
                    ENDE <= x"0000";
                    
                  end if;      
      when s2      =>  WE <= '0';
                  CS <= '0';
                  RD <= '0';
                  ADDR <="ZZZZ";
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
                  start <= '0';
                  zaehl <= '0';
                  rstn_cnt <= '0';
                  next_state <= s1;
                  ENDE <= x"0000";                

        when s_wait  => CS <= '0'; 
                  WE <= '0';
                  RD <= '0';
                  ADDR <="ZZZZ";
                  HDATA <= "ZZZZZZZZZZZZZZZZ";    
                  start <= '0';
                  rstn_cnt <= '0';
                  if counter = '1' then    -- Wait loop to PLL lock
                    next_state    <= s3;
                    zaehl <= '0';
                        
                  else  
                    next_state    <= s_wait;
                    zaehl <= '1';
                    
                  end if;  
                  ENDE <= x"0005";
        when s3      =>  if( addr_index = 5 ) then
                      WE <= '0';
                      CS <= '0';
                      RD <= '0';
                      ADDR <="ZZZZ";
                      HDATA <= "ZZZZZZZZZZZZZZZZ";
                      start <= '0';
                      zaehl <= '0';
                      rstn_cnt <= '0';
                      ENDE <= x"0000";
                      next_state <= idle;
                    else
                      WE <= '1';
                      CS <= '1';
                      RD <= '1';
                      ADDR <= Tabelle(conv_integer(addr_index));
                      HDATA <= Werte(conv_integer(addr_index));
                      start <= '1';
                      zaehl <= '0';
                      rstn_cnt <= '0';
                      next_state <= s4;
                      ENDE <= x"0000";
                    end if;      
        when s4      =>  WE <= '0';
                    CS <= '0';
                    RD <= '0';
                    ADDR <="ZZZZ";
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
                    start <= '0';
                    zaehl <= '0';
                    rstn_cnt <= '0';
                    next_state <= s3;
                    ENDE <= x"0000";  

Der dazugehörige "Warteprozess" sieht so aus.

zaehler: process(clk,zaehl)
variable j: std_logic_vector (15 downto 0):="0000000000000000";-- 0 to 5 :=0;

  begin
  if rising_edge(clk) then
    if zaehl = '1'  then
      if j < ENDE then 
        j := j+1; counter <= '0';
      else 
        j := "0000000000000000";
        counter <= '1';
      end if;
    else
        counter <= '0';
      
    
    end if;
  end if;
    
  k <= j;
  end process;  

Wenn ich die "Post-Route" Simulation ablaufen lasse, werden die ersten 2 
Adressen beschrieben und der Wartezyklus wird auch abgearbeiten. Wenn es 
dann aber vom Zustand "s-wait" zu Zustand "s3" übergeht, werden wieder 
nur X Werte angezeigt.

Gibt es da eine Möglichkeit dies anderst zu realisieren?

Danke

Neuling

Autor: Nobody (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Neuling,

das sieht alles etwas chaotisch aus, ich verstehe aber was Du erreichen 
willst. Erstmal: wenn Du addr_index als integer deklariert hast, kannst 
Du
die Konvertierung conv_integer im s3 weglassen. Und nimm mal 'zaehl' aus 
der Sensitivity-Liste vom process raus, das gehört da nicht hin.

Dass Du die Warteschleife auslagern musst ist eine Folge der Aufteilung
der FSM in Kombinatorik und State-Wechsel, klar. Dadurch wird es aber
auch etwas unübersichtlich. Du nimmst wieder eine Variable, die Du am
Ende einem Signal zuweist. Als Anfänger sollte man Variablen meiden, 
glaub
mir. Nimm bitte ein Signal für den Wartezähler, auch wenn das vermutlich
nichts mit dem Problem zu tun hat.
Die Warteschleife würde ich vereinfachen:

process(clk)
begin
   if rising_edge(clk) then
      if start_wait then -- start-signal aus der FSM = TRUE?
         cnt_q <= ENDE; -- Zähler mit Delay laden
         waiting_q <= true; -- Flag für die FSM 'warten'
      elsif cnt_q > 0 then
         cnt_q <= cnt_q -1; -- runterzählen bis 0
      else
         waiting_q <= false; -- fertig
      end if;
end process;

start_wait ist als signal vom Typ boolean zu deklarieren, ebenso 
waiting_q.
Vor der statemachine setzt Du start_wait generell auf false und nur im 
state s1 bei entspr. Bedingung wird start_wait auf true gesetzt.
Im s_wait fragst Du dann waiting_q ab, wenn es false wird geht es zum 
nächsten State.
Ich vermute aber, dass das Problem immer noch mit dem Array-Index zu tun
hat, irgendwie kommen da falsche Werte rein.
Du kannst im VHDL-Code ein assert für die Simulation einbauen, z.B. so:
assert addr_idx >= 0 and addr_idx < ARRAY_LENGTH report '....' severity 
error;
Wenn der addr_idx einen unzulässigen Wert annimmt bekommst Du dann 
sofort
eine Meldung in der Simulation.

Autor: Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hab meine StateMaschine jetzt erweitert und bin auf ein Problem 
gestossen, welches ich nicht verstehe.

Kurz zur Erklärung:

Habe ein 2tes paar Array`s erstellt und dem ersten entsprechend 
deklariert.

Die Array`s sehen dann wie folgt aus:
constant tabelle: z_array :=(PLL_HI,PLL_LO,BOOT,BMODE,MMODE,BOOT,BMODE,MMODE,IADDR,IDATA,IADDR,IDATA,EIRQIE,IADDR,IDATA,IADDR,IDATA,EIRQIE,EIRQFLG,BMODE,MMODE);
  constant Werte:  w_array :=(x"0008",x"0004",x"008A",x"0005",x"0005",x"008D",x"0015",x"0005",EDMOD0(15downto 0),x"061A",EDMOD1(15downto 0),x"061A",PMODE1(15downto 0),EDMOD0(15downto 0),x"061B",EDMOD1(15downto 0),x"061B",PMODE1(15downto 0),x"FFFF",x"0015",x"0005");
  constant param      :  z1_array := (STAGE,IADDR,STAGE,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA,IADDR,IDATA);
  constant Werte1    :  w1_array := (x"0005",x"0005",x"0005",VFORMAT,x"0001",PREC,x"0001",XFORMLEV,x"0005",UNI,x"0003",CBSIZE,x"0003",WKERNEL,x"0001",STALLPAR,x"0000",ATTRTYPE,x"0001",RCTYPE,x"0001",RCVAL,x"09C4",J2KPROG,x"0000",PICFG,x"0000",QFACT,x"0000",COD_STYLE,x"0001"); 

Dann wird vom Zustand s3 nicht mehr in idle, sondern in den Zustand 
"param_1" von dem es dann in "param_2" geht. Zwischen diesen beiden 
Zuständen wechselt es solange hin und her bis alle Parameter 
beschrioeben werden.
when param_1  =>  if( addr_index2 = 31 ) then    
                    WE <= '0';
                    CS <= '0';
                    RD <= '0';
                    ADDR <="ZZZZ";
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
                    start <= '0';
                    param_start <= '0';
                    zaehl <= '0';
                    rstn_cnt <= '0';
                    rom_addr <= "0000000000000000";
                    rom_read <= '0';
                    ENDE <= x"0000";
                    next_state <= idle;
                  else
                    param_start <= '1';
                    WE <= '1';
                    CS <= '1';
                    RD <= '0';
                    ADDR <= param(addr_index2);
                    HDATA <= Werte1(addr_index2);
                    start <= '0';
                    
                    zaehl <= '0';
                    rstn_cnt <= '0';
                    rom_addr <= "0000000000000000";
                    rom_read <= '0';
                    next_state <= param_2;
                    ENDE <= x"0000";
                    
                  end if;      
      when param_2  =>  WE <= '0';
                  CS <= '0';
                  RD <= '0';
                  ADDR <="ZZZZ";
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
                  start <= '0';
                  param_start <= '0';
                  zaehl <= '0';
                  rstn_cnt <= '0';
                  rom_addr <= "0000000000000000";
                  rom_read <= '0';
                  next_state <= param_1;
                  ENDE <= x"0000";  

Das Problem entsteht bei den param und dem dazugehörigen Wert an der 
Stelle 18. (param= IADDR & Wert1=ATTRTYPE)

Bei der "Post-Route"-Simulation, entstehen an dieser Stelle X.

Wenn ich das ganze nur bis Wert 17 Abfrage funktioniert es Einwandfrei.

Daher hatte ich zu Testzwecken, das Array "param" bzw. "Werte1" auf 17 
Stellen begrenzt.
constant param      :  z1_array := (STAGE  ,IADDR  ,STAGE  ,IADDR  ,IDATA  ,IADDR,IDATA ,IADDR   ,IDATA  ,IADDR,IDATA,IADDR ,IDATA  ,IADDR  ,IDATA  ,IADDR   ,IDATA);  
  constant Werte1    :  w1_array := (x"0005",x"0005",x"0005",VFORMAT,x"0001",PREC,x"0001",XFORMLEV,x"0005",UNI,x"0003",CBSIZE,x"0003",WKERNEL,x"0001",STALLPAR,x"0000");

Zu meiner grossen Verwunderung, kam dann an der Stelle 17 ebenfalls 
X,obwohl es vorher funktionierte.

Stelle 17: Param = IDATA & Werte1 = x"0000"

Wenn ich allerdings einen anderen Wert als 0 drauf schreibe funktioniert 
es!

Hat jemand eine Idee woran es liegen kann, das es einmal funktioniert 
und dann nicht mehr?

Danke

Neuling

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.