Es gibt eine Möglichkeit, Ihren Index für die Synthese statisch zu machen.
Zuerst, basierend auf der Schleife können wir sagen, position
muss einen Wert im Bereich von shift_aux
haben, sonst würden Sie mit Null Scheiben (IEEE Std 1076-2008 8.5 Slice-Namen) enden.
Das kann in der Entity-Deklaration dargestellt werden:
library ieee;
use ieee.std_logic_1164.all;
entity shift_register is
generic (
N: integer := 6;
M: integer := 6
);
port (
en_s: in std_logic;
cod_result: in std_logic_vector (N + M - 1 downto 0);
position: in integer range 0 to N + M - 1 ; -- range ADDED
shift_result: out std_logic_vector(N + M - 1 downto 0)
);
end entity shift_register;
Was sich geändert hat ist die Zugabe eines Bereichsbeschränkung in den Hafen Erklärung position
. Die Idee besteht darin, eine Simulation zu unterstützen, bei der der Standardwert von integer integer'left
sein kann. Das Simulieren Ihrer shift_register
würde an der steigenden Flanke von en_s
fehlschlagen, wenn position
(der tatsächliche Treiber) einen Anfangswert in dem Indexbereich von shift_aux
nicht bereitstellte.
Aus einer Syntheseperspektive erfordert eine unbegrenzte Ganzzahl, dass Sie sowohl positive als auch negative Ganzzahlwerte berücksichtigen. Ihre for-Schleife verwendet nur positive ganzzahlige Werte.
Problem
variable i: integer range 0 to N + M - 1 := 0; -- range ADDED
Um das unmittelbare Synthese uns für Schleife bei der Suche:
Das gleiche kann in der Deklaration der Variablen i
im Prozess erfolgen.
Xilinx-Support-Problem AR# 52302 teilt uns mit, dass das Problem dynamische Werte für Indizes verwendet.
Die Lösung ist, zu ändern, was die for-Schleife hat:
architecture shift_loop of shift_register is
begin
process (en_s)
variable shift_aux: std_logic_vector(N + M - 1 downto 0);
-- variable i: integer range 0 to N + M - 1 := 0; -- range ADDED
begin
if en_s'event and en_s = '1' then
-- i := position;
shift_aux := (others => '0');
for i in 0 to N + M - 1 loop
-- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0);
if i = position then
shift_aux(N + M - 1 downto i)
:= cod_result(N + M - 1 - i downto 0);
end if;
end loop;
shift_result <= shift_aux;
end if;
end process;
end architecture shift_loop;
i
Wenn ein statischer Wert wird, wenn die Schleife in Synthese abgerollt wird, kann in der Berechnung der Indizes verwendet werden.
Hinweis: Dies gibt uns einen N + M-Eingangsmultiplexer, bei dem jeder Eingang ausgewählt wird, wenn i = position
.
Dieses Konstrukt kann durch Optimierung tatsächlich zu einem Barrel-Shifter kollabiert werden, obwohl man erwarten könnte, dass die Anzahl der beteiligten Variablen für große Werte von N und M einen prohibitiven Syntheseaufwand erfordern oder einfach fehlschlagen.
Wenn die Synthese erfolgreich ist, werden Sie jedes Ausgabeelement in der Zuweisung in einen separaten Multiplexer zusammenfassen, der Patricks barrel shifter entspricht.
Für ausreichend große Werte von N und M können wir die Tiefe der Anzahl der Multiplexerschichten im Barrel-Shifter basierend auf der Anzahl der Bits in einem binären Ausdruck des ganzzahligen Abstandsbereichs definieren.
Das erfordert entweder einen deklarierten Integer-Typ oder Subtyp für position
oder den Log2-Wert von N + M. Wir können den log2-Wert verwenden, weil er nur statisch verwendet würde. (XST unterstützt log2 (x) wobei x ein Real ist, um statische Werte zu bestimmen, die Funktion wird im IEEE-Paket math_real gefunden). Dies gibt uns die binäre Länge von position
. (Wie viele Bits sind erforderlich, um die Verschiebungsstrecke, die Anzahl der Ebenen von Multiplexern zu beschreiben).
architecture barrel_shifter of shift_register is
begin
process (en_s)
use ieee.math_real.all; -- log2 [real return real]
use ieee.numeric_std.all; -- to_unsigned, unsigned
constant DISTLEN: natural := integer(log2(real(N + M))); -- binary lengh
type muxv is array (0 to DISTLEN - 1) of
unsigned (N + M - 1 downto 0);
variable shft_aux: muxv;
variable distance: unsigned (DISTLEN - 1 downto 0);
begin
if en_s'event and en_s = '1' then
distance := to_unsigned(position, DISTLEN); -- position in binary
shft_aux := (others => (others =>'0'));
for i in 0 to DISTLEN - 1 loop
if i = 0 then
if distance(i) = '1' then
shft_aux(i) := SHIFT_LEFT(unsigned(cod_result), 2 ** i);
else
shft_aux(i) := unsigned(cod_result);
end if;
else
if distance(i) = '1' then
shft_aux(i) := SHIFT_LEFT(shft_aux(i - 1), 2 ** i);
else
shft_aux(i) := shft_aux(i - 1);
end if;
end if;
end loop;
shift_result <= std_logic_vector(shft_aux(DISTLEN - 1));
end if;
end process;
end architecture barrel_shifter;
XST unterstützt auch **
wenn der linke Operand 2 und der Wert von i
ist als eine Konstante in der Folge von Anweisungen in einer LOOP-Anweisung gefunden behandelt.
Dies könnte mit Signalen anstelle von Variablen oder strukturell in einer Generate-Anweisung statt einer Schleifenanweisung innerhalb eines Prozesses oder sogar als Unterprogramm implementiert werden.
Die Grundidee hier mit diesen beiden Architekturen abgeleitet von Ihnen ist es, etwas Synthese geeignet zu produzieren.
Der Vorteil der zweiten Architektur über die erste ist, zu einer Verringerung der Menge an Syntheseaufwand bei der Optimierung für größere Werte von N + M.
Keines dieser Architekturen überprüft wurde, um eine Testumgebung in den ursprünglichen fehlt. Sie analysieren und erarbeiten beide.
Schreiben eines einfachen Fall Prüfstand:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity shift_register_tb is
end entity;
architecture foo of shift_register_tb is
constant N: integer := 6;
constant M: integer := 6;
signal clk: std_logic := '0';
signal din: std_logic_vector (N + M - 1 downto 0)
:= (0 => '1', others => '0');
signal dout: std_logic_vector (N + M - 1 downto 0);
signal dist: integer := 0;
begin
DUT:
entity work.shift_register
generic map (
N => N,
M => M
)
port map (
en_s => clk,
cod_result => din,
position => dist,
shift_result => dout
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if now > (N + M + 2) * 20 ns then
wait;
end if;
end process;
STIMULI:
process
begin
for i in 1 to N + M loop
wait for 20 ns;
dist <= i;
din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1));
end loop;
wait;
end process;
end architecture;
und Simulieren zeigt, dass der Bereich der position
und die Anzahl der Schleifendurchläufe nur die Anzahl der Bits im Multiplikator decken muss und nicht der Multiplikand. Wir brauchen keinen vollen Barrel Shifter.
Das kann in beiden shift_register-Architekturen leicht behoben werden und hat den Nebeneffekt, die shift_loop-Architektur viel attraktiver zu machen, es wäre einfacher, basierend auf der Multiplikator-Bitlänge (vermutlich M) und nicht der Produktbitlänge (N + M).
Und das würde Ihnen:
library ieee;
use ieee.std_logic_1164.all;
entity shift_register is
generic (
N: integer := 6;
M: integer := 6
);
port (
en_s: in std_logic;
cod_result: in std_logic_vector (N + M - 1 downto 0);
position: in integer range 0 to M - 1 ; -- range ADDED
shift_result: out std_logic_vector(N + M - 1 downto 0)
);
end entity shift_register;
architecture shift_loop of shift_register is
begin
process (en_s)
variable shift_aux: std_logic_vector(N + M - 1 downto 0);
-- variable i: integer range 0 to M - 1 := 0; -- range ADDED
begin
if en_s'event and en_s = '1' then
-- i := position;
shift_aux := (others => '0');
for i in 0 to M - 1 loop
-- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0);
if i = position then -- This creates an N + M - 1 input MUX
shift_aux(N + M - 1 downto i)
:= cod_result(N + M - 1 - i downto 0);
end if;
end loop; -- The loop is unrolled in synthesis, i is CONSTANT
shift_result <= shift_aux;
end if;
end process;
end architecture shift_loop;
Ändern der Testumgebung:
STIMULI:
process
begin
for i in 1 to M loop -- WAS N + M loop
wait for 20 ns;
dist <= i;
din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1));
end loop;
wait;
end process;
gibt ein Ergebnis zeigt die Verschiebungen über den Bereich des Multiplikatorwert sind (angegeben durch M):
Also die Moral hier ist, Sie brauchen keine vollständige Barrel Shifter, nur einer, der über den Multiplikatorbereich und nicht über den Produktbereich arbeitet.
Das letzte Bit Code sollte Synthese zulässig sein.
Ich weiß, warum nicht funktioniert, meine Aufgabe ist es, einen Booth-Multiplikator zu implementieren, so dass ich nicht x <= a * b verwenden kann. Jedenfalls danke –
@DarioFigliuzzi so Ihre eigentliche Frage ist "Wie implementiere ich einen Barrel Shifter?". Vor diesem Hintergrund gibt es diesbezüglich Fragen. –
Ich dachte mehr darüber nach, wie man das Problem umgehen könnte. Ein alternativer Weg –