Forum: FPGA, VHDL & Co. VHDL: Volladdierer


von Andi K. (fry12)


Lesenswert?

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:
1
entity FULLADDER_2BIT is
2
  port(A, B  : in std_logic_vector(1 downto 0);
3
      C_IN  : in std_logic;
4
      S     : out std_logic_vector(1 downto 0);
5
      C_OUT : out std_logic);
6
end FULLADDER_2BIT;
7
8
architecture FULLADDER_2BIT_IDEAL of FULLADDER_2BIT is
9
  component FULLADDER
10
    port(A, B, C_IN : in std_logic;
11
        C_OUT, S   : out std_logic);
12
  end component;
13
  
14
  signal W_CARRY : std_logic;
15
  
16
begin
17
  FA0: FULLADDER port map(A => A(0),
18
                  B => B(0),
19
                  C_IN => C_IN,
20
                  C_OUT => W_CARRY,
21
                  S => S(0));
22
                  
23
  FA1: FULLADDER port map(A => A(1),
24
                  B => B(1),
25
                  C_IN => W_CARRY,
26
                  C_OUT => C_OUT,
27
                  S => S(1));
28
  
29
end FULLADDER_2BIT_IDEAL;
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
entity FULLADDER is
2
  port(A, B, C_IN : in std_logic;
3
      C_OUT, S    : out std_logic);
4
end FULLADDER;
5
6
architecture FULLADDER_IDEAL of FULLADDER is
7
  component HALFADDER
8
    port(X0, Y0       : in std_logic;
9
        CARRY0, SUM0 : out std_logic);
10
  end component;
11
  
12
  signal W_CARRY0, W_CARRY1, W_SUM : std_logic;
13
  
14
begin
15
  HA0: HALFADDER port map(X0 => A, 
16
                  Y0 => B, 
17
                  CARRY0 => W_CARRY0, 
18
                  SUM0 => W_SUM);
19
                  
20
  HA1: HALFADDER port map(X0 => W_SUM, 
21
                  Y0 => C_IN, 
22
                  CARRY0 => W_CARRY1, 
23
                  SUM0 => S);
24
  
25
  C_OUT <= W_CARRY0 OR W_CARRY1;
26
  
27
28
end FULLADDER_IDEAL;

Nun fehlt noch die VHDL-Datei für einen einzelnen Halbaddierer:
1
entity HALFADDER is
2
  port(X0, Y0       : in std_logic;
3
      CARRY0, SUM0 : out std_logic);
4
end HALFADDER;
5
6
architecture HALFADDER_IDEAL of HALFADDER is
7
8
begin
9
  SUM0   <= X0 XOR Y0;
10
  CARRY0 <= X0 OR Y0;
11
12
end HALFADDER_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?

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Grobi (Gast)


Lesenswert?

> 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.

von Andi K. (fry12)


Lesenswert?

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
ENTITY FULLADDER_2BIT_TESTBENCH IS
2
END FULLADDER_2BIT_TESTBENCH;
3
 
4
ARCHITECTURE behavior OF FULLADDER_2BIT_TESTBENCH IS 
5
 
6
    -- Component Declaration for the Unit Under Test (UUT)
7
 
8
    COMPONENT FULLADDER_2BIT
9
    PORT(
10
         A : IN  std_logic_vector(1 downto 0);
11
         B : IN  std_logic_vector(1 downto 0);
12
         C_IN : IN  std_logic;
13
         S : OUT  std_logic_vector(1 downto 0);
14
         C_OUT : OUT  std_logic
15
        );
16
    END COMPONENT;
17
    
18
19
   --Inputs
20
   signal A : std_logic_vector(1 downto 0) := (others => '0');
21
   signal B : std_logic_vector(1 downto 0) := (others => '0');
22
   signal C_IN : std_logic := '0';
23
24
   --Outputs
25
   signal S : std_logic_vector(1 downto 0);
26
   signal C_OUT : std_logic;
27
   -- 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_2BIT PORT MAP (
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
      wait for 100 ns;  
58
59
      --wait for <clock>_period*10;
60
61
      -- insert stimulus here 
62
    wait for 50 ns;
63
    A <= "01";
64
    wait for 50 ns;
65
    B <= "10";
66
    C_IN <= '0';
67
    wait for 50 ns;
68
    C_IN <= '1';
69
      wait;
70
   end process;
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)

: Bearbeitet durch User
von Fpgakuechle K. (Gast)


Lesenswert?

das carry vom halbadder wird mit AND gebildet, nicht mit OR.
MfG,

von Andi K. (fry12)


Angehängte Dateien:

Lesenswert?

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?

: Bearbeitet durch User
von Fpgakuechle K. (Gast)


Lesenswert?

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: FOR loopindex in 0 TO 15 GENERATE
5
  i_FULLADDS: FULLADDER port map(
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
               END GENERATE;
12
  carries_in(15 downto 1) <= carries_out(14 downto 0);

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

von berndl (Gast)


Lesenswert?

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, ...

von Fpgakuechle K. (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.