学习日志之VHDL
implementation of pentium4 adder
structure
The adder of pentium4 can be divided into two part. The first part is the carry generator another is sum generator.The carry generator is only responsible for the generation of carry bit. And these carry bit can be used to select the result generated by the sum generator.
This structure is used to solve the problem that the carry in ripple carry adder genrated asynchronously. In this scenario, the carry bit on high bit is much slower than low bits. with the implementation of this algorithm, carry bits and sum bits can be generated at the same time. In this way, we could avoid the delay produced by transmiting the result of carry generated by previous 1 bit full adder.
implementation step
To describe the detail of its logic we choose implement it in structure level.
ripple carry adder
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity RCA is
generic (DRCAS : Time := 0 ns;
DRCAC : Time := 0 ns);
Port ( A: In std_logic_vector(3 downto 0);
B: In std_logic_vector(3 downto 0);
Ci: In std_logic;
S: Out std_logic_vector(3 downto 0);
Co: Out std_logic);
end RCA;
architecture STRUCTURAL of RCA is
signal STMP : std_logic_vector(3 downto 0);
signal CTMP : std_logic_vector(4 downto 0);
component FA
generic (DFAS : Time := 0 ns;
DFAC : Time := 0 ns);
Port ( A: In std_logic;
B: In std_logic;
Ci: In std_logic;
S: Out std_logic;
Co: Out std_logic);
end component;
begin
CTMP(0) <= Ci;
S <= STMP;
Co <= CTMP(4);
ADDER1: for I in 1 to 4 generate
FAI : FA
generic map (DFAS => DRCAS, DFAC => DRCAC)
Port Map (A(I-1), B(I-1), CTMP(I-1), STMP(I-1), CTMP(I));
end generate;
end STRUCTURAL;
configuration CFG_RCA_STRUCTURAL of RCA is
for STRUCTURAL
for ADDER1
for all : FA
use configuration WORK.CFG_FA_BEHAVIORAL;
end for;
end for;
end for;
end CFG_RCA_STRUCTURAL;
sum generator
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity sum_gen is
Port (
c_sel: in std_logic_vector(7 downto 0);
a_o,b_o: in std_logic_vector(31 downto 0);
s_o: out std_logic_vector(31 downto 0)
);
end sum_gen;
architecture str of sum_gen is
component carry_select_block is
port (
a : in STD_LOGIC_VECTOR (3 downto 0);
b : in STD_LOGIC_VECTOR (3 downto 0);
cin : in STD_LOGIC;
s : out STD_LOGIC_VECTOR (3 downto 0)
);
end component;
signal a_s0,a_s1,a_s2,a_s3,a_s4,a_s5,a_s6,a_s7: STD_LOGIC_VECTOR (3 downto 0);
signal b_s0,b_s1,b_s2,b_s3,b_s4,b_s5,b_s6,b_s7: STD_LOGIC_VECTOR (3 downto 0);
signal s_s0,s_s1,s_s2,s_s3,s_s4,s_s5,s_s6,s_s7: STD_LOGIC_VECTOR (3 downto 0);
begin
a_s0<=a_o(3 downto 0);
b_s0<=b_o(3 downto 0);
a_s1<=a_o(7 downto 4);
b_s1<=b_o(7 downto 4);
a_s2<=a_o(11 downto 8);
b_s2<=b_o(11 downto 8);
a_s3<=a_o(15 downto 12);
b_s3<=b_o(15 downto 12);
a_s4<=a_o(19 downto 16);
b_s4<=b_o(19 downto 16);
a_s5<=a_o(23 downto 20);
b_s5<=b_o(23 downto 20);
a_s6<=a_o(27 downto 24);
b_s6<=b_o(27 downto 24);
a_s7<=a_o(31 downto 28);
b_s7<=b_o(31 downto 28);
block0: carry_select_block port map(a_s0,b_s0,c_sel(0),s_s0);
block1: carry_select_block port map(a_s1,b_s1,c_sel(1),s_s1);
block2: carry_select_block port map(a_s2,b_s2,c_sel(2),s_s2);
block3: carry_select_block port map(a_s3,b_s3,c_sel(3),s_s3);
block4: carry_select_block port map(a_s4,b_s4,c_sel(4),s_s4);
block5: carry_select_block port map(a_s5,b_s5,c_sel(5),s_s5);
block6: carry_select_block port map(a_s6,b_s6,c_sel(6),s_s6);
block7: carry_select_block port map(a_s7,b_s7,c_sel(7),s_s7);
s_o<=s_s0 & s_s1 & s_s2 & s_s3 & s_s4 & s_s5 & s_s6 & s_s7;
end str;
carry generator
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity carry_gen is
Port (
a: in std_logic_vector(31 downto 0);
b: in std_logic_vector(31 downto 0);
c: out std_logic_vector(7 downto 0)
);
end carry_gen;
architecture str of carry_gen is
component PG_unit is
port(
a,b: in std_logic;
p,g: out std_logic
);
end component;
type level1 is array (15 downto 0) of std_logic;
signal g1: level1;
signal p1: level1;
type level2 is array (7 downto 0) of std_logic;
signal g2: level2;
signal p2: level2;
type level3 is array (4 downto 0) of std_logic;
signal g3: level3;
signal p3: level3;
type level4 is array (4 downto 0) of std_logic;
signal g4: level4;
signal p4: level4;
type level5 is array (4 downto 0) of std_logic;
signal g5: level5;
signal p5: level5;
begin
level_1: for i in 0 to 15 generate
p1(i)<=a(i) xor b(i);
g1(i)<=a(i) and b(i);
end generate;
level_2: for i in 0 to 7 generate
p2(i)<=p1(2*i) and p1(2*i+1);
g2(i)<=(g1(2*i) and p1(2*i+1)) or g1(2*i+1);
end generate;
level_3: for i in 0 to 3 generate
p3(i)<=p2(2*i) and p2(2*i+1);
g3(i)<=(g2(2*i) and p2(2*i+1)) or g2(2*i+1);
end generate;
level_4_odd: for i in 0 to 1 generate
p4(i*2+1)<=p3(2*i) and p3(2*i+1);
g4(i*2+1)<=g3(2*i+1) and (g3(2*i) or p3(2*i+1));
end generate;
level_4_even: for i in 0 to 1 generate
p3(i*2)<=p2(2*i) and p1(2*(2*i+1));
g3(i*2)<=g1(2*(2*i+1)) and (g2(2*i) or p1(2*(2*i+1)));
end generate;
level_5:
g5(0)<=(g4(1) and p2(4)) or g2(4);
g5(1)<=(g4(1) and p3(2)) or g3(2);
g5(2)<=(g4(1) and p4(2)) or g4(2);
g5(3)<=(g4(1) and p4(3)) or g4(3);
c<=g5(3)&g5(2)&g5(1)&g5(0)&g4(1)&g4(0)&g3(0)&g2(0);
end str;
the complete P4 adder
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity p4_adder is
Port ( a : in STD_LOGIC_VECTOR (31 downto 0);
b : in STD_LOGIC_VECTOR (31 downto 0);
s : out STD_LOGIC_VECTOR (31 downto 0));
end p4_adder;
architecture str of p4_adder is
component sum_gen is
Port (
c_sel: in std_logic_vector(7 downto 0);
a_o,b_o: in std_logic_vector(31 downto 0);
s_o: out std_logic_vector(31 downto 0)
);
end component;
component carry_gen is
Port (
a: in std_logic_vector(31 downto 0);
b: in std_logic_vector(31 downto 0);
c: out std_logic_vector(7 downto 0)
);
end component;
signal c_s: std_logic_vector(7 downto 0);
begin
carry: carry_gen port map(a,b,c_s);
sum: sum_gen port map(c_s,a,b,s);
end str;
some notes about VHDL
about configuration
This kind of sentence is usually used in huge and complex design with many different architecture to specify which architecture is in need. It usually appears in the process of simulation, which means you have to define a configuration at the end of your testbench.
the format of configuration is as below:
configuration 配置名 of 实体名 is
配置说明
end 配置名;
the point of its usage are as following :
- every entity with multiple architectures should declare all of the architecture at the end in configuration sentence.
- if there are some other entities which decide to use this entity to describe its function in structure level, you should make a choice in the 配置说明 of configuration block.
e.g.
--file NO.1
entity one is
port(...);
end one;
architecture method1 of one is
begin
...
end architecture;
architecture method2 of one is
begin
...
end architecture;
...
configuration one_config of one is
for method1
end for;
end one_config;
configuration two_config of one is
for method2
end for;
end one_config;
--file NO.2
entity two is
port(...);
end one;
architecture str of two is
begin
...
end architecture
configuration config of two is
for str
use configuration WORK.two_config;
end for;
end config;
generate statement
Generate statement is used to generate structure with similar form. And this statement can reduce the length of our VHDL code.
The format of this statement is as below:
标签: for 循环控制变量 in 循环变量取值范围 generate
...--需要进行的操作和生成的结构
end generate
循环控制变量 is a parameter which also can be used in the body of loop. It doesn’t need to be defined in advance. And it can be used simultainously in other loops.
循环变量取值范围 is usually defined with the form like (低位 to 高位)or (高位 downto 低位)
e.g.
label: for i in (0 to 15) generate
mux: mux port map (a,b,s,o);
end generate;
about port assignment of parameters in port map
During the process of coding we meet a problem about parameter assignment. My idea is that assign a part of a long vector to a parameter in the port map with identical bits. But it seems VHDL doesn’t allow us to do it directly. The correct way to do this is as below.
signal a_s: std_logic_vector(7 downto 0);
...
carry: carry_gen port map(a=>a_s(3 downto 0),b,c_s);
Generate an array type and array
In VHDL, there isn’t like the language like C or Python. if you wanna define an array, you have to define an array type in advance. But the synthizer only support the vector with 1 dimensional. but actually you can define an array with 2 dimensional. There are 2 different scenarios when we define an array type:
- with constrain on the range of suffix
- without constrain on the range of suffix
in the first scenario, we can use format as is shown below
TYPE 数组名IS ARRAY (数组范围)OF 数据类型;
and for the second scenario, there is a symbol <> which means you don’t want to confirm the range of this array now, but you have to confirm it when you wanna define an array in this type.
TYPE 数组名IS ARRAY (数组下标名 RANGE <>)OF 数据类型
e.g.
TYPE Bit_Vector IS Array (Natural Range <>)OF BIT;
...
VARIABLE va:Bit_Vector (1 to 6);
and the first scenario is the same.