Hallo,
ich benötige noch einmal eure Unterstützung, bin nämlich immer noch
ziemlich erschlagen.
Ich habe vor einigen Wochen als ich mit vhdl begonnen habe,
std_logic_unsiged verwendet und da hatten std_logic vektoren für Zähler
wie unten funktioniert.
da ich vernommen habe, daß obige packages empfehlenswerter sind, habe
ich mir vorgenommen, diese auch zu verwenden aber sie treiben mich in
den Wahnsinn, denn intuitiv komme ich nie ans Ziel.
2 fragen: wo ist bei folgendem mein Denkfehler und wo finde ich eine
Übersicht, was ich wie wohin konvertieren kann/muss und wie ich
vektoren, integers verwalte.
Schlagt mich nicht, wenn das über die Maßen idiotisch und banal ist.
Ach ja: mit nibble passiert noch gar nichts weiter. Soll später
-logisch- ein Nibble zur Anzeige bringen ich habe aber zuerst nur ein
Signal was rund zählen soll gemacht. Aus Respekt vor den Fehlern.
Nimm integer:
>> signal nibble : integer range 0 to 3 := 0;
Und dann kannst du hin und her konvertieren und casten:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std>> process (clk, clk_enable) begin
Hierreicht clk in der Sensitivliste aus, denn der Prozess muß nur dann
neu berehnet werden, wenn clk sich ändert.
EDIT:
Hat ein Nibble bei dir 4 Bits?
Dann müsste das ein
integer range 0 to 15 := 0;
sein. Alternativ z.B. ein
unsigned(3 downto 0) := "0000";
schäm nach einiger Zeit auf dem Balkon ist mir der ":"<->";" Ärger
doch selber aufgefallen. ich habe ungelogen über eine Stunde darüber
gebrütet... :-(
Nichtsdestotrotz bleibt die Frage: was macht man denn nun mit integers,
unigneds und std_logic_vecrtors und wann castet man wohin?
Werde zusehen den thread nicht weiter mit Folgeposts zu verseuchen - da
wäre mal anmelden sinnvoll, daß editieren möglich ist. Entschuldigung.
danke.
Noch eine konkrete Frage:
angenommen ich habe so einen
1
digit_sel:integerrange0to3
Sowie ein
1
digit:std_logic_vector(3downto0);
Damit soll aus einem 8 Bit Zähler
1
counter:naturalrange0to2**16-1
immer ein Nibble (ja dachte das wären quasi genormt 4 bit)
ausgeschnitten und angezeigt werden. Dabei dachte ich an so etwas wie
unten außerhalb eines prozesses, der das Signal "nibble" anzeigt. Stelle
würde auch noch ausgewählt es geht mir gerade um das auswählen, welches
nicht recht klappen will.
counter müsste dort wohl in std_logic_vector gecastet werden? Eben das
verwirrt mich. Würde man noch ein Signal für den gecasteten
interger/unsigned vorsehen? ist die Denke überhaupt richtig und kann man
davon ausgehen, daß die Schreibweise und verwendung von zig Signalen
bzw. aufteilung in Prozesse und außerprozess Abarbeitung keinen Einfluss
auf Größe/Geschwindigkeit hat? Es kommen ja auch größere Projekte...
Lesbar wird das glaube ich nicht.
Aber zunächst wäre ich glücklich über Erleuchtung bei dem simplen
Beispiel.
Du musst dich immer fragen auf welchem Level du denken willst.
Bsp : ich nutze für Zähler grundsätzlich unsigned und zwar aus dem
Grund, das ich mir damit genau das in der Hardware vorstelle was ich
auch beschreibe : einen Zähler mit exakt so viel Bits wie in der
Definition angegeben der bei 111...1 überläuft.
Natural hingegen baut je nach Range gleich noch Logik zum Reset auf 0 an
einer bestimmten Position(maximum) ein.
Dementsprechend kann es auch nicht direkt ausgegeben werden, z.b. auf
Pins, denn die Logik die dahinter steckt ist nicht mehr exakt definiert.
(in der Folge natürlich schon, deswegen kann man es ja auch
konvertieren, aber im ersten Moment für die Sprache VHDL an sich nicht)
Bei unsigned ist das kein Problem, da es genau das gleiche Format wie
std_logic_vector hat, demzufolge ist keine Konvertierung nötig sondern
lediglich eine Umbenennung des Typs.
bsp :
signal x : unsigned(15 downto 0);
y <= std_logic_vector(x(3 downto 0));
Merke : kein "to_std_logic_vector"
Bei naturals oder integer kommt eben eine Umwandlung vor, hauptsächlich
um zu klären wie breit denn die zu erzeugende Zahl überhaupt ist.
Wie das funktioniert kannst du den zugrunde liegenden Packages(also jene
die du einbindest) entnehmen.
Deine With-select Anweisung ist somit schon ok, aber ein simples 3
downto 0 ist wohl eher etwas für eine unsigned als für eine natural.
Und ob du mit integer oder auch mit unsigned selecten willst bleibt dir
überlassen.
Anzumerken sei jedoch das dies durchaus einen Unterschied machen kann.
Bsp : mit unsigned kannst du problemlos ein Bit alleine zum selecten
nutzen.
digit <= counter(3 downto 0) when digit_sel(0)='1' else...
Was in der Hardware deutlich schneller ist als eine Überprüfung auf die
volle Range von digit_sel.
Das macht zwar bei einer 2 Bit breiten zahl keinen großen Unterschied,
bei breiten select Anweisungen hingegen schon.
Natürlich kann man sich auch auf den Synthesizer verlassen, was aber
nicht immer klappt (etwa wenn das select von außen kommt).
Du siehst also : da gibts Unmengen von Möglichkeiten. Deine Aufgabe ist
es nun das für dich heraus zu ziehen von dem du meinst es nutzen zu
wollen.
Für den Anfang hilft es z.b. schon mal jede Variante aufzuschreiben, zu
simulieren und zu synthetisieren und sich die Unterschiede im RTL-Viewer
sowie in der Hardwareauslastung anzusehen.
Was man dabei lernt kann einem niemand mal eben aufschreiben.
natural ist ein eingeschränkter integer Tap. Wenn du den natural sowieso
weiter einschränkst, dann nimm doch einfach gleich den Basistyp:
1
counter:integerrange0to2**16-1
EDIT:
Iulius schrieb:
> Bsp : ich nutze für Zähler grundsätzlich unsigned
Ich verwende für Zähler nur eingeschränkte integer, und weiß implizit,
dass die als eine bestimmte Anzahl FF realisiert werden. Dann sehe ich
auch in der simulation gleich, wenn der Zähler mal Werte annimmt, für
die er eigentlich nicht ausgelegt ist.
> Natural hingegen baut je nach Range gleich noch Logik zum Reset auf 0 an> einer bestimmten Position(maximum) ein.
Das stimmt nicht.
1
signalcnt:integerrange0to511:=0;
2
:
3
processbegin
4
waituntilrising_edge(clk);
5
if(cnt<511)thencnt<=cnt+1;
6
elsecnt<=0;
7
endif;
8
endprocess;
Dieser integer-Zähler wird trotz der explizit beschriebenen
Rücksetzbedingung exakt gleich implementiert wie der Verktor-Zähler mit
seiner impliziten Rücksetzung:
1
signalcnt:unsigned(8downto0):=(others=>'0');
2
:
3
processbegin
4
waituntilrising_edge(clk);
5
cnt<=cnt+1;
6
endprocess;
Für die Hacker unter uns, die ohne Simulation auskommen:
auch das hier wird genau gleich in Hardware abgebildet
1
signalcnt:integerrange0to511:=0;
2
:
3
processbegin
4
waituntilrising_edge(clk);
5
cnt<=cnt+1;
6
endprocess;
Von unschlagbarem Vorteil ist der /integer/-Zähler, wenn Vergleiche mit
dem Zählerwert gemacht werden:
1
signalcnt:integerrange0to511:=0;
2
:
3
if(cnt=234)then
4
:
Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:
>> Dieser integer-Zähler wird trotz der explizit beschriebenen>> Rücksetzbedingung exakt gleich implementiert...
Ist ja auch kein Wunder bei der Range, was soll er da auch sonst tun ?
Versuch das mal mit einer Range die nicht direkt an einer Bitgrenze
endet.
Zumal ich keinen Vorteil sehe in einer Integer die ich mit 0 bis 511
einsetze anstatt einer 8 bis 0 unsigned.
>> Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:
wüsste nicht warum.
1
signalcnt:unsigned(8downto0):=(others=>'0');
2
...
3
ifcnt=234then
funktioniert wunderbar mit dem IEEE.NUMERIC_STD
Wie gesagt, dazu wirds 10 verschiedene Meinungen geben. Letztendlich
muss jeder für sich entscheiden wie er arbeiten will.
Iulius schrieb:
> Ist ja auch kein Wunder bei der Range, was soll er da auch sonst tun ?> Versuch das mal mit einer Range die nicht direkt an einer Bitgrenze> endet.
Genau dann erkenne ich in der Simulation, wenn der Zähler aus dem
definierten Bereich hinausläuft.
Bei einem 640x480 Display sind z.B. die Werte 479 und 639 interessant.
Klar, dass auch ein integer range 0 to 479 in der Implementierung 9
Bits braucht. Aber wenn der Index tatsächlich mal 480 wird, sagt mir das
die Simulation. Bei einem unsigned (8 downto 0) wird weitergezählt bis
nach 511 der implizite Überlauf kommt.
>>> Beim Vektor-Zähler ist hier eine umständliche Wandlung nötig:> wüsste nicht warum.> funktioniert wunderbar mit dem IEEE.NUMERIC_STD
Stimmt.
Vergleiche funktionieren, aber die simple Zuweisung eines Dezimalwerts
braucht dann diese Umwandlung. Und das:
1
idx<=to_unsigned(479,idx'length);
ist allemal besser lesbar als:
1
idx<="111011111";-- 479, falls der Kommentar noch stimmt
>> Genau dann erkenne ich in der Simulation, wenn der Zähler aus dem>> definierten Bereich hinausläuft
Durch die Range Angabe beschwöre ich ja gerade den Fall heraus.
"Ach ich geb ja die Range an und damit ist der Counter fertig"
Verwende ich immer und konsistent unsigned, dann bin ich es gewöhnt das
alles selbst zu bearbeiten und mir entgeht das idr nicht (ist zumindest
noch nie passiert)
>> aber die simple Zuweisung eines Dezimalwerts braucht dann diese Umwandlung
Hier stimme ich dir zu, wer gerne Dezimalzahlen direkt zuweist, den kann
das durchaus stören.
Da ich ohnehin in der Hardware nicht in Dezimal rechne nutze ich meist
x"hex" oder eben direkt binär bei kleinen Zählern.
Da ist eben die Abwägung : wandle ich lieber hier um oder an einer
anderen Stelle ?
Wobei man sich fragen muss ob man bei rein Dezimaler/integer Denkweise
überhaupt noch sinnvoll einzelne Bitpositionen ausgewerten kann.
Wenn ich 479 zuweise kann ich zwar noch sagen das idx(0) = '1' und
idx(7)='1' (nach umwandlung wohlbemerkt), aber danach hörts langsam auf
und ich bräuchte einen Taschenrechner.
Deswegen meinte ich ja auch : Geschmackssache. Mir persönlich ist die
Integer Schreibweise jedenfalls zu weit von der tatsächlichen Hardware
weg und weil unsigned ohnehin nicht wirklich umständlicher ist nutze ich
lieber das.
Im Gegenteil, so wie ich arbeite bräuchte ich mit Integer wohl eher mehr
Umwandlungen.
Super. ich muss gestehen daß mir gar nicht recht bewusst war, daß
unsigned ein Vektor ist. Dadurch erklärt sich schon einiges.
ich habe versucht, daß gelernte bestmöglich umzusetzen. dazu musste das
Nibble auswählen doch in einen Prozess weichen.
Code ist unten angehängt - 4 Fragen ergeben sich mir aber.
1) ich begreife noch nicht, warum ich im prozess "choose_nibble" nicht
0,1,2,3 im switch verwenden kann statt der Vektorschreibweise "0000"....
ich hatte es so verstanden, daß ich eben bei unsigned auch numerische
Vergleiche und Zuweisungen machen darf.
2) Die Synthese spricht von 5.6 ns minumum period. irgendwelche timing
constraints habe ich nicht zusätzlich angegeben ( so weit bin ich noch
gar nicht vorgedrungen) Ist das das, was man erwarten könnte, oder habe
ich schon einen gemeinen Performance killer gemacht? Wer Zeit und Lust
zur Durchsicht hätte sei herzlich aufgefordert dazu zu posten.
3) Als c Programmierer habe ich mich auf meine Formatierung eingestellt.
ich habe versucht, das so zu machen, wie ich glaube, daß es in vhdl
gemacht werden sollte - ich finds dennoch über die Maßen
unübersichtlich. oder liegt daß nur an mangelnder Erfahrung?
4) unter Implement Design / Place & Route findet sich ein Rufzeichen.
Scheinbar eine Warnung, aber weder im Warnings Reiter noch sonstwo finde
ich sie erklärt. :-( Worum handelt es sich, wie brisant ist sie und wie
vermeidet man sie?
ich danke euch noch einmal recht herzlich!
zu 1 :
das klappt bei case nicht da du das "=" verwenden musst um unsigned
direkt mit einer integer zahl zu vergleichen.
Case und with/select bieten das nicht. Innerhalb eines process ist also
"if" nötig bzw außerhalb when/else.
Allerdings brauchst du den Mux ohnehin nicht in einem process samt clock
zu verstecken. Ich würde das so kompakt lösen.
1
seg_en<=x"E"whendigit_sel=1else
2
x"D"whendigit_sel=2else
3
x"B"whendigit_sel=3else
4
x"7";
Das Gleiche gilt übrigens auch für die Case-Anweisung bei dem
Hex-Lookup.
zu 2 :
5.6ns also 178mhz sind je nach Chip realistisch für das hier verwendete.
Die größte Durchlaufzeit hat dabei mit großer Sicherheit der
slow_clk-Zähler.
Für solche Counter kann man LFSR nutzen(siehe wikipedia), da der
absolute Zählerwert unwichtig ist und nur die Periodendauer zählt. Damit
lässt sich der Maximaltakt ggf noch etwas anheben.
Allerdings wollen wirs für den Anfang mal nicht übertreiben, du kannst
das problemlos so lassen.
Übrigens aber mal wieder ein Punkt wo integer versagt ;)
zu 3:
Das ist schon so ok. Wenn du mehr übersicht willst dann musst du
hierarchischer arbeiten, etwa das hex lookup noch als component
einbinden.
Ansonsten hilft ein guter Quelltext-Editor welcher das Ein-/Ausklappen
von einzelnen Codeabschnitten unterstützt.
zu 4 :
ohne zu wissen was es ist kann man das nicht sagen. Manche Warnings sind
eigentlich gar keine, sondern nur Infos, manche sind essentiell und
weisen auf gravierende Fehler hin.
Leider werden im Laufe des Projekts die Warnings immer weiter zunehmen,
sodass du am Ende gar nicht mehr die Zeit und Muße haben wirst alle
durchzusehen.
Besonders wenn man generisch arbeitet und etwa dudurch einzelne
Bitpositionen wegoptimiert werden können häufen sich die Meldungen sehr
schnell.
Wenn etwas nicht wie erwartet funktioniert lohnt sich ein Blick allemal,
ansonsten reicht es wohl gelegentlich mal drauf zu schauen. Für den
Anfang aber lieber einmal zu oft, denn manchmal finden sich auch
typische Anfängerfehler (z.b. gated clock) die so schnell aus der Welt
geschafft werden können.
> ich habe versucht, daß gelernte bestmöglich umzusetzen.
Das ist gar nicht mal so schlecht gelungen.
Andere brauchen da mehr Iterationen ;-)
> daß ich eben bei unsigned auch numerische Vergleiche und Zuweisungen> machen darf.
Deshalb verwende ich integer für die Zähler und Indices ;-)
BTW:
Du könntest auch schreiben:
1
casedigitis
2
whento_unsigned(1,4)=>segments<="1111001";
3
whento_unsigned(2,4)=>segments<="0100100";
4
whento_unsigned(3,4)=>segments<="0110000";
5
:
Ob das allerdings Leserlicher ist... :-/
Besser wäre dann eher die Hex-Schreibweise:
oh, oh, oh.
Vielleicht habe ich die Korken verfrüht knallen lassen. Nachdem die
Hexadezimale Anzeige mich natürlich nicht zufrieden stellen konnte, habe
ich nach einer bin-bcd Umwandlung gesucht und bin auf den "shift add 3"
Algorithmus gestoßen.
Wäre ich zwar niemals selber drauf gekommen, aber leuchtet mir ein. Eine
Umsetzung habe ich bei obigem Programm natürlich probiert - einige
std_logic_vector - unsigned Ersetzungen, geschüttelt, sythetisiert....
fehlerhaft.
Ich hänge, trotz der riesen Menge, den Code mal an, denn sonst kann man
mir ja nicht helfen.
Meine Fragen.
1) tja warum zeigen sich eigentlich nicht die erwünschten zahlen von
0..255?
2) Ich hatte große Hoffnung in die Änderung gesteckt, die das
einbeziehen des clk in das Modul bin2bcd umfasste. urplötzlich erinnerte
ich mich an das Mantra bzgl alles takten...
3) Vielleicht der richtige Moment, mit der systematischen fehlersuche
bzw. Simulation zu beginnen. Wie wo was macht man da? Wonach suchen?
4) Im bin2bcd modul habe ich nun unsigned Vektoren verwendet. verstehe
ich die Zusammenhänge richtig, daß für das Top Modul nur std_logic
zugelassen ist, weil physikalisch vorhanden, oder ist selbst da unsigned
zulässig?
Vielleicht sieht jemand den fehler und kann mir die Systematik näher
bringen
> habe ich nach einer bin-bcd Umwandlung gesucht und bin auf den> "shift add 3" Algorithmus gestoßen.
Woher hast du die Idee?
Ist das dein eigener VHDL-Quellcode?
> architecture behave of BIN2BCD is
Du weißt schon, was eine for-Schleife in VHDL macht?
Damit wird einfach nur Hardware mehrfach erzeugt...
Wolltest du das?
Ich mach das immer so:
http://www.lothar-miller.de/s9y/categories/44-BCD-Umwandlung
Auch da ist die gleiche Idee dahinter: wenn Übertrag, dann +3
Die Idee über for Schleife ist natürlich nicht von mir. Mit einer
Umsetzung von Null an würde ich mich auch selber noch zu sehr unter
Druck setzen. habe ich umgewandelt. z.B. unter Benutzung der unsigned
Vektoren.
Die Verwendung der For Schleife verstehe ich so, daß diese quasi
entflochten wird und somit für kleine Tiefen einen Vorteil gegenüber
einer Statemaschine wie bei dir hat, die ja immer mehrere Taktzyklen
dauern muss. Ich werde mir beide Lösungen mal genauer anschauen und
darüber nachdenken.
Für die Umwandlung von Zahlen, die sich alle zig Takte ändern wäre ja
eine Routine, die paar Takte dauert irrelevant. Wenn ich mit den bcd
Werten eines schnellen Datenstroms etwas machen müsste, würde bei
deiner Lösung dessen Rate durch die notwendigen Takte pro Umwandlung
bestimmt?
Vermutlich denke ich einfach noch zu kompliziert bzw. will zu viel auf
einmal beachten.
Würdest du denn sagen bei mir wird Murks angezeigt (also unsinnige bcd
Zahlen incl. As..Fs) wegen eines Fehlers in der Routine oder ist das
Problem eher in der Verschaltung der bin2bcd im count zu suchen.
Ich versuche bewusst components und auch Prozesse die keine sein müssten
s.o. zu verwenden, um ein Gefühl dafür zu bekommen.
Aufteilung auf Sourcen und anlegen eines component pools kann ja später
erfolgen.
Erst mal sollte ds Programm funktionieren finde ich :-(
> Würdest du denn sagen bei mir wird Murks angezeigt (also unsinnige bcd> Zahlen incl. As..Fs) wegen eines Fehlers in der Routine oder ist das> Problem eher in der Verschaltung der bin2bcd im count zu suchen.>> Vielleicht der richtige Moment, mit der systematischen fehlersuche>> bzw. Simulation zu beginnen.
Es ist nie zu spät, aber ich hätte schon früher damit angefangen... ;-)
> Wie wo was macht man da? Wonach suchen?
Am einfachsten testest du jedes einzelne deiner Untermodule, und wenn du
Lust und Zeit hast, das Top-Modul zusammen mit den Untermodulen auch
noch...
Das gibt mir zwar jetzt keinen wirklich konkreten Anhaltspunkt wie und
wo ich den Hebel ansetze :-(, aber ich werd in den nächsten Tagen noch
mal darüber brüten und ggf. konkreter fragen.
Informationen über Projektplanung und Testbenches sind rar gesäht.
Deinen Buchtip habe ich allerdings bestellt.
Was mich jetzt aber mehr und mehr interessiert sind Vor- und Nachteile
der For Schleife.