Forum: FPGA, VHDL & Co. Keine M4K Blöcke synthetisiert


von wurstwerner (Gast)


Lesenswert?

Hallo,
Ich habe folgendes Problem: Das angehängte Listing läuft an für sich 
einwandfrei. Die grobe Funktion: Es kommen gemultiplexte Werte über 
in_vector, die in einem Array(ram_array) auseinandersortiert und zwecks 
späteres Mittelwertbildung auch aufaddiert werden.
Allerdings sollen nun im übergeordneten Projekt Zusatzfunktionen 
implementiert werden wofür der Platz auf dem Cyclone EP1C3 nicht mehr 
ausreicht (144 LC zu viel). Meine Hoffnung war nun LC sparen zu können, 
indem die Register ram_array auch tatsächlich als block_ram 
synthetisiert werden, was QuartusII 11.0 allerdings nicht tut. Ich 
vermute einen Fehler meinerseits bei dem Zugriff auf das Array, finde 
ihn aber nicht. Ist eventuell der "verteilte" Zugriff auf das Array das 
Problem und ich muss ein eigenes Entity schreiben, dass auf das RAM 
zugreift? Wäre wirklich eine große Hilfe. Vielen Dank und Grüße
1
ARCHITECTURE mux_control_a OF mux_control IS
2
TYPE states is (wait_for_steady_signal,mux_steady_signal);
3
TYPE ram is array (0 to 15) of Std_Logic_Vector(19 downto 0);
4
5
SIGNAL state: Std_logic;
6
signal counter_sig: std_logic_vector(11 downto 0);
7
SIGNAL prev_counter_sig: Std_Logic_Vector(11 downto 0);
8
signal phys_mux_addr: std_logic_vector(3 downto 0);
9
signal prev_phys_mux_addr: std_logic_vector(3 downto 0);
10
SIGNAL steady_signal_counter: Std_Logic_Vector(15 downto 0) := "0000000000000000";
11
SIGNAL steady_signal_counter_reset: Std_Logic := '0';
12
SIGNAL ram_array: ram := (others => (others => '0'));
13
SIGNAL array_addition_counter: Std_Logic_Vector(11 downto 0) := (others => '0');
14
15
begin
16
  phys_mux_addr             <= mux_addr_in; --signale aus der addr_generator entity übernehmen
17
  counter_sig             <= counter_sig_in;    
18
  steady_signal_counter_reset   <= steady_signal_counter_reset_in;
19
  
20
  process (clk, prev_counter_sig, in_vector, nReset, steady_signal_counter_reset, steady_signal_counter, state, array_addition_counter, mean_val_div,steady_signal_value,phys_mux_addr) --multiplext jeden zählerstand in eigenes register
21
  begin
22
  if (nReset = '0') then
23
    state <= '0';
24
    steady_signal_counter <= (others => '0');
25
    prev_counter_sig <= (others => '0');
26
    array_addition_counter <= (others => '0');
27
  elsif CLK'event and CLK = '1' then
28
    if (state = '1') and (counter_sig /= prev_counter_sig) then --mux_nch zuweisung ein mal jeden add_en4 intervall (counter_sig zählt die add_en4 pulse)
29
      prev_counter_sig <= counter_sig;       
30
      if(array_addition_counter = mean_val_div) then --genug werte zur mittelwertbildung aufaddiert also counter und ram zurücksetzten.
31
        array_addition_counter <= (others => '0'); --hier wird nur zu anfang des nächsten additions zyklus reingesprungen
32
        ram_array(conv_integer(phys_mux_addr)) <= (others => '0');
33
      else
34
        case phys_mux_addr is
35
          when "0000" => ram_array(0) <= ram_array(0) + in_vector;
36
          when "0001" => ram_array(1) <= ram_array(1) + in_vector;
37
          when "0010" => ram_array(2) <= ram_array(2) + in_vector;
38
          when "0011" => ram_array(3) <= ram_array(3) + in_vector;
39
          when "0100" => ram_array(4) <= ram_array(4) + in_vector;
40
          when "0101" => ram_array(5) <= ram_array(5) + in_vector;
41
          when "0110" => ram_array(6) <= ram_array(6) + in_vector;
42
          when "0111" => ram_array(7) <= ram_array(7) + in_vector;
43
          when "1000" => ram_array(8) <= ram_array(8) + in_vector;
44
          when "1001" => ram_array(9) <= ram_array(9) + in_vector;
45
          when "1010" => ram_array(10) <= ram_array(10) + in_vector;
46
          when "1011" => ram_array(11) <= ram_array(11) + in_vector;
47
          when "1100" => ram_array(12) <= ram_array(12) + in_vector;
48
          when "1101" => ram_array(13) <= ram_array(13) + in_vector;
49
          when "1110" => ram_array(14) <= ram_array(14) + in_vector;
50
          when "1111" => ram_array(15) <= ram_array(15) + in_vector;
51
          when others => ram_array(0) <= (others => '0');
52
        end case;
53
        array_addition_counter <= array_addition_counter + 1; --zahl der additionen mitzählen
54
      end if;
55
    end if;
56
    
57
    if(prev_phys_mux_addr /= phys_mux_addr) then 
58
      array_addition_counter <= (others => '0');
59
      ram_array(conv_integer(phys_mux_addr)) <= (others => '0');
60
      prev_phys_mux_addr <= phys_mux_addr;
61
    end if;
62
    
63
  end if;
64
  end process;
65
  
66
  update_outputs: process(clk, nReset, steady_signal_counter_reset, array_addition_counter, mean_val_div, phys_mux_addr)
67
  begin
68
    if(nReset = '0') then
69
      mux_1ch <= (others => '0');
70
      mux_2ch <= (others => '0');
71
      mux_3ch <= (others => '0');
72
      mux_4ch <= (others => '0');
73
      mux_5ch <= (others => '0');
74
      mux_6ch <= (others => '0');
75
      mux_7ch <= (others => '0');
76
      mux_8ch <= (others => '0');
77
      mux_9ch <= (others => '0');
78
      mux_10ch <= (others => '0');
79
      mux_11ch <= (others => '0');
80
      mux_12ch <= (others => '0');
81
      mux_13ch <= (others => '0');
82
      mux_14ch <= (others => '0');
83
      mux_15ch <= (others => '0');
84
      mux_16ch <= (others => '0');
85
    elsif CLK'event and CLK = '1' and (array_addition_counter = mean_val_div) then --werte sind aufaddiert und neue mux adresse liegt an
86
      if(phys_mux_addr = "0000") then          --immer nur das aktuelle ram register updaten
87
        mux_1ch <= ram_array(0)(19 downto bit_shift); --division durch 4 ^= zwei rechtsshift
88
      elsif(phys_mux_addr = "0001") then
89
        mux_2ch <= ram_array(1)(19 downto bit_shift);
90
      elsif(phys_mux_addr = "0010") then
91
        mux_3ch <= ram_array(2)(19 downto bit_shift);
92
      elsif(phys_mux_addr = "0011") then
93
        mux_4ch <= ram_array(3)(19 downto bit_shift);
94
      elsif(phys_mux_addr = "0100") then
95
        mux_5ch <= ram_array(4)(19 downto bit_shift);
96
      elsif(phys_mux_addr = "0101") then
97
        mux_6ch <= ram_array(5)(19 downto bit_shift);
98
      elsif(phys_mux_addr = "0110") then
99
        mux_7ch <= ram_array(6)(19 downto bit_shift);  
100
      elsif(phys_mux_addr = "0111") then
101
        mux_8ch <= ram_array(7)(19 downto bit_shift);
102
      elsif(phys_mux_addr = "1000") then
103
        mux_9ch <= ram_array(8)(19 downto bit_shift);
104
      elsif(phys_mux_addr = "1001") then
105
        mux_10ch <= ram_array(9)(19 downto bit_shift);
106
      elsif(phys_mux_addr = "1010") then
107
        mux_11ch <= ram_array(10)(19 downto bit_shift);
108
      elsif(phys_mux_addr = "1011") then
109
        mux_12ch <= ram_array(11)(19 downto bit_shift);
110
      elsif(phys_mux_addr = "1100") then
111
        mux_13ch <= ram_array(12)(19 downto bit_shift);
112
      elsif(phys_mux_addr = "1101") then
113
        mux_14ch <= ram_array(13)(19 downto bit_shift);
114
      elsif(phys_mux_addr = "1110") then
115
        mux_15ch <= ram_array(14)(19 downto bit_shift);
116
      elsif(phys_mux_addr = "1111") then
117
        mux_16ch <= ram_array(15)(19 downto bit_shift);
118
      end if;
119
120
    end if;
121
  end process update_outputs;
122
      
123
end mux_control_a;

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


Lesenswert?

wurstwerner schrieb:
> indem die Register ram_array auch tatsächlich als block_ram
> synthetisiert werden, was QuartusII 11.0 allerdings nicht tut.
Sieh dir mal an, WIE so ein RAM funktioniert. Und insbesondere, ob es 
gleichzeitig gelesen und beschrieben werden kann:
1
-- geht das: gleichzeitig schreiben  und  lesen?
2
          when "0000" => ram_array(0) <= ram_array(0) + in_vector;
3
          when "0001" => ram_array(1) <= ram_array(1) + in_vector;
Bei Xilinx BRAMs ginge das nicht, und so arg viel anders sind die Dinger 
von Altera sicher auch nicht...

von PittyJ (Gast)


Lesenswert?

Ich hatte auch mal Probleme, dass Quartus einen Speicher über 
Logikeinheiten realisiert hat und nicht das Ram benutzte.
Ich bin dann dazu übergegangen, dass ich das Ram immer über den 
Megawizard erzeugen lasse. Dann werden auch wirklich die 
RAM-Speicherzellen im Chip benutzt.

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


Lesenswert?

PittyJ schrieb:
> Ich hatte auch mal Probleme, dass Quartus einen Speicher über
> Logikeinheiten realisiert hat und nicht das Ram benutzte.
Das liegt dann idR. daran, dass der Synthesizer kein RAM erkennen 
konnte. Für ein zuverlässiges Erkennen eines RAMs aus einer generischen 
VHDL-Beschreibung sollte man sich an die entsprechenden 
Language-Guidelines halten.

von Matthias (Gast)


Lesenswert?

Wir haben hier mehrere ansaetze probiert Altera zum Zeitpunkt der 
Synthese erkennen zu lassen das ein RAM auch im RAM plaziert werden 
soll. Wie Lothar schon sagt (und aus eigener Erfahrung kann ich das 
bestaetigen) erkennt Xilinx ISE bei korrekter Ansteuerung automatisch. 
Bei Quartus ist mir das auch nach intensivem Probieren nicht geglueckt.
Wir machen das mittlerweile anders, binden das altera_mf package ein und 
instantiieren das entsprechende modul von altera direkt im Code.

Der Code unten ist ein Beispiel und wahrscheinlich sind nicht alle 
GENERICS dabei - dafuer gibts von Altera aber eine gute Docu!
http://www.altera.com/literature/ug/ug_ram_rom.pdf
1
library altera_mf;      -- Include altera package for altera blocks
2
  use altera_mf.all;
3
4
  -- Introduce altera-specific altsyncram component
5
  component altsyncram
6
    generic
7
    (
8
      address_aclr_a                      : string;
9
      clock_enable_input_a                : string;
10
      clock_enable_output_a               : string;
11
      init_file                           : string;
12
      intended_device_family              : string;
13
      lpm_hint                            : string;
14
      lpm_type                            : string;
15
      numwords_a                          : natural;
16
      operation_mode                      : string;
17
      outdata_aclr_a                      : string;
18
      outdata_reg_a                       : string;
19
      widthad_a                           : natural;
20
      width_a                             : natural;
21
      width_byteena_a                      : natural
22
    );
23
    port
24
    (
25
      clock0                              : in    std_logic;
26
      address_a                           : in    std_logic_vector (widthad_a - 1 downto 0);
27
      rden_a                              : in    std_logic;
28
      q_a                                 : out   std_logic_vector (width_a - 1 downto 0)
29
    );
30
  end component;
31
32
  ratio_table : altsyncram
33
    generic map
34
    (
35
      address_aclr_a                      => "NONE",                            -- No asynchrone CLEAR necessary
36
      clock_enable_input_a                => "BYPASS",                          -- No clock enable for input
37
      clock_enable_output_a               => "BYPASS",                          -- No clock enable for output
38
      init_file                           => "NONE",                            -- Name of the initialisation file
39
      intended_device_family              => "Cyclone III",                     -- Device family for implementation
40
      lpm_hint                            => "NONE",                            -- In-system modification allowed
41
      lpm_type                            => "altsyncram",                      -- Use a ALTERA SYNCRONE RAM block
42
      numwords_a                          => TABLE_DEPTH,                       -- Define the number of words in table
43
      operation_mode                      => "RAM",                             -- Use block as a RAM cell
44
      outdata_aclr_a                      => "NONE",                            -- No output clear
45
      outdata_reg_a                       => "CLOCK0",                          -- register output to main clock
46
      widthad_a                           => TABLE_DEPTH,                       -- Define the width of address bus
47
      width_a                             => TABLE_WIDTH,                       -- Define the width of data bus
48
      width_byteena_a                     => 1                                  -- 
49
    )
50
    port map
51
    (
52
      clock0                              => i_clk,                             -- Run on main clock
53
      address_a                           => std_logic_vector (address),        -- Address pointer from above
54
      rden_a                              => '1',                               -- Always READ ENABLE
55
      unsigned (q_a)                      => table_output                       -- The table output
56
    );

von abc (Gast)


Lesenswert?

Keine Ahnung wo das Problem sein soll, bei halbwegs sinnvoller 
Beschreibung wird doch alles problemlos erkannt.

Sogar nicht voll ausgenutzte Blöcke aus mehrdimensionalen Arrays werden 
gut auf M4K Blöcke gemappt.

Adresse im Register speichern entsprechend darüber indexieren -> fertig.

Wenn ich natürlich von mehr als 2 Adressen gleichzeitig lesen will oder 
resets einbaue etc, dann wird kein Blockram genutzt.


Bei der ziemlich sinnfreien Beschreibung oben wundert es mich wenig das 
kein BRam verwendet wird.

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


Lesenswert?

Wo ich mir den Original-Code nochmal anschaue fällt mir noch was auf:
1
  update_outputs: process(clk, nReset, steady_signal_counter_reset, array_addition_counter, mean_val_div, phys_mux_addr)
2
  begin
3
    if(nReset = '0') then
4
      :
5
    elsif CLK'event and CLK = '1' and (array_addition_counter = mean_val_div) then --werte sind aufaddiert und neue mux adresse liegt an

1. die Sensitivliste ist überbestimmt. Es würden clk und nReset reichen.
   (Mir würde sogar clk alleine reichen...)
2. das ist eine noch sehr ungewöhnliche Art eines Clock-Enables, wenn
   in die Flankenabfrage gleich eine Kombinatorische Abfrage gepackt 
wird

Ich würde das eher so schreiben:
1
  update_outputs: process(clk)
2
  begin
3
    if CLK'event and CLK = '1' then
4
      if(nReset = '0') then
5
          :
6
      elsif (array_addition_counter = mean_val_div) then --werte sind aufaddiert und neue mux adresse liegt an
7
          :
Oder vielmehr so:
1
  update_outputs: process 
2
  begin
3
    wait until rising_edge(clk);
4
    if (nReset = '0') then
5
        :
6
    elsif (array_addition_counter = mean_val_div) then --werte sind aufaddiert und neue mux adresse liegt an
7
        :

von wurstwerner (Gast)


Lesenswert?

Sowas in die Richtung dachte ich mir schon. Die Hinweise von Lothar und 
Matthias waren aber trotzdem lehrreich. Vielen Dank dafür. Damit werde 
ich erst mal weiter machen.

Eine Frage aber noch: Warum kein Async Reset? Generell oder nur beim RAM 
Zugriff?

Und die Sensitivliste sieht so unschön aus, weil Quartus sonst beim 
synthetisieren meckert...

von Matthias (Gast)


Lesenswert?

Bei uns ist der asynchrone RESET standard. Im instantiierungsbeispiel 
isser nicht drin weil ich den Code eigentlich von einem ROM kopiert hab 
und eben bei "operation_mode" RAM statt ROM geschrieben hab. In dem 
beispiel brauchte ich keinen RESET.
Generell find ichs asynchron schöner, aber Lothar wird einen Grund dafür 
haben denk ich.

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


Lesenswert?

Matthias schrieb:
> Generell find ichs asynchron schöner, aber Lothar wird einen Grund dafür
> haben denk ich.
Es kommt darauf an, was man daraus macht... ;-;
Hier gibt es einen Verweis im 
Beitrag "Re: Timing-Problem?"
Und noch was zum Thema im 
Beitrag "Re: Timing-Problem?"

Bei der Xilinx-Toolchain gibt es sogar einen Schalter, der asynchrone 
Resets automatisch auf synchron umstellt... :-o

Matthias schrieb:
> In dem beispiel brauchte ich keinen RESET.
Ohne Reset ists einfach schöner...

wurstwerner schrieb:
> Und die Sensitivliste sieht so unschön aus, weil Quartus sonst beim
> synthetisieren meckert...
WAS tut das Ding?  :-o
1
  update_outputs: process(clk, nReset, steady_signal_counter_reset, array_addition_counter, mean_val_div, phys_mux_addr)
In diesem Prozess sind trotz der unüblichen Enable-Schreibweise die 
Signale steady_signal_counter_reset und phys_mux_addr unnötig.

Und hier
1
  process (clk, prev_counter_sig, in_vector, nReset, steady_signal_counter_reset, steady_signal_counter, state, array_addition_counter, mean_val_div,steady_signal_value,phys_mux_addr)
gilt das für alle Signale ausser clk und nReset.

von Matthias N. (vbchaos)


Lesenswert?

Lothar Miller schrieb:
> Matthias schrieb:
>> In dem beispiel brauchte ich keinen RESET.
> Ohne Reset ists einfach schöner...

Ja, da gings aber darum das ich das ROM nicht an einen asynchronen CLEAR 
angeschlossen habe, weil das bei einem ROM in meinem speziellen Fall 
nicht so viel Sinn machte.
In Prozessen verwende ich IMMER einen RESET, die Vergangenheit hat mich 
leider zu oft stunden oder tagelang in designs nach Fehlern suchen 
lassen nur weil irgendwelche Knilche module zusammengeschustert haben 
die nie einen RESET aus der Nähe gesehen haben. Dann starten die Zaehler 
sonst wo und alle synchronität ist zum Teufel.

Das Quartus bei der sensitivity list meckert will ich nur zu gerne 
glauben, allerdings wohl eher weil zuviel drin steht. Deine sensitivity 
list braucht in beiden fällen genau 2 signale - reset und clock. Wenn 
Quartus dann noch meckern sollte, würde mich wirklich sehr interessieren 
warum...

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


Lesenswert?

Matthias Nix schrieb:
> In Prozessen verwende ich IMMER einen RESET, die Vergangenheit hat mich
> leider zu oft stunden oder tagelang in designs nach Fehlern suchen
> lassen nur weil irgendwelche Knilche module zusammengeschustert haben
> die nie einen RESET aus der Nähe gesehen haben.
Nur um mal über den Tellerrand von Altera rauszuschauen (und weil die 
FPGAs soooo arg unterschiedlich gar nicht sind): lies das recht 
unterhaltsame WP272 von Xilinx.

von abc (Gast)


Lesenswert?

Matthias Nix schrieb:
> In Prozessen verwende ich IMMER einen RESET, die Vergangenheit hat mich
> leider zu oft stunden oder tagelang in designs nach Fehlern suchen
> lassen nur weil irgendwelche Knilche module zusammengeschustert haben
> die nie einen RESET aus der Nähe gesehen haben. Dann starten die Zaehler
> sonst wo und alle synchronität ist zum Teufel.

Wie soll das denn passieren?

Ein Zähler startet immer da wo er auch initialisiert wird. Ob ich das 
bei einschalten tue oder per Hand später resetten muss spielt doch keine 
Rolle.

Verwende eigentlich grundsätzlich keine Resets, weil es mir einfach zu 
fehlerträchtig ist. Irgentein Signal vergisst man immer wieder in den 
Reset reinzunehmen und das läuft dann frei während Andere im Reset 
hängen und hinterher funktioniert garnix mehr.

Ein funktionierender Reset im laufenden Betrieb (also lange nach dem 
einschalten) ist mir bei halbwegs umfangreichen Designs ohnehin noch nie 
begegnet. Funktionierend im Sinne von: "so vertrauenswürdig wie ein 
neues Einschalten"

von Matthias (Gast)


Lesenswert?

abc schrieb:
> Verwende eigentlich grundsätzlich keine Resets, weil es mir einfach zu
> fehlerträchtig ist.

Auf der Autobahn kommt Ihnen ein Falschfahrer entgegen - Einer? 
TAUSENDE!

Mal ernsthaft: Wenn du meinst, du musst es anders machen, mach es doch 
so... Willst du da jetzt mit mir diskutieren? Ich werde dich nicht 
herbeibeten was alles auftreten kann wenn man keinen RESET verwendet, 
denn scheinbar bist du (gemessen an deinen bisherigen Kommentaren) sehr 
von dir überzeugt und brauchst nichts mehr dazu zu lernen. Von daher: 
Warum fragst du mich überhaupt etwas?

von Klaus (Gast)


Lesenswert?

Matthias schrieb:
> Mal ernsthaft: Wenn du meinst, du musst es anders machen, mach es doch
> so... Willst du da jetzt mit mir diskutieren? Ich werde dich nicht
> herbeibeten was alles auftreten kann wenn man keinen RESET verwendet,
> denn scheinbar bist du (gemessen an deinen bisherigen Kommentaren) sehr
> von dir überzeugt und brauchst nichts mehr dazu zu lernen. Von daher:
> Warum fragst du mich überhaupt etwas?

Was ist dir den über die Leber gelaufen? Ich glaube, dir ist nicht 
bewusst, das ein Signal ohne Reset auf einem FPGA nicht zufällig 
startet, sondern mit 0 initialisiert wird. Außerdem kann man auch bei 
der Deklaration des Signals einen Initialisierungeswert vorgeben, mit 
dem das Signal zu anfang geladen wird. Daher ist nur in wirklichen 
Ausnahmefällen ein Reset wirklich notwendig.

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


Lesenswert?

Matthias schrieb:
> Auf der Autobahn kommt Ihnen ein Falschfahrer entgegen - Einer?
> TAUSENDE!
Wenn du diese Witzschublade schon aufmachst, dann hab ich auch noch 
einen:
Scheixe muß schmecken. Tausende Fliegen können nicht irren.

Im Ernst: du hast das erwähnte Whitepaper nicht gelesen?
Ein Reset ist meist unnötig. Und wenn schon ein Reset nötig ist, dann 
sollte der lokal gehalten werden.

Der Hintergrund: das Reset-Signal muß wie jedes andere Signal verdrahtet 
werden. Es gibt kein "Reset-Netzwerk" (wie z.B. die Taktnetze), das 
dafür sorgt, dass der Skew dieses Signals gering bleibt. Und wenn du 
irgendein Signal quer durchs ganze FPGA verdrahten mußt, dann wird dein 
Design langsam.

Ich vermute das: DU hast dir irgendwann mal die Finger verbrannt und 
ziehst jetzt schon früh morgens die feuerfesten Handschuhe an, dass 
sowas nicht mehr passiert. Oder kannst du einen (in Zahlen 1) guten 
Grund nennen, immer einen Reset zu verwenden?
Und nein, das Argument "brauche ich für den Resettaster in der 
Entwicklungsphase" gilt NICHT. An zigtausenden Geräten bei Kunden wird 
nicht mehr entwickelt.

von Matthias (Gast)


Lesenswert?

Klaus schrieb:
> Ich glaube, dir ist nicht
> bewusst, das ein Signal ohne Reset auf einem FPGA nicht zufällig
> startet, sondern mit 0 initialisiert wird.

Wenn ich aber doch gar keine 0 will?

Klaus schrieb:
> Außerdem kann man auch bei
> der Deklaration des Signals einen Initialisierungeswert vorgeben, mit
> dem das Signal zu anfang geladen wird. Daher ist nur in wirklichen
> Ausnahmefällen ein Reset wirklich notwendig.

ähm, ja...

Lothar Miller schrieb:
> Ich vermute das: DU hast dir irgendwann mal die Finger verbrannt und
> ziehst jetzt schon früh morgens die feuerfesten Handschuhe an, dass
> sowas nicht mehr passiert. Oder kannst du einen (in Zahlen 1) guten
> Grund nennen, immer einen Reset zu verwenden?
> Und nein, das Argument "brauche ich für den Resettaster in der
> Entwicklungsphase" gilt NICHT. An zigtausenden Geräten bei Kunden wird
> nicht mehr entwickelt.

Bin ich dir jetzt Rechenschaft schuldig? Bist du mein Vorgesetzter, mein 
Chef oder mein Kunde? Nein? Oh... Aber OK, ein Grund: globaler Neustart 
des Designs mit garantiert definierten und bekannten Zuständen aller 
Ausgänge ohne die Stromzufuhr der Leiterplatte oder des FPGAs zu 
unterbrechen. Wenn du da was besseres weisst, bin ich ganz Ohr...

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


Lesenswert?

Matthias schrieb:
> Wenn ich aber doch gar keine 0 will?
Dann schreib '1' hin:
1
  signal meinvektor : std_logic_vector(7 downto 0) := "10100101";
2
  signal meininteger : integer range 0 to 1023 := 567;
Das kann zwischenzeitlich jeder Synthesizer.

Matthias schrieb:
> Bin ich dir jetzt Rechenschaft schuldig?
Nein.

> Aber OK, ein Grund: globaler Neustart
> des Designs mit garantiert definierten und bekannten Zuständen aller
> Ausgänge
Du hast offenbar spezielle Aufgaben und brauchst spezielle Lösungen. Ich 
meine, ein Sytem sollte auch einen Stromausfall unbeschadet überstehen.
> ohne die Stromzufuhr der Leiterplatte oder des FPGAs zu unterbrechen.
Du kannst eine Rekonfiguration eines FPGAs idR. durch einen dedizierten 
Pin von aussen einleiten (Xilinx : PROG_B). Dort habe selbst ich dann 
einen "Entwickler-Reset-Knopf" angeschlossen.

> Wenn du da was besseres weisst, bin ich ganz Ohr...
Derzeit arbeiten alle FPGA-Hersteller an der partiellen Rekonfiguration 
zur Laufzeit. Das könnte was sein...

von Matthias (Gast)


Lesenswert?

Lothar Miller schrieb:
> Matthias schrieb:
>> Wenn ich aber doch gar keine 0 will?
> Dann schreib '1' hin:  signal meinvektor : std_logic_vector(7 downto 0) := 
"10100101";
>   signal meininteger : integer range 0 to 1023 := 567;
> Das kann zwischenzeitlich jeder Synthesizer.

Da muss ich bei Altera mal nachschauen, ich weiss nur das ISE das kann. 
Modelsim richtet sich danach, dass ein Synthesizer das kann finde ich 
zumindest grenzwertig und ehrlich gesagt auch nicht so schön - Aber das 
soll meine persönliche Meinung bleiben.

Lothar Miller schrieb:
> Du hast offenbar spezielle Aufgaben und brauchst spezielle Lösungen.

Exakt.

Lothar Miller schrieb:
> Du kannst eine Rekonfiguration eines FPGAs idR. durch einen dedizierten
> Pin von aussen einleiten (Xilinx : PROG_B). Dort habe selbst ich dann
> einen "Entwickler-Reset-Knopf" angeschlossen.

Die Prozedur kenne ich, allerdings ist das nicht was wir wollen, weil 
ich dann wieder nicht weiss, was auf den entsprechenden Ausgaengen an 
Zustaenden vorliegt, auch wenn es nur fuer etwa eine Sekunde ist.

Ich will ja auch keinen Streit vom Zaun brechen, es gibt nur eben nicht 
DIE Lösung für alles. Ich bin auch die Diskussion über Variablen leid, 
mein Kollege findets toll, ich nicht... Solange er sie nur synchron 
benutzt, kann ich damit leben :)
Abstriche muss man immer irgendwie machen. Wir brauchen nicht so enorm 
viel MHz, aber haben lieber das plus an Zuverlaessigkeit

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


Lesenswert?

Matthias schrieb:
> dass ein Synthesizer das kann finde ich zumindest grenzwertig
Oh, die können zwischenzeitlich noch ganz andere Dinge:
http://www.lothar-miller.de/s9y/archives/47-wait-im-Prozess.html
http://www.lothar-miller.de/s9y/archives/16-Takt-im-Prozess.html

> und ehrlich gesagt auch nicht so schön
Es ist einfach eine logische Weiterentwicklung der Software:
Ein RAM-basiertes FPGA muss sowieso am Anfang aus dem Config-Speicher 
geladen werden. Warum dann nicht gleich mit den "richtigen" Werten?

> bin auch die Diskussion über Variablen leid, mein Kollege findets toll
Das isser, der Klassiker:
Beitrag "Variable vs Signal"

von Matthias (Gast)


Lesenswert?

Lothar Miller schrieb:
> Das isser, der Klassiker:

Ja, aber wie gesagt bin ichs leid ;)

von Christian R. (supachris)


Lesenswert?

Matthias schrieb:
> Die Prozedur kenne ich, allerdings ist das nicht was wir wollen, weil
> ich dann wieder nicht weiss, was auf den entsprechenden Ausgaengen an
> Zustaenden vorliegt, auch wenn es nur fuer etwa eine Sekunde ist.

Das ist doch klar definiert. Bei Xilinx kann man mit dem HSWAPEN Pin 
sogar festlegen, ob die I/Os im Moment der Konfig hochohmig sind oder 
mit Pullups arbeiten. Das geht ganz sicher auch bei Altera und 
Lattice...
Ein sauberes HW-Design hat an allen wichtigen Ausgängen Pull-Widerstände 
für den Fall, dass man mit den Konfig-Pull-Ups nicht hinkommt, weil man 
entweder ein low braucht oder die zu schwach sind.

Natürlich ist ein globaler Rsset nicht verboten, wenn man mit dem 
Mehrverbrauch an Ressourcen leben kann. Was sich allerdings von selbst 
verbietet ist ein asynchroner Reset an mehr als einem FlipFlop. Das 
ergibt nur Kraut und Rüben im Moment des Loslassens des Resets. Wir 
benutzen für einige Designs auch einen recht globalen Reset, der über 
den USB Controller an der normalen Datenübertragung vorbei ausgelöst 
werden kann. Somit kann man die Kiste in einen definierten Zustand 
bringen, wenn die beispielsweise auf einen externen Trigger wartet, der 
nicht kommt. Aber der ist sauber einsynchronisiert und nur da 
angeschlossen, wo es nötig ist.

von berndl (Gast)


Lesenswert?

Matthias schrieb:
> Aber OK, ein Grund: globaler Neustart
> des Designs mit garantiert definierten und bekannten Zuständen aller
> Ausgänge ohne die Stromzufuhr der Leiterplatte oder des FPGAs zu
> unterbrechen. Wenn du da was besseres weisst, bin ich ganz Ohr...

einfach neu programmieren/laden vielleicht?

von abc (Gast)


Lesenswert?

Matthias schrieb:
> Da muss ich bei Altera mal nachschauen, ich weiss nur das ISE das kann.

Das kann Altera genauso wie Xilinx, zumindest auf allen aktuellen FPGAs.

Matthias schrieb:
> Aber OK, ein Grund: globaler Neustart
> des Designs mit garantiert definierten und bekannten Zuständen aller
> Ausgänge ohne die Stromzufuhr der Leiterplatte oder des FPGAs zu
> unterbrechen.

Und das klappt bei dir tatsächlich?

Trotz das Blockrams jetzt nicht mehr bei 0 sind?
Du vergisst nie ein Signal in den Reset reinzunehmen?
Deine Design sind klein genug damit der Reset überall Synchron 
gleichzeitig ankommt und auch wieder weg ist?
Externe Komponenten überstehen diese Phase bzw lassen sich entsprechend 
wieder konfigurieren?

Wenn du das schaffst, Respekt.

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


Lesenswert?

abc schrieb:
> und auch wieder weg ist?
Das Verlassen des Resets ist der eigentliche Knackpunkt.
Denn wenn auf dem handverdrahteten und damit langsamen Resetpfad ein 
größerer Skew auftritt (wie gesagt: es gibt kein Resetnetz mehr auf 
aktuellen FPGAs, auf jeden Fall keines, das dem Anwender zur Verfügung 
steht), dann könnte die eine FSM den reset noch sehen, die nadere schon 
freigegeben sein. Oder schlimmer: 6 von 13 FFs einer FSM sind noch im 
Reset, die anderen 7 sind einen Takt früher losgelaufen.
Es gibt solche Designs, die nach einem Reset nicht immer anlaufen. Wenn 
sie aber angelaufen sind, dann funktioniert alles tagelang problemlos...

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.