Hallo zusammen!
Ich arbeite gerade ein wenig mit VHDL (bin totaler Anfänger) und benutze
dazu das Xilinx ISE Webpack. Jetzt habe ich mir gedacht, ich könnte mal
als kleine Übung einen 2-Bit-Volladdierer bauen und ihn entsprechend in
Komponenten zerlegen, um die component-Funktion zu testen:
Also ein 2-Bit-Volladdierer bestehend aus zwei 1-Bit-Volladdierern, die
wiederum jeweils aus zwei 1-Bit-Halbaddierern und einem OR-Gatter
aufgebaut sind. Allerdings kommt bei der Simulation nur Blödsinn heraus.
Hier mal der Code des 2-Bit-Volladierers:
Ich denke es ist recht selbsterklärend, A und B sind die Eingangszahlen
(jeweils 2 Bit), S die Ausgangszahl. Das interne Signal W_CARRY wird
benutzt, um den Carry-Ausgang des einen Volladdierers mit dem
Carry-Eingang des anderen zu verbinden.
Soweit ich das mit dem component verstanden habe, lege ich jetzt eine
neue VHDL-Datei namens "FULLADDER" an und schreibe dort entsprechend das
Verhalten eines 1-Bit-Volladdierers rein:
1
entityFULLADDERis
2
port(A,B,C_IN:instd_logic;
3
C_OUT,S:outstd_logic);
4
endFULLADDER;
5
6
architectureFULLADDER_IDEALofFULLADDERis
7
componentHALFADDER
8
port(X0,Y0:instd_logic;
9
CARRY0,SUM0:outstd_logic);
10
endcomponent;
11
12
signalW_CARRY0,W_CARRY1,W_SUM:std_logic;
13
14
begin
15
HA0:HALFADDERportmap(X0=>A,
16
Y0=>B,
17
CARRY0=>W_CARRY0,
18
SUM0=>W_SUM);
19
20
HA1:HALFADDERportmap(X0=>W_SUM,
21
Y0=>C_IN,
22
CARRY0=>W_CARRY1,
23
SUM0=>S);
24
25
C_OUT<=W_CARRY0ORW_CARRY1;
26
27
28
endFULLADDER_IDEAL;
Nun fehlt noch die VHDL-Datei für einen einzelnen Halbaddierer:
1
entityHALFADDERis
2
port(X0,Y0:instd_logic;
3
CARRY0,SUM0:outstd_logic);
4
endHALFADDER;
5
6
architectureHALFADDER_IDEALofHALFADDERis
7
8
begin
9
SUM0<=X0XORY0;
10
CARRY0<=X0ORY0;
11
12
endHALFADDER_IDEAL;
Das Problem ist nun: Wenn ich mir eine Testbench erzeugen lasse und
bspw. für den Eingang A "01" (binär) wähle (alle anderen Eingänge sind
auf 0), bekomme ich für den Ausgang S "11" und für den Carry-out '1',
was natürlich nicht stimmen kann. Allerdings habe ich keine Ahnung was
falsch sein könnte. An alle die bis jetzt durchgehalten haben: Schon mal
vielen Dank fürs lesen ;-)
Wer kann mir da weiterhelfen?
Andi X. schrieb:> Allerdings habe ich keine Ahnung was falsch sein könnte.
Du hast doch schon die Siluationam laufen, da kannst du doch einfach
herausfinden, was schief läuft...
Als Tipp: du kannst im ISIM links im Fenster (Strukturbaum) auch interne
Signale von Submodulen zur Waveform hinzifügen. Dann kannst du ja mal
kontrollieren, ob jedes Modul das macht, was du von ihm erwartest.
> eine Testbench
Lass doch mal die Testbench sehen und mach einen Screenshot von der
Waveform...
> Ich arbeite gerade ein wenig mit VHDL (bin totaler Anfänger) und benutze> dazu das Xilinx ISE Webpack. Jetzt habe ich mir gedacht, ich könnte mal> als kleine Übung einen 2-Bit-Volladdierer bauen und ihn entsprechend in> Komponenten zerlegen, um die component-Funktion zu testen
Ist das eine Hausaufgabe, oder tust du dir gern selber weh? Ich wäre
beim besten Willen niemals auf die Idee gekommen, einen Addierer in
subatomare Teile zu zerlegen und die dann per händischer Instantiierung
wieder zu einem Addierer zusammenzufügen. Sowas gibt es doch nur an
Schulen und in Lehrbüchern...
> um die component-Funktion zu testen
Was ist das?
> Wer kann mir da weiterhelfen?
Ich könnte, aber ich will nicht. Denn 1. ist das sicher etwas ganz
Einfaches, und 2. lernst du nichts dabei, wenn ich dir diesen einfachen
Fehler zeige.
Mein Tipp wäre: nimm den '+' Operator, der in VHDL eingebaut ist. Und
wenn du schon unbedingt Komponenten einsetzen willst, dann bastle dir
einen Timer, der jede Sekunde ein Clock-Enable ausgibt und binde den als
Komponente in ein Lauflicht oder sonstwas ein. Dann hast du shcon mal
was, was du später auch noch verwenden kannst...
> Ich wäre> beim besten Willen niemals auf die Idee gekommen, einen Addierer in> subatomare Teile zu zerlegen und die dann per händischer Instantiierung> wieder zu einem Addierer zusammenzufügen
Ich denke Andi will damit einfach mal üben wie die Definition,
Deklaration und Instanziierung von Componenten und der Simulator
funktioniert. Als Übung finde ich das ganz ok.
Grobi schrieb:>> Ich wäre>> beim besten Willen niemals auf die Idee gekommen, einen Addierer in>> subatomare Teile zu zerlegen und die dann per händischer Instantiierung>> wieder zu einem Addierer zusammenzufügen>> Ich denke Andi will damit einfach mal üben wie die Definition,> Deklaration und Instanziierung von Componenten und der Simulator> funktioniert. Als Übung finde ich das ganz ok.
Exakt das ist es! Natürlich könnte ich mir das Numeric-package einbinden
und zwei Zahlen einfach addieren, aber es geht mir hier nicht um das
Ergebnis an sich, sondern das ist eine reine Übungssache, um, wie Grobi
bereits geschrieben hat, Componenten, Simulator etc. zu testen. Wie
gesagt, ich bin totaler Anfänger in Sachen VHDL und würde nichts lernen,
wenn ich S <= A + B; eintippen würde ;)
Und nein, es ist weder eine Hausaufgabe noch Prüfungsaufgabe oder
irgendetwas anderes in diese Richtung, einfach nur eine kleine Übung,
die ich mir ausgedacht habe, also bitte keine Flames à la "Ich löse doch
nicht deine Hausaufgaben" ;-)
>Als Tipp: du kannst im ISIM links im Fenster (Strukturbaum) auch interne>Signale von Submodulen zur Waveform hinzifügen. Dann kannst du ja mal>kontrollieren, ob jedes Modul das macht, was du von ihm erwartest.
Danke für den Tipp! Das werde ich mir mal anschauen
Okay, also die Testbench hab ich mir vom Webpack automatisch erzeugen
lassen und habe auf die schnelle ein paar kleine Signalzuweisungen
reingepackt:
1
ENTITYFULLADDER_2BIT_TESTBENCHIS
2
ENDFULLADDER_2BIT_TESTBENCH;
3
4
ARCHITECTUREbehaviorOFFULLADDER_2BIT_TESTBENCHIS
5
6
-- Component Declaration for the Unit Under Test (UUT)
-- No clocks detected in port list. Replace <clock> below with
28
-- appropriate port name
29
30
--constant <clock>_period : time := 10 ns;
31
32
BEGIN
33
34
-- Instantiate the Unit Under Test (UUT)
35
uut:FULLADDER_2BITPORTMAP(
36
A=>A,
37
B=>B,
38
C_IN=>C_IN,
39
S=>S,
40
C_OUT=>C_OUT
41
);
42
43
-- Clock process definitions
44
--<clock>_process :process
45
--begin
46
-- <clock> <= '0';
47
-- wait for <clock>_period/2;
48
-- <clock> <= '1';
49
-- wait for <clock>_period/2;
50
--end process;
51
52
53
-- Stimulus process
54
stim_proc:process
55
begin
56
-- hold reset state for 100 ns.
57
waitfor100ns;
58
59
--wait for <clock>_period*10;
60
61
-- insert stimulus here
62
waitfor50ns;
63
A<="01";
64
waitfor50ns;
65
B<="10";
66
C_IN<='0';
67
waitfor50ns;
68
C_IN<='1';
69
wait;
70
endprocess;
71
72
END;
Die Bereiche mit clock habe ich auskommentiert, da ich keinen Takt
verwende (hier soll nichts auf einen FPGA implementiert werden, ich
schaue nur, dass ich mit der VHDL-Syntax zurechtkomme)
Fpga Kuechle schrieb:> das carry vom halbadder wird mit AND gebildet, nicht mit OR.> MfG,
Vielen Dank, das war tatsächlich der Fehler! :)
Eine Frage habe ich noch: Wenn ich mir das Schematic anzeigen lasse,
würde ich zwei Volladdierer, also FA0 und FA1 erwarten, ich bekomme
allerdings nur das Bild im Anhang angezeigt. Kommentiere ich jedoch
jeweils einen Volladdierer aus, bekomm ich ihn entsprechend angezeigt,
also FA0 oder FA1. Außerdem ist der C_OUT nicht mit dem C_OUT Ausgang
der entity verbunden. Ist das normal?
Edit:
@Lothar:
>Ich wäre beim besten Willen niemals auf die Idee gekommen, einen Addierer in>subatomare Teile zu zerlegen und die dann per händischer Instantiierung>wieder zu einem Addierer zusammenzufügen.
Mal rein aus Interesse, wie macht man so etwas effektiver (also jetzt
nicht über ein +)? Gibt es eine Möglichkeit die Instantiierungen in
einer Art Schleife ablaufen zu lassen?
Andi X. schrieb:> @Lothar:>>Ich wäre beim besten Willen niemals auf die Idee gekommen, einen Addierer in>>subatomare Teile zu zerlegen und die dann per händischer Instantiierung>>wieder zu einem Addierer zusammenzufügen.> Mal rein aus Interesse, wie macht man so etwas effektiver (also jetzt> nicht über ein +)? Gibt es eine Möglichkeit die Instantiierungen in> einer Art Schleife ablaufen zu lassen?
Ja, siehe unvollständiges beispiel:
1
--Instanziierung der fullader
2
--dabei Verdrahtung mit std_logic_vector mit Index loopindex
3
4
G_16bit_adder:FORloopindexin0TO15GENERATE
5
i_FULLADDS:FULLADDERportmap(
6
A=>A(loopindex),
7
B=>B(loopindex),
8
C_IN=>carries_in(loopindex),
9
C_OUT=>carries_out(loopindex),
10
S=>S(loopindex));
11
ENDGENERATE;
12
carries_in(15downto1)<=carries_out(14downto0);
wobei "+" vorzuziehen ist. In modernen FPGA's kann das auf
verschiedenene "Hardware-Adder" abgebildet (Syntetisiert/map) werden:
-carry-chain + luts
-dsp-slices
Oder embedded memory als Adder-LookUp-table verwenden (falls alle slices
belegt sind, aber noch BRAMS frei).
MfG
Fpga Kuechle schrieb:> wobei "+" vorzuziehen ist. In modernen FPGA's kann das auf> verschiedenene "Hardware-Adder" abgebildet (Syntetisiert/map) werden
Denn gerade solche alltäglichen Aufgaben sind den FPGA Entwicklern
natürlich auch bekannt und es wurden zig Mannjahre z.B. allein auf das
effiziente Design des Carrys verwendet und Patente dafür erteilt (jeder
Zähler ist ein Addierer). Da muss jede manuelle Implementierung
zwangsläufig schlechter sein.
Lothar Miller schrieb:> Fpga Kuechle schrieb:>> wobei "+" vorzuziehen ist. In modernen FPGA's kann das auf>> verschiedenene "Hardware-Adder" abgebildet (Syntetisiert/map) werden> Denn gerade solche alltäglichen Aufgaben sind den FPGA Entwicklern> natürlich auch bekannt und es wurden zig Mannjahre z.B. allein auf das> effiziente Design des Carrys verwendet und Patente dafür erteilt (jeder> Zähler ist ein Addierer). Da muss jede manuelle Implementierung> zwangsläufig schlechter sein.
Wobei es gar nicht so schlecht ist, wenigstens einmal einen
'Ripple-Carry' Addierer sowie einen 'Carry-Lookahead' Addierer zu Fuss
zu bauen und ggf. auch mal die maximalen Taktfrequenzen bzw. den
Resourcenverbrauch anzuschauen. Das mag fuer FPGAs nicht wirklich viel
bringen, zum Verstaendnis der Logik aber schon. Sind halt Grundlagen,
die man im Logic-Design verstanden haben sollte...
Wenn schon jemand 'einfach mal so' in die Materie schnuppern will, dann
hat das schon einen Sinn. Und dann danach halt so Sachen wie FSMs, ...
berndl schrieb:> Lothar Miller schrieb:>> Fpga Kuechle schrieb:>>> wobei "+" vorzuziehen ist. In modernen FPGA's kann das auf>>> verschiedenene "Hardware-Adder" abgebildet (Syntetisiert/map) werden>> Denn gerade solche alltäglichen Aufgaben sind den FPGA Entwicklern>> natürlich auch bekannt und es wurden zig Mannjahre z.B. allein auf das>> effiziente Design des Carrys verwendet und Patente dafür erteilt (jeder>> Zähler ist ein Addierer). Da muss jede manuelle Implementierung>> zwangsläufig schlechter sein.>> Wobei es gar nicht so schlecht ist, wenigstens einmal einen> 'Ripple-Carry' Addierer sowie einen 'Carry-Lookahead' Addierer zu Fuss> zu bauen und ggf. auch mal die maximalen Taktfrequenzen bzw. den> Resourcenverbrauch anzuschauen. Das mag fuer FPGAs nicht wirklich viel> bringen, zum Verstaendnis der Logik aber schon. Sind halt Grundlagen,> die man im Logic-Design verstanden haben sollte...
Nun das schärft den Blick für Varianten eine kombinatorische Schaltung
aufzubauen. Da aber im FPGA das meiste aus LUT's statt aus NAND-Gatter
aufgebaut wird und die Routing resourcen nicht so feingranular anpassbar
sind wie im Full-Custom-Entwurf sind dieBewertungen der verschiedenen
Adder-Architekturen aus dem Lehrbuch nur bedingt auf FPGA-Realisierungen
übertragbar. Siehe:
http://forums.xilinx.com/t5/Spartan-Family-FPGAs/About-technology-mapping/m-p/116474/highlight/true#M9040
Als Beispiel sei auf die Xilinx Apps zum Multiplexer design XAPP466 und
XAPP522 verwiesen. Selbst bei so simplen Strukturen kann man durch
Optimierung auf FPGA-Logik Vorteile erlangen.
MfG