Forum: FPGA, VHDL & Co. Outputsignal bleibt gleich


von Eren Y. (kaitou)


Lesenswert?

Hallo Leute

Sitze nun seit 3 Stunden am gleichen Code und schaffe es nicht, das 
ganze korrekt zum laufen zu bringen.
Es handelt sich um einen PRN Generator. Genauer gesagt, ein 
Schieberegister, der pseudozufällig '1' oder '0' rausspuckt. Der Code 
ist ziemlich selbsterklärend.

Simulation und alles funktioniert problemlos, jedoch kommt immer nur der 
gleiche Wert raus (lfsr_out = '0').

Code:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.std_logic_unsigned.all;
4
use ieee.numeric_std.all;
5
6
entity lfsr_counter is
7
  generic(
8
    WIDTH : integer := 10
9
  );
10
  port(
11
    clk      : in  std_logic;       --clock
12
    rst      : in  std_logic;       --positiv rst
13
    lfsr_out : out std_logic        --1 bit output of lfsr
14
  );
15
end lfsr_counter;
16
17
-------------------------------------------------------------------
18
19
architecture behavioral of lfsr_counter is
20
  type state_type is (state_rst, state_go); --rst: reset; go: lfsr shifts
21
22
  signal present_state : state_type;
23
  signal next_state    : state_type;
24
  signal lfsr          : std_logic_vector((WIDTH - 1) downto 0) := (others => '0');
25
  signal d0            : std_logic                              := '0'; --stores the current feedbackvalue
26
27
begin
28
29
  --sequencial logic:
30
  -------------------------------------------------------------------
31
  state_register : process(clk, rst)
32
  begin
33
    if (rst = '1') then
34
      present_state <= state_rst; --default state on reset.
35
    elsif (rising_edge(clk)) then
36
      present_state <= next_state; --state change
37
    end if;
38
  end process;
39
40
  --  combinatorial logic
41
  -------------------------------------------------------------------    
42
43
  comb_logic : process(present_state, rst)
44
  begin
45
    case present_state is
46
      when state_rst =>
47
        if (rst = '1') then
48
          next_state <= state_rst;
49
        else
50
          next_state <= state_go;
51
        end if;
52
      when state_go =>
53
        if (rst = '1') then
54
          next_state <= state_rst;
55
        else
56
          next_state <= state_go;
57
        end if;
58
    end case;
59
  end process;
60
61
  output_logic : process(present_state)
62
  begin
63
    if (present_state = state_go) then
64
      --assert ((WIDTH >= 3) and (WIDTH <= 10))
65
      --report "Error: the LFSR width must be between 3 and 10" severity failure;
66
      case WIDTH is               --definitions for the feedback
67
        when 3      => d0 <= lfsr(2) xnor lfsr(1);
68
        when 4      => d0 <= lfsr(3) xnor lfsr(2);
69
        when 5      => d0 <= lfsr(4) xnor lfsr(2);
70
        when 6      => d0 <= lfsr(5) xnor lfsr(4);
71
        when 7      => d0 <= lfsr(6) xnor lfsr(5);
72
        when 8      => d0 <= lfsr(7) xnor lfsr(5) xnor lfsr(4) xnor lfsr(3);
73
        when 9      => d0 <= lfsr(8) xnor lfsr(4);
74
        when 10     => d0 <= lfsr(9) xnor lfsr(6);
75
        when others => null;
76
      end case;
77
      lfsr     <= std_logic_vector(unsigned(lfsr) sll 1); --shifting all bits to left by 1
78
      lfsr_out <= lfsr(WIDTH - 1); --MSB to output
79
      lfsr     <= lfsr(WIDTH - 1 downto 1) & d0; --concatenate the feedback to the lfsr
80
    else
81
      lfsr     <= (others => '0'); --reset state -> lfsr contains only '0'
82
      lfsr_out <= '0';
83
    end if;
84
  end process;
85
end architecture;

Wenn ich in der output_logic den lfsr_out <= '1' setze, kommt bei der 
simulation immer 1 heraus. Die Testbench beginnt 1 clkzyklus lang mit 
reset, danach ist reset 0 für 1024 Taktzyklen... Seht jemand grad den 
Fehler?

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Eren Y. schrieb:
> Die Testbench beginnt 1 clkzyklus lang mit reset, danach ist reset 0 für
> 1024 Taktzyklen... Seht jemand grad den Fehler?
Wie wäre es, wenn du die paar VHDL Dateien hier einfach mal anhängst? 
Damit kann man sich leichter ein Projekt aufsetzen und ein Bild 
machen...

BTW: Wenn deine Simulation schon läuft, dann musst du nur überlegen, was 
du beim Schreiben der Zeilen gedacht hast, und kontrollieren ob genau 
das passiert.

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ein Wort zum Verhalten von Signalen in Prozessen (und zum eigentlichen 
Problem hier):
Eren Y. schrieb:
1
  lfsr     <= std_logic_vector(unsigned(lfsr) sll 1); --shifting all bits to left by 1
2
  lfsr_out <= lfsr(WIDTH - 1); --MSB to output
3
  lfsr     <= lfsr(WIDTH - 1 downto 1) & d0; --concatenate the feedback to the lfsr
lfsr behält seinen "alten" Wert während des gesamten Prozesses. Und am 
Ende des Prozesses "gewinnt" die letzte Zuweisung. Also ist die erste 
der obigen drei Zeilen wirkungslos, weil der in der ersten Zeile 
zugewiesene Wert in der dritten Zeile wieder überschreiben wird.

BTW: zum Formatieren von VHDL-Code bitte die [vhdl] Tags verwenden.

BTW2:
Hierzu ein Wort:
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
Damit hast du doppelte Typdefinitionen und irgendwann sicher seltsame 
Fehlermeldungen. Fazit: diese beiden niemals zusammen einbinden.
Siehe den Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"

: Bearbeitet durch Moderator
von Eren Y. (kaitou)


Lesenswert?

Hallo Lothar

> BTW: zum Formatieren von VHDL-Code bitte die vhdl Tags verwenden.

Vielen Dank für das Bearbeiten meines Beitrages.


Lothar M. schrieb:
> use ieee.std_logic_unsigned.all;
> use ieee.numeric_std.all;
> Damit hast du doppelte Typdefinitionen und irgendwann sicher seltsame
> Fehlermeldungen. Fazit: diese beiden niemals zusammen einbinden.

Ich hatte Probleme mit "sll" in Vivado. Dieses Pkg hatte ich noch 
eingefügt gehabt, da ich ungeduldig wurde. Aber war überflüssig ja, 
danke!

Lothar M. schrieb:
> Ein Wort zum Verhalten von Signalen in Prozessen (und zum eigentlichen
> Problem hier):
> lfsr behält seinen "alten" Wert während des gesamten Prozesses. Und am
> Ende des Prozesses "gewinnt" die letzte Zuweisung. Also ist die erste
> der obigen drei Zeilen wirkungslos, weil der in der ersten Zeile
> zugewiesene Wert in der dritten Zeile wieder überschreiben wird.

Ich nehme an, zwei Zuweisungen des gleichen Signals sind in einem 
Prozess also nicht zulässig, da man Hardware beschreibt und somit alles 
gleichzeitig abläuft? Ich habe jetzt versucht dies zu korrigieren indem 
ich die Shift-Left Anweisung und das Anhängen des Feedbacks in einem 
letzten Schritt durchführe:
1
      lfsr_out                 <= lfsr(WIDTH - 1); --MSB to output
2
      lfsr(WIDTH - 1 downto 0) <= lfsr(WIDTH - 2 downto 0) & d0;

Aber ich sehe keine Veränderung. Ich denke dass der Fehler irgendwo in 
der Outputlogic liegt. Was passiert da zuerst, was danach? Der Inhalt 
von lfsr bleibt doch nach dem process erhalten oder geht der wieder in 
den Default-Zustand?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Eren Y. schrieb:
> Ich denke dass der Fehler irgendwo in der Outputlogic liegt.
Wie kommst du darauf? Ändert sich der Wert des lfsr irgendwann? Nein? 
den Grund habe ich genannt: das Verhalten von Signalen in Prozessen...

> Ich nehme an, zwei Zuweisungen des gleichen Signals sind in einem
> Prozess also nicht zulässig, da man Hardware beschreibt und somit alles
> gleichzeitig abläuft?
Genau andersrum: du kannst zigtausemal irgendwas an ein Signal zuweisen. 
Das Signal ändert seinen Wert während des gesamten Prozesses nicht. Er 
am Schluss des Prozesses (oder beim nächsten wait) übernimmt das signal 
den zuletzt zugewiesenen Wert. Ein echt praktisches Verhalten, wenn 
man sich dran gewöhnt hat. Mal angenommen, hier komme ich mit a=2 in den 
Prozess:
1
signal a : integer;
2
signal b : integer;
3
4
process (clk) begin
5
  if rising_edge(clk) begin 
6
     a <= 5;      -- a wird am Ende des Prozesses 5, behält aber vorerst den Wert 2
7
     b <= a+1     -- b wird am Ende des Prozesses 3, behält aber vorerst den Wert
8
     a <= a+4;    -- a wird am Ende des Prozesses 5, a bleibt aber vorerst 2          
9
     a <= b+3;    -- a bleibt 2
10
     a <= a+1;    -- a bleibt 2          
11
  end if;
12
end process;    -- jetzt "bekommt" a den zuletzut zugewiesenen Wert 3
Des Witz daran ist, dass ich bis auf die letzte Zeile alle vorigen 
Zeilen ohne Funktionsänderung beliebig durcheinander mischen kann.

Und bei dir ist das die letzte Zuweisung:
lfsr <= lfsr(WIDTH - 1 downto 1) & d0;
Und nur die ist interessant. Also wird das lfsr laufend sich selber 
zugewisen. nur das unterste Bit könnte mal 1 oder auch 0 sein.

Das hier ist übrigens eine kombinatorische Schleife, die du aber wegen 
der unvollständigen Sensitivliste nicht bemerkst:
lfsr     <= std_logic_vector(unsigned(lfsr) sll 1);
Denn ein LFSR muss getaktet sein. Und ein Takt ist immer ein 
xxx_edge() oder ein 'event.
http://www.lothar-miller.de/s9y/archives/42-Kombinatorische-Schleifen.html

: Bearbeitet durch Moderator
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Für mich sieht es so aus, als würden Latche gebildet werden ...

Ich würde erstmal alles auf clk-getaktete Prozesse umbauen ...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Mampf F. schrieb:
> Für mich sieht es so aus, als würden Latche gebildet werden ...
Das ist das Problem der Zwei-Prozess-Schreibweise: der Takt wird dann 
von Anfängern nur für die FSM verwendet, Zähler (oder hier das LFSR) 
laufen ungetaktet als (versteckte) kombinatorische Schleife.
http://www.lothar-miller.de/s9y/archives/43-Ein-oder-Zwei-Prozess-Schreibweise-fuer-FSM.html

Der Synthesizer meldet solche gegateten kombinatorischen Schleifen dann 
gern als Latch.

Ich hol mal den Prozess mit der unvollständigen Sensitivliste extra raus 
und kürze ihn etwas ein:
1
  output_logic : process(present_state)
2
  begin
3
    if (present_state = state_go) then
4
      case WIDTH is               --definitions for the feedback
5
        when 3      => d0 <= lfsr(2) xnor lfsr(1); -- lfsr fehlt in der Sensitivliste, denn eine Änderung 
6
        when 4      => d0 <= lfsr(3) xnor lfsr(2); -- von lfsr müsste eine Neuberechnung des Prozesses anstoßen
7
        ...
8
        when others => null; 
9
      end case;
10
      lfsr     <= std_logic_vector(unsigned(lfsr) sll 1); -- wenn lfsr in der Sensitivliste steht, dann wird hier
11
                                                          -- bei jeder Änderung von lfsr ein neuer Wert für lfsr berechnet
12
                                                          -- und weil ein neuer Wert berechnet wird, ändert sich lfsr --> Endlosschleife
13
    else
14
      lfsr     <= (others => '0'); --reset state -> lfsr contains only '0'
15
      lfsr_out <= '0';
16
    end if;
17
  end process;

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Ich hol mal den Prozess mit der unvollständigen Sensitivliste extra raus
> und kürze ihn etwas ein

Deshalb hatte ich mir angwohnt, (nahezu) alles als getakteten Prozess 
zu schreiben ... Dann muss ich mir auch keine Gedanken um die 
Sensitivity-Liste machen.

Wenn ich kombinatorisch etwas mache, dann nicht in Prozessen :)

Bin damit bisher gut gefahren^^

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.