So verwenden Sie signiert und unsigniert in VHDL
Die Typen mit und ohne Vorzeichen in VHDL sind Bitvektoren, genau wie der Typ std_logic_vector. Der Unterschied besteht darin, dass der std_logic_vector zwar großartig für die Implementierung von Datenbussen ist, aber für die Durchführung arithmetischer Operationen nutzlos ist.
Wenn Sie versuchen, eine beliebige Zahl zu einem std_logic_vector-Typ hinzuzufügen, erzeugt ModelSim den Kompilierungsfehler:Keine zulässigen Einträge für den Infix-Operator „+“. Dies liegt daran, dass der Compiler nicht weiß, wie er diese Sammlung von Bits, die der Vektor ist, interpretieren soll.
Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.
Wir müssen unseren Vektor als signiert oder unsigniert deklarieren, damit der Compiler ihn als Zahl behandelt.
Die Syntax zum Deklarieren von signierten und unsignierten Signalen lautet:signal <name> : signed(<N-bits> downto 0) := <initial_value>;
signal <name> : unsigned(<N-bits> downto 0) := <initial_value>;
Genau wie bei std_logic_vector können die Bereiche to
sein oder downto
jede Reichweite. Aber das Deklarieren von Signalen mit anderen Bereichen als downto 0
ist so ungewöhnlich, dass es uns nur verwirren würde, wenn wir uns noch länger mit diesem Thema beschäftigen würden. Der Anfangswert ist optional, standardmäßig ist er 'U'
für alle Bits.
Wir haben bereits den integer
verwendet Typ für arithmetische Operationen in früheren Tutorials. Warum brauchen wir also die signierten und unsignierten Typen? Die meisten Digitaldesigner möchten mehr Kontrolle darüber haben, wie viele Bits ein Signal tatsächlich verwendet.
Außerdem werden vorzeichenbehaftete und vorzeichenlose Werte umlaufen, während der Simulator einen Laufzeitfehler auslöst, wenn ein integer
wird über Grenzen hinaus inkrementiert. Schließlich können signiert und unsigniert andere Werte wie 'U'
haben und 'X'
, während ganze Zahlen nur Zahlenwerte haben können. Diese Metawerte können uns helfen, Fehler in unserem Design zu entdecken.
Übung
In diesem Video erfahren wir, wie sich signierte und unsignierte Signale gleich verhalten und wie sie sich unterschiedlich verhalten:
Der endgültige Code, den wir in diesem Tutorial erstellt haben:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T12_SignedUnsignedTb is end entity; architecture sim of T12_SignedUnsignedTb is signal UnsCnt : unsigned(7 downto 0) := (others => '0'); signal SigCnt : signed(7 downto 0) := (others => '0'); signal Uns4 : unsigned(3 downto 0) := "1000"; signal Sig4 : signed(3 downto 0) := "1000"; signal Uns8 : unsigned(7 downto 0) := (others => '0'); signal Sig8 : signed(7 downto 0) := (others => '0'); begin process is begin wait for 10 ns; -- Wrapping counter UnsCnt <= UnsCnt + 1; SigCnt <= SigCnt + 1; -- Adding signals Uns8 <= Uns8 + Uns4; Sig8 <= Sig8 + Sig4; end process; end architecture;
Das Wellenformfenster in ModelSim, vergrößert auf die interessanten Teile:
Analyse
Die Basis aller Signale in der Wellenform wird auf hexadezimal gesetzt, damit wir sie gleichermaßen vergleichen können.
Im Wrapping-Counter-Beispiel sehen wir, dass sich signierte und unsignierte Signale genau gleich verhalten. Beide UnsCnt
und SigCnt
beginnen bei 0 und werden nacheinander bis FF erhöht. Hex FF (dezimal 255) ist der größte Wert, den unsere 8-Bit-Signale aufnehmen können. Daher setzt das nächste Inkrement beide auf 0 zurück.
Wir haben die beiden 4-Bit-Signale Uns4
erzeugt und Sig4
, und gab beiden einen Anfangswert von „1000“. Wir können aus der Wellenform ersehen, dass sie beide nur Hex 8 (binär 1000) sind.
Die letzten beiden 8-Bit-Signale, die wir erstellt haben, waren Uns8
und Sig8
. Wir können aus der Wellenform ersehen, dass ihre Anfangswerte 0 sind, wie man es erwarten würde. Aber von da an verhalten sie sich anders! Anscheinend machten vorzeichenbehaftete und vorzeichenlose Typen einen Unterschied, wenn zwei Signale unterschiedlicher Länge hinzugefügt wurden.
Dies liegt an etwas, das als Sign Extension bekannt ist . Das Addieren positiver oder negativer Zahlen, die in Vektoren gleicher Länge gespeichert sind, ist die gleiche Operation in der digitalen Logik. Das liegt daran, wie das Zweierkomplement funktioniert. Wenn die Vektoren unterschiedlich lang sind, muss der kürzeste Vektor verlängert werden.
Die vorzeichenlose 4-Bit-Binärzahl „1000“ ist dezimal 8, während die vorzeichenbehaftete 4-Bit-Zahl „1000“ dezimal -8 ist. Die „1“ ganz links neben der vorzeichenbehafteten Zahl zeigt an, dass es sich um eine negative Zahl handelt. Daher werden die beiden 4-Bit-Signale vom Compiler unterschiedlich vorzeichenerweitert.
Dies ist eine Visualisierung, wie die Zeichenerweiterung die unterschiedlichen Werte für Uns8
erstellt und Sig8
Signale:
Imbiss
- Signale mit und ohne Vorzeichen sind Vektoren, die in arithmetischen Operationen verwendet werden können
- Signale mit Vorzeichen und ohne Vorzeichen werden stillschweigend überlaufen
- Sign-Erweiterung kann unterschiedliche Ergebnisse für signierte und unsignierte Typen erzeugen
Weiter zum nächsten Tutorial »
VHDL
- Signiert vs. Unsigniert in VHDL
- So verwenden Sie eine Prozedur in einem Prozess in VHDL
- So verwenden Sie eine unreine Funktion in VHDL
- So verwenden Sie eine Funktion in VHDL
- So verwenden Sie eine Prozedur in VHDL
- So verwenden Sie Konstanten und generische Karten in VHDL
- So verwenden Sie die Port Map-Instanziierung in VHDL
- So installieren Sie kostenlos einen VHDL-Simulator und -Editor
- PIC18-Mikrocontroller:Was er ist und wie er verwendet wird
- Was ist ein Referenzdesignator und wie verwenden wir ihn in der Montage?