Im folgenden meine Überlegungen wie man (als Anfänger) synthesefähigen
code schreiben kann. ich konzentriere mich dabei auf vhdl das kenn ich
am besten.
Nicht alles was vhdl/verilog versteht und simulierbar ist (modelsim)
wird mit dem selben verhalten in einen FPGA/cpld synthetisiert. das
liegt an zwei gründen:
-(synchrones) digitales design hat seine regeln, die Gatter und ff auf
dem chip können nicht alles was (man|aNFÄNGER) sich wünscht.
-Vhdl ist geschwätzig, die synthese ist nur künstlich intelligent (also
dumm)
Folgende Regeln sind strenger formuliert als nötig damit sie anfänger
vor fallgruben schützen. ein erfahrener Anwender kann in spezialfällen
dagegen verstossen, wenn er weiss was er tut:
Only true fools and true experts use gated clocks
(1) Flankenwechsel ('event, rising_edge, posedge) nur bei taktsignalen
verwenden.
(2) keine Takte multiplexen oder abschalten (gated clocks)
(3) den zustand hochohmig ('Z') nur an fpga/cpld pins verwenden.
(4) Nur die ports am Top level modul dürfen die richtung inout verwenden
(5) für Ports nur in,out oder inout benutzen.
(6) in statemachines nur einfache zuweisungen verwenden, Zähler (counter
<= counter + 1) oder multiplexer in einem extra process oder ausserhalb
eines processes verwenden.
(7) ein process hat immer folgenden Rahmen und sens list, ausnahmen
reset mit andere Polarität, takt mit anderer flanke, kein reset
1
process(clk,rst)
2
begin
3
ifrst='1'then
4
--..
5
elsifrising_edge(clk)then
6
--..
7
endif
8
endprocess;
Ausnahmen wie erwähnt meinen:
1
process(clk,rst_n)
2
begin
3
ifrst_n='0'then
4
--..
5
elsifrising_edge(clk)then
6
--auch falling_edge(clk) then
7
--..
8
endif;
9
endprocess;
(8) in einem design takt immer mit derselben Flanke verwenden
(9) Flanken bedingen nicht mit anderen signalen verwenden, also Nie:
if rising_edge(clk_i) and signal2 = '0' then --bullshit
(10) nur die typen std_logic, std_logic_vector, unsigned oder signed
verwenden.
(11) verwende bedingte zuweisungen
1
sig3<='1'when(zustand=aktiv)andenable='1'else
2
'0';
(12) verwende nie wait oder after
(13) Nutze applicationnotes und synthese style guides des
chipherstellers (Altera, xilinx)
(14) Verstehe jede warning, error in der reportdatei des synthesetools
(Xilinx:XST:*.syr)
(15) nutze die Möglichkeit einen stromlaufplan des syntheseergebnises
anzuschauen (Xilinx:ise:RTL-view)
Das sollte für den dikussionsstart genügen. Bitte ergänzen und beachte
das ist für anfänger gedacht, Beschreibungen für Sonderfälle wo diese
reglen aufgeweicht werden verwirren mehr als das sie helfen.
Den Sinn von (9) versteht ich nicht ganz, mein altes Xilinx-ISE hat da
immer den invertierten Clk-Enable-Eingang für Signal2 verwendet,
genauso, wie ich es haben wollte!?
#(9) Flanken bedingen nicht mit anderen signalen verwenden, also Nie:
# if rising_edge(clk_i) and signal2 = '0' then --bullshit
Also für mich sieht das nach gated clock aus. Was du meinst ist wohl
1
ifrising_edge(clk_i)then
2
ifsignal2='0'then
3
q<=d;
4
endif;
5
endif;
und nach meiner regel wäre folgendes verboten:
1
ifrising_edge(clk_i)andsignal2='0'then
2
q<=d;
3
endif;
Hm, grübel simutechnisch ist beides wohl identisch. ist halt ne Frage
wie ein synthesefähiges FF für die verscheidenen hersteller zu
beschreiben ist. Kann sein das die auf Takt als einziges bedingung in
der zeile mit der edge abfrage bestehen, also zeilenweise jeden
ff-eingang beschreiben.
Die idee hinter dem verbot von log. verknüpfungen mit der
Flankenerkennung ist Verhindern von gated clocks. Vielleicht kommt es
darauf an, ob in der sens list wirklich nur der takt und evt. der
asynchrone reset steht.
Es macht ein Unterschied in der Synthese, das konnte ich feststellen.
Schreibt man es in eine Zeile so wirds ein Gated Clock, schreibt man's
in zwei Zeilen mit separater IF abfrage so wird es ein getaktes FF für
die zweite Zeile. Das ist also besser und deshalb benutze ich immer
1
ifrising_edge(clk_i)then
2
ifsignal2='0'then
3
q<=d;
4
endif;
5
endif;
Deine Regeln sind super gut und teilweise mache ich das schon intuitiv
so (komme aus der normalen sequientiellen Programmierung ;)
nur 6.) solltest du ganz genau erklären. Verstehe schon das WARUM aber
nicht das WIE ?
Wenn ich einen getakteten Counter habe wie soll ich diesen ausserhalb
meines getakteten Hautprozesses der die State Machine (getaktet
natürlich) enthält, ebenfalls im gleichen Takt aber in eigenem Process
implementieren ? Als kombinatorische Logik ?
Gruß Hagen
Vielleicht sollte noch in die Regeln, dass Standardzuweisungen bei
Signaldeklaration nicht synthesefähig sind, genauso wie initial-Blöcke,
die in etwa das gleiche machen. Außerdem keine for-Schleifen für Zähler
verwenden :-) .
Ich kann es im Moment nicht ausprobieren, soweit ich mich erinnere,
führten beide Varianten auf das gleiche Ergebnis mit Benutzung des
Clk-Enable-Eingangs.
Die gated Clock bekam ich, wenn ich ein Signal aus zwei anderen via
"and" Verknüpfung erzeugte und dann auf das Steigen des neuen Signals
wartete.
So tiefgehend habe ich mich mit der Materie nicht beschäftigt, aber wenn
ich auf die RTl-Schematik geschaut habe, waren die Möglichkeiten der FFs
immer voll genutzt. Trotzdem hast du Recht, dass man es von vorneherein
so schreiben sollte, dass unterschiedliche Interpretationen
ausgeschlossen sind.
Da hast du eine wirklich gute Richtlinie erstellt!
#Wenn ich einen getakteten Counter habe wie soll ich diesen ausserhalb
#meines getakteten Hautprozesses der die State Machine (getaktet
#natürlich) enthält, ebenfalls im gleichen Takt aber in eigenem Process
#implementieren ? Als kombinatorische Logik ?
Beispiel
beide counter verhalten sich identisch, aber in der zweiten varianten
erkennt die synthese sicher sinen Zähler, während sie in der zweiten
durch den "zerissenen" counter Probleme haben kann.
setzt man dagegen reset_sig und cnt_ena von der fsm aus, hat man einen
Takt verspätung zwischen count_q und count2_q.
der "trick" liegt in der Abfrage der zustandsvariable für den
Zustandsübergang und für das setzen des counters extra. das entspricht
genau den Teilschaltungen die die synthese bauen muss:
-Kombinatorik von den Q-Ausgängen der FF des Zustandssignals und einiger
Eingangssignale zu den R/S/CE(?)-Eingängen der selben FF.
-Kombinatorik von den Q der FF des Zustandssignals und einiger (andere)
Eingangssignale zu den CE und R der FF des counters.
Wird es so zerteilt, hat es das Synthesetool leichter. Sonst droht Murks
(zu groß, falsches Verhalten) oder es geht garnicht. Aber zumindest die
ISE ist inzwischen schlau genug da fast immer noch was draus zu machen.
Mit dieser regel sollten es aber auch "dümmere" tools den code
übersetzten können.
-
@GümmelTürk
Danke für den Anhang.
Das bringt auch Licht in die Sache mit dem use Befehl,
wen ich das Projekt nicht in einem eizigen File halten will.
Aber die Referenz in dem anderen File nutzen will. ???
Gruss, Holger.
# GümmelTürk
Im Anhang seite 25 ist ein Fehler.
Ein FF mit asynchronen Reset wird nicht wie angegeben so beschrieben:
1
architecturertlofregaresetis
2
begin-- rtl
3
reg:process(clk,rst)
4
begin-- process reg
5
ifrisingedge(clk)then
6
q<=d;
7
endif;
8
ifrst='0'then
9
q<='0';
10
endif;
11
endprocessreg;
12
endrtl;
sondern
1
reg:process(clk,rst)
2
begin-- process reg
3
ifrst='0'then
4
q<='0';
5
elsifrisingedge(clk)then
6
q<=d;
7
endif;
8
endprocessreg;
Es scheint elegant zu sein, im Process Zuweisungen im IF nicht durch ein
elsif zu verbinden (es ist wird eben immer die letzte (untere) gültige
Zuweisung ausgeführt), aber das ist unübersichtlich und unlogisch (die
höchst priore Anweisung steht zuletzt.
Auch die folgende seite ist inkorrekt, mindestens Xilinx fordert das man
einen synchronen reset wie folgt beschreibt:
1
reg:process(clk)
2
begin-- process reg
3
ifrisingedge(clk)then
4
ifrst='0'then
5
q<='0';
6
else
7
q<=d;
8
endif;
9
endif;
10
endprocessreg;
Und statt '0' steht auf der Folie ’0’ (falsches Hockomma), auch das
Kommantarzeichen -- kommt verhunzt von der Folie rüber, vielleicht ein
PDF Problem.
und low-aktive signale sollten im namen als solche gekennzeichnet sein,
also rst_n statt rst.
Ob ich dem Prof mal schreiben tu?
Da fallen mir auch noch ein paar Regeln ein:
- in der Syntese keine Variablen verwenden (falls doch dann
nur innherhalb eines Processes.
- nicht die Bibliotheken
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
sonder numeric_std einbinden
use ieee.numeric_std.all;
Eine meiner Meinung nach gute Zusammenfassung (leider in Englisch)
habe ich mal im Anhang beigefügt.
Zu Punkt (7). Mann sollte eigentlich nur
if (rst = '1') then
verwenden. Falls dann irgend ein Design mit '0' resettet wird
so kann das reset-Signal einmal im Toplevel invertiert werden.
Sonst baut der Compiler vor jedem Modul eine Inverter
ins reset-Signal ein.
Gruß
Ralf
Erstmal Danke und Händeklatschen für den
schönen Beitrag und die hehren Ziele.
Ich habe ein paar Fragen, deren Beantwortung
sicher auch anderen helfen wird.
zu 8.:
Falls ich doch etwas auf die andere Flanke
machen will (weil z.B. irgendein
Chip, den man ansteuert, das braucht),
ist es das Richtige, ein CLK2 <= NOT CLK; zu nutzen?
zu 6.:
Das ist glaube ich die einschneidenste "Regel". :)
Das Beispiel, was du (FPGA-Küchle) dann gegeben hast,
habe ich gesehen und auch halbwegs verstanden.
Aber trotzdem fällt es mir schwer, dass jetzt auf
vorhandene "echte" Fälle anzuwenden bzw. umzusetzen.
Hast du evtl. ein "wirkliches", also komplettes Beispiel
in deiner Küche, wo man alles komplett sieht und dadurch
genau sehen kann, wie man das aufbaut?
zu 6.:
#Hast du evtl. ein "wirkliches", also komplettes Beispiel
#in deiner Küche, wo man alles komplett sieht und dadurch
#genau sehen kann, wie man das aufbaut?
Aus rechtlichen Gründen werde ich Designs die für Geld enstanden sind
nicht veröffentlich (dürfen). Ich schau mal nach freien designs, die den
regeln genügen. meine erster Kandidat wäre der 8 bit uC Picoblaze von
Xilinx. der liegt in vhdl vor und der autor Ken chapman schreibt nur
brauchbaren code (ne menge tips hab ich von ihm gelernt). man schon ob
der die counter auch anfängergerecht auslagert.
#zu 8.:
#Falls ich doch etwas auf die andere Flanke
#machen will (weil z.B. irgendein
#Chip, den man ansteuert, das braucht),
#ist es das Richtige, ein CLK2 <= NOT CLK; zu nutzen?
Keine allgemeine Antwort, außer beim FPGA, synthesestool hersteller
nachzuschauen.
Xilinx sagt (es klappt auch ab ise 8.1.)
-allgemein statt rising_edge falling edge verwenden (klappt gut, neuere
tools erkennen auch selbstständig das das timing sich halbiert (wenn
signale zwischen FF mit rising und FF mit falling wandern )
-für DDR-IOB-FF den negativen takt per inverter zu erzeugen also clk_n
<= not clk;
-falls du wirklich einen zweiten negierten Takt brauchst, also nicht die
FF mit den invertierten takteingang benutzen kannst, dann erzeuge diesen
takt nicht per inverter sondern mit einem Taktmanagere oder
takt-regelkreis(DCM,DLL).
Was vielleicht noch nicht explizit gesagt wurde, dass für sequentielle
Logik alle process (always) Konstrukte in einer Takt-Domäne sein
sollten. Also nur mit ein und dem selben Takt versorgt werden sollten.
Gerade für Anfänger mag es vielleicht sinnvoll sein erst mal für eine
Entwicklung nur eine Takt-Domäne zu nutzen.
vielleicht sollte man hier aber zwischen CPLD und FPGA unterscheiden, da
sich die interne Struktur doch stark unterscheidet. Bei ersteren dienen
die globalen Clocks letztendlich nur zum Einsparen von Produkttermen,
ansonsten kann jede Makrozelle theoretisch mit einem anderen Signal als
Takt versorgt werden. Für den Anfänger mag das zwar nicht von Belang
sein, aber spätestens wenn die Projekte etwas grösser werden, kann ein
zentraler Takt, mit dem alles synchron läuft, ziemlich viele Resourcen
fressen. Und die gibt es bei CPLD's nicht gerade in grossen Mengen.
@FPGA-Küchle:
Kann das sein, dass in deinem Beispiel weiter oben, wie man einen Zähler
außerhalb von FSM betreibt, die Abfrage nach Takt-Flanke fehlt und in
der Zeile count2_q <= count_q + 1, statt count_q count2_q stehen soll,
und reset_sig in die Sens Liste des Prozesses aufgenommen werden muss?
Statt:
Ich weiß, ich bin manchmal kleinlich, aber bitte um Aufklärung, denn ich
möchte gerne das mit dem Auslagern des Zählers aus der FSM voll und ganz
verstanden haben.
Gruß,
Alex
>begin> if reset_sig <= '1' then> count2_q <= "000";>>dumme Frage, müsste das nicht if reset_sig = '1' then heissen?
stimmt, da müsste auch noch if reset_sig = '1' heissen:
#Abfrage nach Takt-Flanke fehlt und in
Ja
#der Zeile count2_q <= count_q + 1, statt count_q count2_q stehen soll,
Ja
#und reset_sig in die Sens Liste des Prozesses aufgenommen werden muss?
nein
(soll ein synchroner reset werden, aber ohne rising_edge ist das ja
nicht erkenntlich.
Asche aufs Haupt, sollte wohl länger ausschlafen ...
#dumme Frage, müsste das nicht if reset_sig = '1' then heissen?
ja
ich knüppele es abends mal durch die synthese eh ich wieder so nen shit
verbreite.
@fpgakuechle,
ne ne, ist halb so schlimm, ich finde es super, dass du dir soviel Mühe
machst, da können solche Fehler schnell mal vorkommen.
Wenn sich Leser aktiv mit der Materie beschäftigen werden sie auch diese
Fehler finden, Alex und ich hamse ja auch gefunden.
Viel wichtiger ist das Prinzip bzw. ein Konzept, und das hast du super
erklärt.
Danke auch an Alex.
Ich fange übrigens gerade mit VHDL an, habe aber zuvor schon einige CPLD
Projekte in ABEL gemacht.
Gruß Volker
Ich finde es wichtig das man unbedingt ein syncrones Design erzugen
sollte und asyncrone Designs als Anfänger meiden sollte. Zudem müssen
die SIGNALE oder PORTS immer durch ein RESET in einen definierten
Anfangszustand gesettz werden. Dies sind aus meiner Sicht die
wichtigsten Regeln Werden diese nicht befolgt kommt es zu Fehlern die
man ganz schwer findet.
Da muss ich ChrisV doch voll unterstützen:
So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen
(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der
Resetleitung auch recht interessant:
Ein Teil vom FPGA wird zurückgesetzt, der Rest kriegt davon nichts mit
--> Statemachines laufen Amok, Zähler zählen Käse...
Probierts mal aus.
Kurz und gut:
Ein Reset von aussen ist ein asynchrones Signal, das gehört erst mal zum
FPGA-Takt synchronisiert und dann intern verarbeitet. So ist das.
Und Michael hat im ersten Satz auch recht:
nur Anfänger können mal (aus Versehen) ein asynchrones Design
hervorzaubern, einem Profi, der sein Geld mit FPGA-Design verdient, darf
das nicht passieren.
Nur müssen Signale nicht mit einem Reset auf definierte Werte gesetzt
werden, ich kann (zumindest für Xilinx FPGAS) schon bei der Synthese
Startwerte angeben (ein FPGA ist eh' nur eine Art RAM, das geladen
wird):
Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.
Das passt dann auch für die Simulation.
Gruß Lothar
Am Rande:
Eine Einstellungs-Frage für FPGA-Designer könnte übrigens lauten:
"Weiviele Takte hatte Ihr letztes Design?"
Die richtige Antwort darauf ist:
"Einen"
@Lothar
>So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen>(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der>Resetleitung auch recht interessant:
Wir wollen mal die Kirche im Dorf lassen. Ein auf einen ein paar (1..10)
Picosekunden langen Puls reagieren wahrscheinlich nicht mal die
schnellsten FPGAs. Bei 100ps würde ich mal frühestens was vermuten.
>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.
Er ist implizit (=0).
>Das passt dann auch für die Simulation.
Dort wird deine Zuweisung ausgeführt. Und damit hast du eine
wunderschöne Inkonsistenz zwischen Simulation und Synthese. ->
SCHROTT!!!
>Eine Einstellungs-Frage für FPGA-Designer könnte übrigens lauten:>"Weiviele Takte hatte Ihr letztes Design?">Die richtige Antwort darauf ist:>"Einen"
Noch so ein Durchblicker-Satz. :-(
Die richtige Antwort wäre wohl eher
"So viel wie nötig, so wenig wie möglich"
Das üben wir nochmal.
MFG
Falk
Hallo,
schönes posting.
Ich habe mir auch ein paar Anregungen überlegt:
zum einen fände ich auch, wie andere schon gesagt haben, die
unterscheidung CPLD <-> FPGA wichtig. So wie ich es verstanden habe ist
regel 8 für CPLDs nicht nötig.
Obohl oder gerade weil ich Anfänger bin habe ich auch einen vorschlag
für eine Ergänzung: Modelliert man eine FSM muss man immer im
case(zustand)
einen default teil haben. auch wenn dieser default teil nie ausgeführt
werden wird. na hat mich heute Morgen darauf gebracht.
dann muss immer in jedem zustand jede verwendete variable zugewiesen
werden (z.B. next_state) sonst werden latches modelliert (hat mich auch
na drauf gebracht.
Vielleicht trifft das auch nur für Verilog und nicht für VHDL zu. Für
den Fall würde ich auch eine Unterscheidung verilog <-> vhdl
vorschlagen.
Das waren 2 der größten Probleme die ich als Anfänger hatte, die ich nie
selbst hätte lösen können und nur durch dieses Forum weiter gekommen
bin.
in einem wiki eintrag fände ich als Anfänger auch ein Gerüst einer fsm
hilfreich. na hat in einem anderen posting sowas geschrieben:
Beitrag "Problem in Verilog: Simulation läuft,Fit gibt falsches Desi"
(weit unten. 17.2.)
mir kommt aber auch schon eine frage zur regel (2). was mache ich, wenn
ich einen sram ansteuern will. an write enable muss dann ja ein je nach
anwendung schneller takt anliegen. aber wenn ich aus dem ram lesen will
muss der natürlich abgeschaltet sein. wie mache ich das dann? externe
elektronik?
bzw habe ich die bedeutung des wortes gated clock falsch verstanden?
Zu dieser Standardwert-Initialsierungs-Diskussion und damit verbundenes
weglassen des reset:
Es mag ja sein, dass Xilinx-Tools für FPGAs oder auch die anderer
Hersteller Standardwerte bei Signaldeklaration in der Synthese
akzeptieren und den FPGA entsprechend initialisieren. Wobei mich mal
interessieren würde inwieweit das wirklich so ist, scheint es ja viele
Meinungen zu geben?
Allerdings sollen das hier ja vielleicht auch allgemeine Regeln zu
synthesefähigem Code werden. Eventuell beachtet nicht jedes Synthesetool
diese Standardwerte. Abgesehen davon kann man ja mit VHDL und Verilog
auch ASICs beschreiben und dann sind Standardwerte erst recht fehl am
Platz, außerdem ist dann ein reset mehr als nötig. (Daher vielleicht
auch die verbreitete Meinung, Standardzuweisungen seien grundsätzlich
nicht synthesefähig.) Das hat zwar nicht viel mit programmierbarer Logik
zu tun aber man sollte es vielleicht zumindest erwähnen bevor jemand es
falsch lernt.
Meinungen?
Die Initialisierung über VHDL bei den Xilinx-Tools funktioniert
(jedenfalls bei den letzten Versionen), das ist keine Frage von
Meinungen.
Vielleicht kann jemand aus der ALTERA-Ecke uns mitteilen, wie es damit
bei Quartus ausschaut.
Da sich die Abfänger ja wahrscheinlich das letzte WebPack holen, sind
diese Initialisierungenn in jedem Fall empfehlenswert.
Und einen Abfänger wird man ja wohl hoffentlich nicht an ein ASIC
ranlassen.
Klaus
Bei Xilinx wird, soweit ich weiss und es auch nutze der
Initialisierungswert in der ucf-Datei angegeben z.B.:
NET "signalname" INIT='0'
Ich will nicht darauf herumreiten, aber vielleicht ist es sinnvoll, ein
bisschen den internen Aufbau von FPGAs und CPLDs zu erklären. Dann wird
auch klar, warum z.B. Punkt (1) bei FPGAs Pflicht ist und bei CPLDs
weitestgehend irrelevant. Die meisten Anfänger werden sich wohl eher ein
billiges CPLD-Board holen.
Welchen Punkt (1) meinst Du ?
(1) Flankenwechsel ('event, rising_edge, posedge) nur bei taktsignalen
verwenden.
Dies gilt für CPLD wie für FPGA's genauso.
Das Design eines CPLD sollte synchron sein, sonst ist das Timing nicht
verläßlich. Ein CPLD hat deshalb genauso dedizierte, intere
Taktleitungen wie ein FPGA.
Naja, ein Anfänger wird nicht gleich einen ASIC bauen, das ist richtig.
Aber vielleicht soll man einen ASIC-Entwurf machen und den Prototyp auf
einem FPGA testen, dann ist es besser sich gar nicht erst an
Initialisierungszuweisungen gewöhnt zu haben, außer man weiß genau was
man tut bzw. dass man nur für die spezielle Plattform entwickelt.
>>So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen>>(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der>>Resetleitung auch recht interessant:>Wir wollen mal die Kirche im Dorf lassen. Ein auf einen ein paar (1..10)>Picosekunden langen Puls reagieren wahrscheinlich nicht mal die>schnellsten FPGAs. Bei 100ps würde ich mal frühestens was vermuten.
Egal ob es jetzt 1, 10, oder 100ps braucht, dass intern ein FF das
Zittern anfängt, dass sind Fehler die erstens: Sehr schwer zu finden
sind und zweitens: Zu verhindern sind, indem ein synchroner reset
eingesetzt wird. Mir fällt keine Situation ein, wo mir ein asynchroner
reset schon mal Vorteile gebracht hätte.
@ChrisV
>Egal ob es jetzt 1, 10, oder 100ps braucht, dass intern ein FF das>Zittern anfängt, dass sind Fehler die erstens: Sehr schwer zu finden>sind und zweitens: Zu verhindern sind, indem ein synchroner reset
Schon klar, das steht ausser Frage. Ich wollte lediglich der
aufkeimenden Hysterie etwas entgegen setzten, dass jeder physikalisch
noch so kleine Puls die FlipFlops aus dem Takt bringt.
MFG
Falk
@Falk: auf die Gefahr hin, dass ich mich wiederhole:
>signal flag1 : STD_LOGIC := '1';>signal flag0 : STD_LOGIC := '0';>signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";>signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";>>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.>Das passt dann auch für die Simulation.
Probiers einfach mal aus (wie gesagt mit Xilinx):
Gleich nach dem Laden des FPGAs ist flag1 = 1, flag0 = 0, count1 = 1100
und count2 = 1234abcd.
Genauso wie in der Simulation.
Wenn ich NICHTS angebe, ist die Initialisierung der Hardware implizit =
0 (null, low) und in der Simulation = U (undefined), und das gibt dann
ohne so einen expliziten Reset unschöne Effekte. Weil eben U verknüpft
mit irgendwas anderem (1,0,H,L,Z...) immer noch U gibt.
Und jetzt meine Ansicht: wenn ich der Hardware Startwerte im Sourcecode
vorgeben kann, die dann ja einfach von der Toolchain in den Bitstrom
eingesetzt und bei jedem FPGA-Start neu aus dem Config-ROM geladen
werden, dann brauche ich für solche Startwerte keinen Reset.
>Das üben wir nochmal
Ich für meinen Teil habe das ausgiebig geübt.
Aber bitte, wenn nötig üben wir beide das nochmal.
@Lothar
@Falk: auf die Gefahr hin, dass ich mich wiederhole:
>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.>Das passt dann auch für die Simulation.>Probiers einfach mal aus (wie gesagt mit Xilinx):>Gleich nach dem Laden des FPGAs ist flag1 = 1, flag0 = 0, count1 = 1100>und count2 = 1234abcd.>Genauso wie in der Simulation.
Huch, was ist das denn?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity test is
Port ( flag1_o : out STD_LOGIC;
flag0_o : out STD_LOGIC;
count1_o : out STD_LOGIC_VECTOR (3 downto 0);
count2_o : out STD_LOGIC_VECTOR (31 downto 0);
clk: in std_logic
);
end test;
architecture Behavioral of test is
signal flag1 : STD_LOGIC := '1';
signal flag0 : STD_LOGIC := '0';
signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";
begin
flag1_o <= flag1;
flag0_o <= flag0;
count1_o <= count1;
count2_o <= count2;
end Behavioral;
Erst sagt mir der Depp von XST das
Compiling vhdl file C:/Data/work/VHDL/ram_emu/test.vhd in Library work.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 16.
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 17.
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 18.
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 19.
Default values are ignored in synthesis.
Entity <test> (Architecture <behavioral>) compiled.
und dann das???
Synthesizing Unit <test>.
Related source file is C:/Data/work/VHDL/ram_emu/test.vhd.
WARNING:Xst:653 - Signal <flag1> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <flag0> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count1<3>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count1<2>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count1<1>> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count1<0>> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count2<31>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<30>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<29>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<28>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<27>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<26>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<25>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<24>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<23>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<22>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<21>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<20>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<19>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<18>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<17>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<16>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<15>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<14>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<13>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<12>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<11>> is used but never assigned. Tied
to value 1.
WARNING:Xst:653 - Signal <count2<10>> is used but never assigned. Tied
to value 0.
WARNING:Xst:653 - Signal <count2<9>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<8>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<7>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<6>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<5>> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count2<4>> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count2<3>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<2>> is used but never assigned. Tied to
value 1.
WARNING:Xst:653 - Signal <count2<1>> is used but never assigned. Tied to
value 0.
WARNING:Xst:653 - Signal <count2<0>> is used but never assigned. Tied to
value 1.
Unit <test> synthesized.
>Und jetzt meine Ansicht: wenn ich der Hardware Startwerte im Sourcecode>vorgeben kann, die dann ja einfach von der Toolchain in den Bitstrom>eingesetzt und bei jedem FPGA-Start neu aus dem Config-ROM geladen>werden, dann brauche ich für solche Startwerte keinen Reset.
Richtig, aber in den Mauals von Xilinx stand immer EXPLIZIT drin, dass
die Initialisierung NICHT für die Synthese verwendet wird (so wie auch
die erste Ausschrift von XST). So waren z.B. bei Simulationsmodellen von
BRAMs immer die Initialisierungswerte UND Attribute gesetzt, einmal für
die Simulation und einmal für die Synthese. Aber dann verwendet XST sie
DOCH???
Muss ich das versetehen?
>>Das üben wir nochmal>Aber bitte, wenn nötig üben wir beide das nochmal.
Was ich hiermit getan habe. Versteh ich dennoch nicht so ganz. Die XST
Entwickler wissen wohl auch nichst so recht was sie wollen?
Aber halt! Das war jetzt nur ein gaaanz einfacher Test. Was ist mit
"echten" Signalen?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity test is
Port ( flag1_o : out STD_LOGIC;
flag0_o : out STD_LOGIC;
count1_o : out STD_LOGIC_VECTOR (3 downto 0);
count2_o : out STD_LOGIC_VECTOR (31 downto 0);
clk: in std_logic
);
end test;
architecture Behavioral of test is
signal flag1 : STD_LOGIC := '1';
signal flag0 : STD_LOGIC := '0';
signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";
begin
process(clk)
begin
if rising_edge(clk) then
flag1 <= not flag1;
flag0 <= not flag0;
count1 <= count1 +1;
count2 <= count2 +5;
end if;
end process;
flag1_o <= flag1;
flag0_o <= flag0;
count1_o <= count1;
count2_o <= count2;
end Behavioral;
Ich bekomme die gleiche Ausschrift wie oben "Default values are ignored
in synthesis.". ABer keine Ausschrift über die Zuweisung von
Defaultwerten. Leider kann mir das Design nicht im FPGA-Editor
anschauen, ich hab hier im Moment nur Webpack 4.2. Der Fall bleibt also
vorerst offen.
MFG
Falk
@Falk
Soviel ich weiß und auch weiter oben beschrieben habe, wird der
Startwert in der ucf-Datei festgelegt. Da sich im ersten Fall die
Signalwerte nicht ändern können, werden nach der Optimierung die
Ausgangsstufen fest auf '0' oder '1' gelegt und eigentlich gar keine
Logik erzeugt. Im zweiten Fall können sich die Ausgangssignale ändern
und werden somit nicht mit '0' oder '1' verbunden.
Jörg
@Falk: Ich hatte vergessen zu sagen, dass diese Defaultwert-Zuweisung
meines Wissens erst ab WebPack Version 7 funktioniert. Jedenfalls ohne
Fehlermeldungen.
Gruß
Lothar
@Joerg Wolfram
>Soviel ich weiß und auch weiter oben beschrieben habe, wird der>Startwert in der ucf-Datei festgelegt. Da sich im ersten Fall die
Dieses Verfahren kenn ich auch. Ist aber unschön, weil es leicht zu
Inkonsistenzen kommt.
@Lothar
>@Falk: Ich hatte vergessen zu sagen, dass diese Defaultwert-Zuweisung>meines Wissens erst ab WebPack Version 7 funktioniert. Jedenfalls ohne>Fehlermeldungen.
Ahhhja, das erklärt einiges. Ich hab immer nur bis ISE 6.3 verwendet.
MfG
Falk
Hier ist meine Erfahrung:
Wenn man z.B. zwei Werte (a 128 bit) arithmetisch behandeln möchte.
variable als natural -> sehr langsam ~ 20 MHz
variable als std_logic_vector schneller ~ 110 MHz
signale (arch intern) -> am schnellsten ~ 310 MHz
Von shematic's her sehen die erstellten vhdl files auch besser aus, als
wenn man mit variablen arbeitet.