Hallo zusammen.
Meine Kentnisse im Bereich VHDL sind leider ein wenig eingeroste. Ich
habe ein Signal, welches auf 1 Bit quantisiert ist. Ich möchte nun ein
FIR-Filter (hier Moving Average Filter) mit 4 Koeffizienten
implementieren. Beim Versuch die einzelnen Bits zusammenzuzählen weiss
ich jedoch nicht weiter (also die 4. unterste Zeile). Ich habe schon
verschiedenste Castin-Methoden probiert, jedoch ohne erfolg. Kann mir
jemand sagen, wie ich diese 4 Bits zusammenzählen kann?
Dieter schrieb:> Ist der Reset so richtig beschrieben?
Wozu überhaupt ein Reset? ;-)
Seis drum...
R. K. schrieb:> Kann mir jemand sagen, wie ich diese 4 Bits zusammenzählen kann?
Der erste logische Schritt wäre der, das eine Bit zu einem Vektor zu
erweitern, dann diesen Vektor für die Addition zum unsigned zu casten:
Expression in type conversion to unsigned has 4 possible definitions
2
in this scope, for example, SIGNED and UNSIGNED.
Das bedeutet, das die Cast-Funktion nicht weiß, welchen Datentypen sie
da konvertieren soll, denn "00" kann ja ein bit_vector, ein
std_logic_vector, ein signed oder ein unsigned sein.
Abhilfe schafft, hier nicht einen Cast sondern einen Qualifier zu
verwenden, der der Addition sagt, dass die Vektoren als unsigned
Operanden verwendet werden sollen:
Ich würde mal die aynchronen resets weglassen oder in synchrone wandeln
wenn das casten nicht geht, dann einfach einzeln wandeln, der Compiler
macht das dann schon
if (bit_x = '1') then
value_x <= "00100"; die 4 steht hier für 1.0
else
value_x <= "00000";
end if
das mit x für alle bits = 4x
dann addieren:
sum <= std_logic (unsigned (value_1) + + + );
sum ist dann maximal "10000" = 4x 1.00 = 4.00
mittel = sum (5 downto 3);
die vektoren sind in der grösse so gewählt, dass kein überlauf entsteht
und beim summieren die längen passen, ferner gibt es keinen underflow
oder rundungsfehler
Ich hatte mal eine ähnliche Anwendung (gesetzte Bits in einem 16Bit-Wort
zählen). Hab es mit einer Schleife gelöst.
Ob das elegant ist oder nicht, mag ich nicht beurteilen, aber jedenfalls
funktioniert es:
1
signalsBitsInWords:std_logic_vector(4downto0);
2
3
process(CLK)
4
variablevBitsInWord:std_logic_vector(4downto0);
5
begin
6
if(rising_edge(CLK))then
7
vBitsInWord:="00000";
8
forcin0to15loop
9
if(WORDIN(c)='1')then
10
vBitsInWord:=vBitsInWord+1;
11
endif;
12
endloop;
13
sBitsInWords<=vBitsInWord;
14
endif;
15
endprocess;
Wird innerhalb eines Taktzyklus' ausgeführt und die Synthese generiert
daraus meines Wissens 16 Addierer.
R. K. schrieb:> FIR_comb: process (ClkxCI, RstxRBI)
Der Prozess hat seinen Namen nicht verdient, weil er nicht
kombinatorisch ist...
Ich hätte da noch einen:
1
FIR_comb:process(DataBufxD)
2
variablecnt:integerrange0to4;
3
begin
4
cnt:=0;
5
foriin0to3loop
6
ifDataBufxD(i)='1'then
7
cnt:=cnt+1;
8
endif;
9
endloop;
10
ReadyxSO<=std_logic_vector(to_unsigned(cnt,3));
11
endprocessFIR_comb;
Ergebnis:
Macro Statistics
# Adders/Subtractors : 3
3-bit adder : 3
EDIT: Hoppala, zu spät.
Aber wenigstens ist meine Lösung richtiger (4 Bits statt 16)... ;-)
Und ausserdem wird die vorgeschlagene Addition eines integers auf einen
std_logic_vector mit der numeric_std nicht funktionieren:
vBitsInWord := vBitsInWord + 1;
Super danke.
Mir gefällt die Lösung von Lothar Miller am besten, da ich die
for-schleifen in einem VHDL-Code irgendwie "unpassend" finde. (so lange
man diese vermeiden kann).
Oder ist das sowiso egal und man hofft dass der Compiler was schlaues
daraus macht?
R. K. schrieb:> Oder ist das sowiso egal und man hofft dass der Compiler was schlaues> daraus macht?
Nein, Hoffen hilft da nicht. Das hier ist z.B. am schnellsten und
ressourcensparendsten:
Die for-Schleife wird ja nicht sequentiell umgesetzt, sondern parallel.
Kommt es da nicht im Bsp von Lothar mit zu einem "kombinatorischem"
counter?
Ich meine zB so dass wenn DataBufxD(0) '1' ist der counter hochzählt.
Wenn DataBufx(1) '1', etc. dann auch. Sprich sobald eines der Bits '1'
ist, wird wild herum gecountet?
Matthias schrieb:> der counter hochzählt.
Da zählt kein Counter!
Dieser Counter ist nur eine Hilfestellung für den Synthesizer. Damit
weiß der Synthesizer, wei viele Addierer er verwenden muss. Der Counter
taucht in der Realität nirgends auf...
Lothar Miller schrieb:> Aber wenigstens ist meine Lösung richtiger (4 Bits statt 16)... ;-)
Selbstverständlich.
> Und ausserdem wird die vorgeschlagene Addition eines integers auf einen> std_logic_vector mit der numeric_std nicht funktionieren:> vBitsInWord := vBitsInWord + 1;
Doch, funktioniert, nachweislich! Ich hab mich auch gewundert...
Stimmt. Lookup-Tabellen waren schon im Studium immer die schnellsten
Varianten um so was zu wandeln. Jedoch hatte ich dies
verdrängt/vergessen.
Um das Hoffen ein bisschen zu "vebessern" gehe ich meistens so vor:
1)Überlegen was ich will
2) Code schreiben
3) Im RTL schauen was der Compiler gemacht hat
Bronco schrieb:>> Und ausserdem wird die vorgeschlagene Addition eines integers auf einen>> std_logic_vector mit der numeric_std nicht funktionieren:>> vBitsInWord := vBitsInWord + 1;> Doch, funktioniert, nachweislich! Ich hab mich auch gewundert...
Kann nicht sein. Und wie erwartet:
1
ERROR:HDLParsers:808 - "C:/..../sob.vhd" Line 39. + can not have such operands in this context.
R. K. schrieb:> Mir gefällt die Lösung von Lothar Miller am besten, da ich die> for-schleifen in einem VHDL-Code irgendwie "unpassend" finde. (so lange> man diese vermeiden kann).
Sag doch sowas nicht!
"For" hat auch in VHDL seine Darseinberechtigung, um parallele Logik zu
erzeugen.
Stell Dir mal vor, Dein Filter hätte 1024 Taps.
Willst Du 1024 einzelne Zeilen schreiben und das ganze nachher noch
warten können?
Lothar Miller schrieb:>>> Und ausserdem wird die vorgeschlagene Addition eines integers auf einen>>> std_logic_vector mit der numeric_std nicht funktionieren:>>> vBitsInWord := vBitsInWord + 1;>> Doch, funktioniert, nachweislich! Ich hab mich auch gewundert...> Kann nicht sein. Und wie erwartet:
Auch auf die Gefahr hin, jetzt geteert und gefedert zu werden.
In der entsprechenden Datei benutzen wir natürlich noch:
1
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
useIEEE.STD_LOGIC_ARITH.ALL;
4
useIEEE.STD_LOGIC_UNSIGNED.ALL;
(Auf die historischen Gründe will ich hier gar nicht eingehen...)
Das mit der parallelen Logik ist wirklich ein gutes Argument. (Ich werde
dies später sicher noch brauche, wenn ich die Dezimation etc.
implementiere)
Wenn ich mir mein Programm so genau anschaue, dann würde ich die
1-Bit-Quantisierung gerne mal ein wenig aufweichen. Meine Signal ist
somit nicht mehr 1-Bit, sondern 4 Bit breit. Kann ich in meinem Programm
die Vektoren durch Arrays ersetzen?
Ich war wohl ein wenig voreilig. Eine möglich Lösung lautet prinzipiell
wie folgt: (der Ausgang mit einer Breite von 3 Bits macht jedoch altell
noch keinen Sinn)
Ich würde zur Sicherheit vor die for-Schleife noch ein
tmp := 0;
einfügen. Denn sonst könnte die Variable blitzschnell zur
kombinatorischen Schleife ausarten:
1
Xst:2170 - Unit preamble_correlator : the following signal(s) form a combinatorial loop: tmp
Zum Hintergrund:
http://www.lothar-miller.de/s9y/categories/36-Kombinatorische-Schleife
Das Schlimme daran:
das wirst du bei einer Simulation nicht feststellen, weil die Änderdung
von tmp die Neuberechnung des Prozesses anstossen sollte, das aber nicht
kann, weil Variablen nicht in die Sensitivliste genommen werden können.
Siehe dazu den recht lesenswerten
Beitrag "Variable vs Signal"
Mit dem Fazit: Keine Variablen für Anfänger. ;-)
Danke. Das mit dem tmp := 0; sehe ich aus deinem Argument ein.
Wenn ich jedoch mein RTL anschaue, bin ich mir eigentlich ziemlich
sicher, dass ich nach einem Reset einen definierten Zustand von Null
haben sollte. Oder liege ich hier falsch?
R. K. schrieb:> dass ich nach einem Reset einen definierten Zustand von Null> haben sollte. Oder liege ich hier falsch?
Für die Simulation: nach den Reset hat ein integer den maximal negativen
Wert (integer'left).
Für die Hardware: schnurzegal. Denn nach dem Loop-Unrolling hast du
einfach nur 63 Addierer (mit einer entsprechend langen und langsamen
Carry-Chain!!!).
Ich würde da eine "Buchführung" empfehlen: wenn du eine '1'
hereinbekommst, dann zählst du einen Zähler eins hoch. Wenn du eine '1'
hinausgibst, dann zählst du den Zähler runter. Wenn Eingang=Ausgang,
dann tust du nichts. Ergebnis: nur zwei kleine Addierer = schnelles
Design.
Das mit der langen und langsamen Logik ist mir klar. Für den gegebenen
Fall mit dem Moving Average gebe ich dir natürlich recht, da hilft die
Buchführung.
Ich werde später jedoch eine Korrelation bestimmen müssen. Das ganze
führt dann auf eine FIR -Struktur, welch dank dem rein logischen
Referenzsignal (also 1er und -1er) immerhin einfach implementierbar ist.
Jedoch bleibt meine grosse Logik.