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


von Neuling (Gast)


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:
1
constant tabelle: z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE);  
2
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:
1
constant tabelle: z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE,BOOT,BMODE,MMODE);  
2
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

von Klaus Falser (Gast)


Lesenswert?

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

von Neuling (Gast)


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.

1
   when idle    => WE <= '0';
2
                      CS <= '0';
3
                      RD <= '0';
4
                      ADDR <="ZZZZ";
5
                      HDATA <= "ZZZZZZZZZZZZZZZZ";
6
                      start <= '0';
7
                      rstn_cnt <= '1';
8
                      next_state <= s1;
9
                      
10
      when s1   => if( h = 8 ) then
11
                       WE <= '0';
12
                       CS <= '0';
13
                       RD <= '0';
14
                       ADDR <="ZZZZ";
15
                       HDATA <= "ZZZZZZZZZZZZZZZZ";
16
                       start <= '0';
17
                       rstn_cnt <= '0';
18
                       next_state <= idle;
19
                  else
20
                       WE <= '1';
21
                       CS <= '1';
22
                       RD <= '1';
23
                       ADDR <= Tabelle(conv_integer(h));
24
                       HDATA <= Werte(conv_integer(h));
25
                       start <= '1';
26
                       next_state <= s2;
27
                       ENDE <= x"0000";
28
                   end if;      
29
      when s2      =>  WE <= '0';
30
                       CS <= '0';
31
                       RD <= '0';
32
                       ADDR <="ZZZZ";
33
                       HDATA <= "ZZZZZZZZZZZZZZZZ";
34
                       start <= '0';
35
                       rstn_cnt <= '0';
36
                       next_state <= s1;

von Mark (Gast)


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!

von Neuling (Gast)


Lesenswert?

Also die Array`s sind wie folgt deklariert
1
type z_array is array (0 to 7) of std_logic_vector (3 downto 0);
2
  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.
1
Addr_cnt: process(clk,start,rstn_cnt)
2
variable i: std_logic_vector (3 downto 0):="0000";-- 0 to 5 :=0;
3
4
  begin
5
  if (rstn_cnt = '1') then
6
    i := "0000";
7
    
8
  elsif rising_edge(clk) then
9
    if start = '1'  then
10
       i := i+1; 
11
    end if;
12
  end if;
13
    
14
  h <= i;
15
  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:
1
constant tabelle  :  z_array := (PLL_HI,PLL_LO,BOOT,BMODE,MMODE,x"0",x"1",x"2");
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.
1
use IEEE.std_logic_unsigned.all;
Daher wundere ich mich das am Ende -8 ausgegeben wird, kann das der 
Fehler sein?

von Ralf (Gast)


Lesenswert?

Hallo Neuling,

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

Gruß

Ralf

von Neuling (Gast)


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.

von Ralf (Gast)


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
1
use IEEE.std_logic_unsigned.all;

einzubinden.

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

Vielleicht kannst du ja mal den ganzen Sourccode zeigen.


Gruß

Ralf

von Mark (Gast)


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!

von Neuling (Gast)


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:
1
when idle    => WE <= '0';
2
                  CS <= '0';
3
                  RD <= '0';
4
                  ADDR <="ZZZZ";
5
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
6
                  start <= '0';
7
                  zaehl <= '0';
8
                  rstn_cnt <= '1';
9
                  next_state <= s1;
10
                  ENDE <= x"0000";
11
      when s1      =>  if( addr_index = 2 ) then    
12
                    WE <= '0';
13
                    CS <= '0';
14
                    RD <= '0';
15
                    ADDR <="ZZZZ";
16
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
17
                    start <= '0';
18
                    zaehl <= '0';
19
                    rstn_cnt <= '0';
20
                    ENDE <= x"0000";
21
                    next_state <= s_wait;
22
                  else
23
                    WE <= '1';
24
                    CS <= '1';
25
                    RD <= '1';
26
                    ADDR <= Tabelle(conv_integer(addr_index));
27
                    HDATA <= Werte(conv_integer(addr_index));
28
                    start <= '1';
29
                    zaehl <= '0';
30
                    rstn_cnt <= '0';
31
                    next_state <= s2;
32
                    ENDE <= x"0000";
33
                    
34
                  end if;      
35
      when s2      =>  WE <= '0';
36
                  CS <= '0';
37
                  RD <= '0';
38
                  ADDR <="ZZZZ";
39
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
40
                  start <= '0';
41
                  zaehl <= '0';
42
                  rstn_cnt <= '0';
43
                  next_state <= s1;
44
                  ENDE <= x"0000";                
45
46
        when s_wait  => CS <= '0'; 
47
                  WE <= '0';
48
                  RD <= '0';
49
                  ADDR <="ZZZZ";
50
                  HDATA <= "ZZZZZZZZZZZZZZZZ";    
51
                  start <= '0';
52
                  rstn_cnt <= '0';
53
                  if counter = '1' then    -- Wait loop to PLL lock
54
                    next_state    <= s3;
55
                    zaehl <= '0';
56
                        
57
                  else  
58
                    next_state    <= s_wait;
59
                    zaehl <= '1';
60
                    
61
                  end if;  
62
                  ENDE <= x"0005";
63
        when s3      =>  if( addr_index = 5 ) then
64
                      WE <= '0';
65
                      CS <= '0';
66
                      RD <= '0';
67
                      ADDR <="ZZZZ";
68
                      HDATA <= "ZZZZZZZZZZZZZZZZ";
69
                      start <= '0';
70
                      zaehl <= '0';
71
                      rstn_cnt <= '0';
72
                      ENDE <= x"0000";
73
                      next_state <= idle;
74
                    else
75
                      WE <= '1';
76
                      CS <= '1';
77
                      RD <= '1';
78
                      ADDR <= Tabelle(conv_integer(addr_index));
79
                      HDATA <= Werte(conv_integer(addr_index));
80
                      start <= '1';
81
                      zaehl <= '0';
82
                      rstn_cnt <= '0';
83
                      next_state <= s4;
84
                      ENDE <= x"0000";
85
                    end if;      
86
        when s4      =>  WE <= '0';
87
                    CS <= '0';
88
                    RD <= '0';
89
                    ADDR <="ZZZZ";
90
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
91
                    start <= '0';
92
                    zaehl <= '0';
93
                    rstn_cnt <= '0';
94
                    next_state <= s3;
95
                    ENDE <= x"0000";

Der dazugehörige "Warteprozess" sieht so aus.

1
zaehler: process(clk,zaehl)
2
variable j: std_logic_vector (15 downto 0):="0000000000000000";-- 0 to 5 :=0;
3
4
  begin
5
  if rising_edge(clk) then
6
    if zaehl = '1'  then
7
      if j < ENDE then 
8
        j := j+1; counter <= '0';
9
      else 
10
        j := "0000000000000000";
11
        counter <= '1';
12
      end if;
13
    else
14
        counter <= '0';
15
      
16
    
17
    end if;
18
  end if;
19
    
20
  k <= j;
21
  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

von Nobody (Gast)


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.

von Neuling (Gast)


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:
1
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);
2
  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");
3
  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);
4
  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.
1
when param_1  =>  if( addr_index2 = 31 ) then    
2
                    WE <= '0';
3
                    CS <= '0';
4
                    RD <= '0';
5
                    ADDR <="ZZZZ";
6
                    HDATA <= "ZZZZZZZZZZZZZZZZ";
7
                    start <= '0';
8
                    param_start <= '0';
9
                    zaehl <= '0';
10
                    rstn_cnt <= '0';
11
                    rom_addr <= "0000000000000000";
12
                    rom_read <= '0';
13
                    ENDE <= x"0000";
14
                    next_state <= idle;
15
                  else
16
                    param_start <= '1';
17
                    WE <= '1';
18
                    CS <= '1';
19
                    RD <= '0';
20
                    ADDR <= param(addr_index2);
21
                    HDATA <= Werte1(addr_index2);
22
                    start <= '0';
23
                    
24
                    zaehl <= '0';
25
                    rstn_cnt <= '0';
26
                    rom_addr <= "0000000000000000";
27
                    rom_read <= '0';
28
                    next_state <= param_2;
29
                    ENDE <= x"0000";
30
                    
31
                  end if;      
32
      when param_2  =>  WE <= '0';
33
                  CS <= '0';
34
                  RD <= '0';
35
                  ADDR <="ZZZZ";
36
                  HDATA <= "ZZZZZZZZZZZZZZZZ";
37
                  start <= '0';
38
                  param_start <= '0';
39
                  zaehl <= '0';
40
                  rstn_cnt <= '0';
41
                  rom_addr <= "0000000000000000";
42
                  rom_read <= '0';
43
                  next_state <= param_1;
44
                  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.
1
constant param      :  z1_array := (STAGE  ,IADDR  ,STAGE  ,IADDR  ,IDATA  ,IADDR,IDATA ,IADDR   ,IDATA  ,IADDR,IDATA,IADDR ,IDATA  ,IADDR  ,IDATA  ,IADDR   ,IDATA);  
2
  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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.