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
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
elsifCLK'eventandCLK='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
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...
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.
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.
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
libraryaltera_mf;-- Include altera package for altera blocks
2
usealtera_mf.all;
3
4
-- Introduce altera-specific altsyncram component
5
componentaltsyncram
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:instd_logic;
26
address_a:instd_logic_vector(widthad_a-1downto0);
27
rden_a:instd_logic;
28
q_a:outstd_logic_vector(width_a-1downto0)
29
);
30
endcomponent;
31
32
ratio_table:altsyncram
33
genericmap
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
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.
elsifCLK'eventandCLK='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
ifCLK'eventandCLK='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
waituntilrising_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
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...
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.
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
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...
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.
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"
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?
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.
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.
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...
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...
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
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.
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?
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.
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...