Hallo,
ich versuche folgende Gleichung in VHDL umzusetzen:
Y = (X1 - X2 - X3 + X4) / 2 ;
Dabei sind X1 - X4 Signale vom Typ std_logic_vector(31 downto 0). Mein
Problem ist, dass X1 - X4 sehr groß werden können (also 0xFFFFFFFF) oder
eben sehr klein (also 0x00000000).
Y soll am Ende auch ein std_logic_vector(31 downto 0) werden. Wenn es
einen Überlauf gibt, dann soll Y = 0xFFFFFFFF ergeben.
Desweiteren soll es ein Vorzeichen Signal geben (prefix), das mir
Anzeigt, ob der Wert Y positiv oder negativ ist.
Mein (recht kläglicher) Versuch war folgender:
entity test is
port(
clk : in std_logic;
rst_n : in std_logic;
-- ...
X1 : in std_logic_vector(31 downto 0);
X2 : in std_logic_vector(31 downto 0);
X3 : in std_logic_vector(31 downto 0);
X4 : in std_logic_vector(31 downto 0);
-- ...
Y : out std_logic_vector(31 downto 0);
prefix : out std_logic
-- ...
);
end entity test;
architecture stb of test
signal s_Y_signed : signed(31 downto 0);
signal s_X1 : std_logic_vector(31 downto 0);
signal s_X2 : std_logic_vector(31 downto 0);
signal s_X3 : std_logic_vector(31 downto 0);
signal s_X4 : std_logic_vector(31 downto 0);
-- ...
begin
-- ...
s_Y_signed <= conv_signed((( conv_integer(s_X1) - conv_integer(s_X2) -
conv_integer(s_X3) + conv_integer(s_X4)) / 2), s_Y_signed'length);
Y <= conv_std_logic_vector( s_Y_signed, Y'length);
prefix <= s_Y_signed(s_Y_signed'high);
-- ...
test_proc : process (clk, rst_n)
begin
if (rst_n = '0') then
s_X1 <= (others => '0');
s_X2 <= (others => '0');
s_X3 <= (others => '0');
s_X4 <= (others => '0');
-- ...
elsif (clk'event and clk = '1') then
s_X1 <= X1;
s_X2 <= X2;
s_X3 <= X3;
s_X4 <= X4;
-- ...
end if;
end process test_proc
-- ...
end architecture stb;
Das mit dem Überlauf fehlt hier noch komplett, da ich mir noch nicht
ganz klar darüber geworden bin wie ich das am Besten detektieren könnte.
Der abgetaktete Prozess schaut hier etwas klein aus, in der
Oringalfassung ist er deutlich größer. Ich hab jetzt nur die wichtigen
Zuweisungen gelassen.
Ich hoffe jemand kann mir helfen mein Problem zu lösen. Vll. bin ich
auch mit diesem Ansatz komplett auf dem Holzweg und jemand anderes kann
mir einen neuen Denkanstoß in eine andere Richtung geben.
Gruß,
Stahlkopf
Nur für unsigned Additionen gesprochen erst mal. Ein Überlauf sollte
doch so festzustellen sein, daß intern die Register ein Bit breiter
gemacht werden als das Ergebnis breit ist.
Überlauf ist dann einfach das zusätzliche Bit was gesetzt ist.
Zur Vorzeichen Betrachtung mag ich mich nicht äußern, aber sollte
grundsätzlich auch keinen Unterschied machen.
Hallo,
danke Panko für deine Hilfe. Du meinst dann, dass das Überlaufproblem
dann so behoben werden kann:
signal s_Y_signed : signed(32 downto 0);
if (s_Y_signed(s_Y_signed'high - 1) = '0') then
-- no overflow
Y <= conv_std_logic_vector( s_Y_signed, Y'length);
else
-- overflow
Y <= (others => '1');
end if;
In dem Fall würde ich dann die Zuweisungen für Y und prefix in den
Process mit hineinziehen. Der würde dann anschließend so ausschauen:
test_proc : process (clk, rst_n)
begin
if (rst_n = '0') then
s_X1 <= (others => '0');
s_X2 <= (others => '0');
s_X3 <= (others => '0');
s_X4 <= (others => '0');
-- ...
Y <= (others => '0');
prefix <= '0';
-- ...
elsif (clk'event and clk = '1') then
s_X1 <= X1;
s_X2 <= X2;
s_X3 <= X3;
s_X4 <= X4;
-- ...
if (s_Y_signed(s_Y_signed'high - 1) = '0') then
-- no overflow
Y <= conv_std_logic_vector( s_Y_signed, Y'length);
else
-- overflow
Y <= (others => '1');
end if;
prefix <= s_Y_signed(s_Y_signed'high);
-- ...
end if;
end process test_proc
Auch Dankeschön Duke für den Link. Mit den Bibliotheken hab ich mich
auch schonmal rumgeärgert. Und die Problematik std_logic_arith und
numeric_std ist mir bekannt. Allerdings hab ich nicht das passende
Pendant für meine Konvertierungen in numeric_std gefunden. Wenn ich z.B.
to_integer verwende, bekomm ich beim kompilieren den Fehler zurück, dass
er das Subprogramm nicht kennt. Aus dem Grund bin ich dann am Ende doch
bei std_logic_arith gelandet (was natürlich jetzt einen Fehler bedeuten
könnte).
Kannst du mir da evtl. helfen und die richtigen Konvertierungstypen für
die numeric_std Library sagen (ich hab den krähenden Vogel (Goggel)
schon bemüht, allerdings ohne Erfolg)?
Gruß,
Stahlkopf
Hallo,
danke nochmal für den Link. Der ist Gold wert!!! Damit haben sich
endlich mal ein paar Fragezeichen zu den Bibliotheken aufgelöst.
Ich habe jetzt also die Umrechnung wie folgt gemacht:
entity test is
port(
clk : in std_logic;
rst_n : in std_logic;
-- ...
X1 : in std_logic_vector(31 downto 0);
X2 : in std_logic_vector(31 downto 0);
X3 : in std_logic_vector(31 downto 0);
X4 : in std_logic_vector(31 downto 0);
-- ...
Y : out std_logic_vector(31 downto 0);
prefix : out std_logic
-- ...
);
end entity test;
architecture stb of test
signal s_Y_signed_ext : signed(32 downto 0);
signal s_Y_signed : signed(31 downto 0);
signal s_X1 : std_logic_vector(31 downto 0);
signal s_X2 : std_logic_vector(31 downto 0);
signal s_X3 : std_logic_vector(31 downto 0);
signal s_X4 : std_logic_vector(31 downto 0);
-- ...
begin
-- ...
s_Y_signed_ext <= to_signed((( to_integer(unsigned(s_X1)) -
to_integer(unsigned(s_X2)) -
to_integer(unsigned(s_X3)) +
to_integer(unsigned(s_X4))) / 2),
s_Y_signed_ext'length);
s_Y_signed <= s_Y_signed_ext(s_Y_signed_ext'high) &
s_Y_signed_ext(30 downto 0);
-- ...
test_proc : process (clk, rst_n)
begin
if (rst_n = '0') then
s_X1 <= (others => '0');
s_X2 <= (others => '0');
s_X3 <= (others => '0');
s_X4 <= (others => '0');
-- ...
Y <= (others => '0');
prefix <= '0';
elsif (clk'event and clk = '1') then
s_X1 <= X1;
s_X2 <= X2;
s_X3 <= X3;
s_X4 <= X4;
-- ...
if (s_Y_signed_ext(s_Y_signed_ext'high - 1) = '0') then
-- no overflow
Y <= std_logic_vector(
to_unsigned(to_integer(s_Y_signed), Y'length));
else
-- overflow
Y <= (others => '1');
end if;
prefix <= s_Y_signed(s_Y_signed'high);
end if;
end process test_proc
-- ...
end architecture stb;
So weit, so gut. Kompilieren funktioniert ohne Probleme. Wenn ich das
jetzt allerdings simuliere, erhalte ich in Modelsim die Fehlermeldung
(und das obwohl er anscheinend alles durch simuliert und nicht
abbricht):
Error: (vsim-86) numstd_conv_unsigned_nu: NATURAL arg value is negative
(-8947848)
Ich geh davon aus, dass mit der Konvertierung etwas nicht ganz passt.
Vermutlich werden irgendwo Werte übergeben, die außerhalb der Reichweite
des Datentyps sind. Allerdings seh ich nicht, an welcher Stelle das
passiert.
Any Idea? Nochmals danke für eure Hilfe!
Gruß,
Stahlkopf
Edit:
Fürs bessere Verständnis der Fehlermeldung, hier die eingestellten
Werte:
X0: 0x00000000
X1: 0x01111111
X2: 0x00000000
X3: 0x00000000
Damit ist das Ergebnis der Rechnung negativ. Aber das sollte ja
schließlich mit signed möglich sein...
Stahlkopf schrieb:> Edit:> Fürs bessere Verständnis der Fehlermeldung, hier die eingestellten> Werte:>> X0: 0x00000000> X1: 0x01111111> X2: 0x00000000> X3: 0x00000000
Das ist natürlich vollkommener Blödsinn. Ich bin da um eine Stelle
verrutscht. Richtig wäre:
X1: 0x00000000
X2: 0x01111111
X3: 0x00000000
X4: 0x00000000
Gruß,
Stahlkopf
BTW, Du kannst auch direkt mit signed und unsigned rechnen.
Wenn Du bis zu auf integer konvertierst, dürften die meisten Systeme nur
mit 32 Bit (signed) rechnen.
Duke
P.S.:
Für sowas:
s_Y_signed <= s_Y_signed_ext(s_Y_signed_ext'high) &
s_Y_signed_ext(30 downto 0);
gibt es resize...
Eine eigene Frage?
Dieser Thread ist über 15 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.