我正在尝试使用生成函数创建一个n位逻辑移位。
entity logical_shift_n is
generic(WIDTH : positive :=8);
port (A: in std_logic_vector(WIDTH-1 downto 0);
S: in std_logic_vector(log2(WIDTH)-1 downto 0);
D: out std_logic_vector(WIDTH-1 downto 0));
type two_dim is array (0 to log2(WIDTH)-1) of std_logic_vector(WIDTH-1 downto 0);
end logical_shift_n;
architecture behavioral of logical_shift_n is
component mux is
port(A,B : in std_logic_vector(WIDTH-1 downto 0);
S : in std_logic;
O : out std_logic_vector(WIDTH-1 downto 0));
end component;
signal D1 : two_dim :=(others=>(others=>'0'));
signal D0 : two_dim :=(others=>(others=>'0'));
signal Y : two_dim :=(others=>(others=>'0'));
begin
D0 <= A;
D1 <= A & '0';
reg: for i in 0 to log2(WIDTH)-1 generate
DC : mux
port map(
A => D0,
B => D1,
S => S(i),
O => Y
);
end generate;
D <= Y;
end behavioral;
我面临的问题是
我需要将“D0”的第一行分配给“A”,将“D1”的第一行分配给“A&'0'”,以便D0的第一行包含正常输入A,D1的第一行包含A 左移 1。
然后我想迭代行(使用生成函数),以便来自第一个多路复用器的输出充当下一个多路复用器的输入,第二个多路复用器应该有一个正常输入(等于之前的输出)与之前的输入一样,然后是另一个输入,该输入应该是前一个输出移位 2。类似地,对于第三个多路复用器,其输入之一应该是前一个输出移位 4 (2^(n-1))。等等。
为了提供更好的想法,我还创建了一个图表。尽管该图仅适用于 8 位(三个多路复用器),但我想使用生成函数将其概括为 n 位。
我创建了一个二维信号。但我不确定如何初始化它的第一行。此外,我不确定如何迭代行,以便发生多路复用器的级联,并且在 n=0,1,2......n
的情况下也会发生左移(2^n)有多种方法可以创建通用或参数控制的逻辑(左)移位器。
这是基于您的问题代码的一个:
library ieee; -- CHANGED, added missing mux
use ieee.std_logic_1164.all;
entity mux is
generic (WIDTH: natural);
port (
A,B: in std_logic_vector(WIDTH - 1 downto 0);
S: in std_logic;
O: out std_logic_vector(WIDTH - 1 downto 0)
);
end entity;
architecture foo of mux is
begin
O <= A when S = '0' else B;
end architecture;
library ieee; -- CHANGED Context clause added
use ieee.std_logic_1164.all;
use ieee.math_real.all; -- ADDED for log2
entity logical_shift_n is
generic (WIDTH: positive := 8);
port (
A: in std_logic_vector(WIDTH - 1 downto 0);
-- CHANGED, added useage for log2 from package math_real, ceil for non powers of two
S: in std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
D: out std_logic_vector(WIDTH - 1 downto 0));
-- CHANGED don't calculate length again and again:
type two_dim is array (0 to S'LEFT) of
std_logic_vector(WIDTH - 1 downto 0);
end entity logical_shift_n;
architecture behavioral of logical_shift_n is
component mux is
generic (WIDTH: natural);
port (
A,B: in std_logic_vector(WIDTH - 1 downto 0);
S: in std_logic;
O: out std_logic_vector(WIDTH - 1 downto 0)
);
end component;
signal D1: two_dim; -- CHANGED -- :=(others=>(others=>'0'));
-- signal D0: two_dim; -- CHANGED -- :=(others=>(others=>'0'));
signal Y : two_dim; -- CHANGED -- :=(others=>(others=>'0'));
-- CHANGED, BORROWED from -1997 numeric_std-body.vhdl
function XSLL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
is
constant ARG_L: INTEGER := ARG'LENGTH-1;
alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0');
begin
if COUNT <= ARG_L then
RESULT(ARG_L downto COUNT) := XARG(ARG_L-COUNT downto 0);
end if;
return RESULT;
end XSLL;
begin
-- D0 <= A; CHANGED Either A for i = 0 or Y (i - 1) for i /= 0
-- D1 <= A & '0';
reg:
for i in S'range generate -- CHANGED, breakout i = 0 from rest -1993 syntax
I_EQ_0:
if i = 0 generate
D1(i) <= XSLL(A, 2 ** i);
DC:
mux
generic map (WIDTH => WIDTH)
port map (
A => A, -- CHANGED Y(0) not used
B => D1(i), -- CHANGED, indexed name
S => S(i),
O => Y(i) -- CHANGED, indexed name
);
end generate;
I_NEQ_0:
if i /= 0 generate
D1(i) <= XSLL(Y(i - 1), 2 ** i);
DC:
mux
generic map (WIDTH => WIDTH)
port map (
A => Y(i - 1), -- CHANGED
B => D1(i), -- CHANGED, indexed name
S => S(i),
O => Y(i) -- CHANGED, indexed name
);
end generate;
end generate;
D <= Y(S'LEFT);
end architecture behavioral;
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
entity logical_shift_n_tb is
end entity;
architecture foo of logical_shift_n_tb is
constant WIDTH: natural := 8;
component logical_shift_n is
generic (WIDTH: positive := 8);
port (
A: in std_logic_vector(WIDTH - 1 downto 0);
S: in std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
D: out std_logic_vector(WIDTH - 1 downto 0)
);
end component logical_shift_n;
signal A: std_logic_vector(WIDTH - 1 downto 0) := "01001100";
signal S: std_logic_vector(integer(ceil(log2(real(WIDTH)))) - 1 downto 0);
signal D: std_logic_vector(WIDTH - 1 downto 0);
-- for IEEE Std 1076 revision less than 2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
UUT:
logical_shift_n
generic map ( WIDTH => WIDTH)
port map (
A => A,
S => S,
D => D
);
STIMULI:
process
begin
for i in 0 to 2 ** S'length - 1 loop
S <= std_logic_vector(to_unsigned(i, S'length));
wait for 5 ns;
report LF & HT &
"A = " & to_string(A) & LF & HT &
"S = " & to_string(S) & LF & HT &
"D = " & to_string(D);
wait for 5 ns;
end loop;
wait for 10 ns;
wait;
end process;
end architecture;
这会产生:
%: ghdl -r logical_shift_n_tb
logical_shift_n.vhdl:152:13:@5ns:(report note):
A = 01001100
S = 000
D = 01001100
logical_shift_n.vhdl:152:13:@15ns:(report note):
A = 01001100
S = 001
D = 10011000
logical_shift_n.vhdl:152:13:@25ns:(report note):
A = 01001100
S = 010
D = 00110000
logical_shift_n.vhdl:152:13:@35ns:(report note):
A = 01001100
S = 011
D = 01100000
logical_shift_n.vhdl:152:13:@45ns:(report note):
A = 01001100
S = 100
D = 11000000
logical_shift_n.vhdl:152:13:@55ns:(report note):
A = 01001100
S = 101
D = 10000000
logical_shift_n.vhdl:152:13:@65ns:(report note):
A = 01001100
S = 110
D = 00000000
logical_shift_n.vhdl:152:13:@75ns:(report note):
A = 01001100
S = 111
D = 00000000
%:
注意报告语句的格式取决于 VHDL 工具的实现。
更改代码的操作思路包括使用前一个“阶段”Y 作为多路复用器的未更改输入,第一个除外,它使用未更改的 A 输入。对于移位输入,函数 XSLL 是从 IEEE 包 numeric_std 的最早版本中窃取的,该包主体中的声明通过 use 子句不可见,该子句根据移位距离分配一个输出切片,覆盖输出值的一部分,该输出值具有初始值全部为“0”。对于每一级,D1(i) 的移位距离是 2 的 S 元素次方,除了从 A 派生的第一级之外。之后前一级的 Y 输出用于未移位的多路复用器输入,并且 D1(i) 值是通过移位 2 次方到距离而从前一级 Y 导出的。
测试平台只是一些拼凑在一起的东西,用于演示代码(具有多路复用器的独立实现)分析、详细说明和模拟,没有错误。
一般还有两种方法,递归实例化或递归子程序调用,其中泛型或参数可以定义“阶段”的数量,并在后续实例或调用中进行修改,直到不需要更多的转换。这些可以消除定义您自己的数组类型的需要。
这里,two_dim 类型是一种一维数组类型(它有一个索引),其元素类型是数组类型 (std_logic_vector)。
随便搜索一下,就发现没有返回整数值的标准包 log2 函数的来源。如果 A 的长度不是 2 的幂,则 A 会放入封装 ceil 函数调用中。如果移位距离超过 WIDTH - 1,则函数 XSLL 将返回全“0”,此处使用该函数来鼓励探索预先存在的包。