9.1 桶形移位寄存器
桶形移位寄存器的电路结构如下图所示。该电路包括3个独立的桶形移位器,左侧为第一级寄存器,只有1个‘0’连接到左下角的一个复用器上,第二级有2个‘0’,第三级有4个‘0’。对于位宽更高的矢量,将采用这种逐级加倍插入‘0’的方法来构造桶形移位寄存器。
---------------------桶形移位寄存器------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
-----------------------------------------------------------
ENTITY barrel IS
PORT(
inp : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
shift : IN STD_LOGIC_VECTOR(2 DOWNTO 0); --移动的位数,用二进制数表示
outp : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END barrel;
----------------------------------------------------------
ARCHITECTURE behavior OF barrel IS
BEGIN
PROCESS(inp,shift)
VARIABLE temp1 : STD_LOGIC_VECTOR(7 DOWNTO 0);
VARIABLE temp2 : STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
----------------------1st shifter-----------------
IF (shift(0) = '0') THEN
temp1 := inp;
ELSE
temp1(0) := '0';
FOR i IN 1 TO inp'HIGH LOOP
temp1(i) := inp(i-1);
END LOOP;
END IF;
----------------------2st shifter-----------------
IF (shift(1) = '0') THEN
temp2 := temp1;
ELSE
FOR i IN 0 TO 1 LOOP
temp2(i) := '0';
END LOOP;
FOR i IN 2 TO inp'HIGH LOOP
temp2(i) := temp1(i-2);
END LOOP;
END IF;
----------------------3st shifter----------------
IF (shift(2) = '0') THEN
outp <= temp2;
ELSE
FOR i IN 0 TO 3 LOOP
outp(i) <= '0';
END LOOP;
FOR i IN 4 TO inp'HIGH LOOP
outp(i) <= temp2(i-4);
END LOOP;
END IF;
END PROCESS;
END behavior;
9.2 逐级进位和超前进位加法器
逐级进位加法器
- 优点:需要较少的硬件资源
- 缺点:完成一次计算所需的时延较大(原因:每个全加器的输出结果都依赖于前一级产生的进位)
- 1位全加器FAU:a和b是输入位,cin是进位输入位,s是求和的结果,cout是进位输出位。当输入位有奇数个‘1’时,s必定是‘1’,而当有两个或更多的输入为‘1’时,cout必定是‘1’。逻辑表达式如下:
s=a XOR b XOR cin --a 异或 b:a和b不同时结果为1,反之为0
cout=(a AND b)OR(a AND cin)OR(b AND cin)
下图给出了一个4位无符号的逐级进位加法器,对每一位都使用了全加器FAU,同时给出了1位全加器的真值表。
---------------------4位无符号数的逐级进位加法器------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
-----------------------------------------------------------
ENTITY adder_cripple IS
GENERIC(
n : INTEGER :=4
);
PORT(
a : IN STD_LOGIC_VECTOR(n-1 DOWNTO 0);
b : IN STD_LOGIC_VECTOR(n-1 DOWNTO 0);
cin : IN STD_LOGIC;
s : OUT STD_LOGIC_VECTOR(n-1 DOWNTO 0);
cout : OUT STD_LOGIC
);
END adder_cripple;
----------------------------------------------------------
ARCHITECTURE adder OF adder_cripple IS
SIGNAL c : STD_LOGIC_VECTOR(n DOWNTO 0);
BEGIN
c(0) <= cin;
G1:FOR i IN 0 TO n-1 GENERATE
s(i) <= a(i) XOR b(i) XOR c(i);
c(i+1) <= (a(i) AND b(i)) OR
(a(i) AND c(i)) OR
(b(i) AND c(i));
END GENERATE;
cout <= c(n);
END adder;
- 注意:对于操作符中预定义的“+”操作符,加法器可以直接通过此操作符来实现,且此时综合工具一般会采用逐级进位加法器来实现目标电路。如果不希望采用这种方法,则必须在代码描述上清晰地体现出来。
超前进位加法器
- 优点:运行速度较快
- 缺点:硬件的复杂程度增加
- 运算原理:根据1位全加器的真值表有:
①\[{S_i} = \overline {
{A_i}} {B_i}\overline {
{C_i}} +{A_i}\overline {
{B_i}} \cdot \overline {
{C_i}} + \overline {
{A_i}} \cdot \overline {
{B_i}} {C_i} + {A_i}{B_i}{C_i} = \left( {
{A_i} \oplus{B_i}} \right)\overline {
{C_i}} + \overline {\left( {
{A_i} \oplus {B_i}}\right)} {C_i} = {A_i} \oplus {B_i} \oplus {C_i}\]
②\[{C_{i + 1}} = {A_i}{B_i}\overline {
{C_i}} + {A_i}{B_i}{C_i} + \overline {
{A_i}} {B_i}{C_i} + {A_i}\overline {
{B_i}} {C_i} = {A_i}{B_i} + \left( {
{A_i} \oplus {B_i}} \right){C_i}\]
此时令:进位产生信号(generate)\[{G_i} = {A_i} *{B_i}\],进位传递信号(propagate)\[{P_i} = {A_i}\oplus {B_i}\],则有\[{C_{i + 1}} ={G_i} + {P_i} * {C_i}\]。
另外,4位超前进位加法器的电路结构图如下所示:
现在假设有两个输入矢量:a=a(n-1)a(n-2)…a(1)a(0)和b=b(n-1)b(n-2)…b(1)b(0),那么相应的generate矢量为g=g(n-1)g(n-2)…g(1)g(0),相应的propagate矢量为p=p(n-1)p(n-2)…p(1)p(0)。其中
g(j) = a(j) AND b(j)
p(j) = a(j) XOR b(j)
现在假设进位矢量c=c(n)c(n-1)c(n-2)…c(1)c(0)且\[{C_{i + 1}} ={C_i} * {P_i} + {G_i}\], 即有:
c(0) = cin
c(1) = c(0)p(0)+g(0)
c(2) = c(1)p(1)+g(1) = (c(0)p(0)+g(0))p(1)+g(1) = c(0)p(0)p(1)+g(0)p(1)+g(1)
c(3) = c(2)p(2)+g(2) = (c(0)p(0)p(1)+g(0)p(1)+g(1))p(2)+g(2) = c(0)p(0)p(1)p(2)+g(0)p(1)p(2)+g(1)p(2)+g(2)
c(4) = c(3)p(3)+g(3) = (c(0)p(0)p(1)p(2)+g(0)p(1)p(2)+g(1)p(2)+g(2))p(3)+g(3)
= c(0)p(0)p(1)p(2)p(3)+g(0)p(1)p(2)p(3)+g(1)p(2)p(3)+g(2)p(3)+g(3),等等。
注意:上面的表达式没有一个取决于前级进位输出的计算结果,这是超前进位加法器电路执行速度快的根本原因。另一方面,这种方式会使硬件电路的复杂程度增加,所以只能用于实现位数不是很多的加法器(如4位),位宽更高的超前进位加法器就需要将上述小规模电路组合起来了。
4位超前进位加法器:
-----------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
-----------------------------------------------------------
ENTITY CLA_Adder 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);
cout: OUT STD_LOGIC
);
END CLA_Adder;
-----------------------------------------------------------
ARCHITECTURE CLA_Adder OF CLA_Adder IS
SIGNAL c: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL p: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL g: STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
---------------------PGU:------------------------------
G1: FOR i IN 0 TO 3 GENERATE
p(i) <= a(i) XOR b(i); --异或
g(i) <= a(i) AND b(i);
s(i) <= p(i) XOR c(i);
END GENERATE;
---------------------CLAU:-----------------------------
c(0) <= cin;
c(1) <= (cin AND p(0)) OR
g(0);
c(2) <= (cin AND p(0) AND p(1)) OR
(g(0) AND p(1)) OR
g(1);
c(3) <= (cin AND p(0) AND p(1) AND p(2)) OR
(g(0) AND p(1) AND p(2)) OR
(g(1) AND p(2)) OR
g(2);
c(4) <= (cin AND p(0) AND p(1) AND p(2) AND p(3)) OR
(g(0) AND p(1) AND p(2) AND p(3)) OR
(g(1) AND p(2) AND p(3)) OR
(g(2) AND p(3)) OR
g(3);
cout <= c(4);
END CLA_Adder;
-----------------------------------------------------------
9.3 定点除法
注意:预定义运算符“/”只能进行2^n类型的除法运算,其运算本质实际上就是移位操作。
除法电路的算法
假设要计算 y=a/b,其中a>b ,且a是 n 位二进制数。假设:a=“1011”,b=“0011”(这里左边可补0可不补0),改除法运算的结果是y=“0011”和余数“0010”.该除法算法如下表:
索引i | 与a相关的输入a_inp(i) | 比较 | 与b相关的输入b_inp(i) | 商y(i) | 操作 |
3 | 1011 | < | 0011000 | 0 | none |
2 | 1011 | < | 0001100 | 0 | none |
1 | 1011 | > | 0000110 | 1 | a_inp(0)=a_inp(1)-b_inp(1) |
0 | 0101 | > | 0000011 | 1 | rem=a_inp(0)-b_inp(0) |
0010(rem) |
对于除法运算有:
①i 的范围为 (n-1 downto 0);
②b_inp(i) 为b 左移 i 位,低位补零;
③与a相关的输入中,a_inp(n-1) = a,另有
,
其中余数 rem=a_inp(-1) 且遵循上述等式;
④商
。
VHDL除法器:
-----------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-----------------------------------------------------------
entity divider is
generic(n: integer := 4);
port(
a: in integer range 0 to 15;
b: in integer range 0 to 15;
y: out std_logic_vector( n-1 downto 0 );
rest: out integer range 0 to 15;
err: out std_logic
);
end divider;
-----------------------------------------------------------
architecture rtl of divider is
begin
process (a,b) --“process”中为顺序描述
variable temp1: integer range 0 to 15;
variable temp2: integer range 0 to 15;
begin
--------------Error and initialization-------------
temp1 := a;
temp2 := b;
if (b = 0) then
err <= '1';
else
err <= '0';
end if;
-------------------------y:------------------------
for i in n-1 downto 0 loop
if (temp1 >= temp2*2**i) then
y(i) <= '1';
temp1 := temp2*2**i;
else
y(i) <= '0';
end if;
end loop;
----------------------Remainder--------------------
rest <= temp1;
end process;
end rtl;
9.4 串行数据接收器
串行数据接收器如下图所示,包括时钟信号(clk)、复位信号(rst)、串行数据输入端口(din)和并行数据输出端口(data),以及产生了两个指示信号:err(错误指示信号)和data_valid(有效数据指示信号)。
输入信号是一个字符流。每个完整的字符包含10位,第1位是起始位,当其为高时标志一个字符的开始,电路开始接受后面的数据。
- 判断方法:reg(0)=‘1’。
接下来的7位是有效数据,第9位是奇偶校验位,当数据中1的个数是偶数时其值应该为‘0’,奇数时则为‘1’。
- 判断方法:
统计有效数据的奇偶位数 temp0 = reg(1) XOR reg(2) XOR reg(3) XOR reg(4) XOR reg(5) XOR reg(6) XOR reg(7)
上式中异或 XOR的作用:不同(奇数)为‘1’,相同(偶数)为‘0’。
奇偶位数与奇偶校验位比较 temp1 = temp0 XOR reg(8)
上式中异或 XOR的作用:不同为‘1’(错误),相同为‘0’(正确)。
第10位是终止位,如果传输正确,其值应该为‘1’,且当接收电路发现奇偶校验错误或结束位不是‘1’时将发出错误指示。
- 判断方法:temp2 = temp1 OR ( NOT reg(9) ),表示“有‘1’为‘1’”。
当数据接收正确时,存储在内部寄存器中的数据并行输出data,同时data_valid有效。
-----------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-----------------------------------------------------------
entity receiver is
port(
clk: in bit;
rst: in bit;
din: in bit;
data: out bit_vector(6 downto 0);
err: out bit;
data_vaild: out bit
);
end receiver;
-----------------------------------------------------------
architecture rtl of receiver is
begin
process(clk,rst)
variable count: integer range 0 to 10;
variable reg: bit_vector(9 downto 0);
variable temp: bit;
begin
if rst = '0' then
count := 0;
reg := (reg'range => '0');
-- reg := (others => '0');
-- reg := "0000000000";
temp := '0';
err <= '0';
data_vaild <= '0';
elsif clk'event and clk = '1' then
if (reg(0) = '0' and din = '1') then
reg(0) := '1';
elsif reg(0) = '1' then
count := count+1;
if count<10 then
reg(count) := din;
elsif count=10 then
temp := (reg(1) xor reg(2) xor reg(3) xor --优先级:not>or>xor
reg(4) xor reg(5) xor reg(6) xor
reg(7) xor reg(8)) or not reg(9);
err <= temp;
count := 0;
reg(0) := din;
if temp = '0' then
data <= reg(7 downto 1); --在没有新的有效数据输入之前,输出数据始终保持为原来的值。
data_vaild <= '1'; --在第一次有效数据输入后,数据有效指示信号变为高,后面一直为高。
end if;
end if;
end if;
end if;
end process;
end rtl;
9.5 并/串变换器
并/串变换器是一个使用移位寄存器的典型例子,作用是将并行的数据块以串联的方式连续输出。
转换器的电路结构如下图所示。当load有效时,并行输入数据d(7:0)被同步储存在移位寄存器中,且当load保持为高时,MSB即d(7)在输出端始终保持有效。一旦load返回‘0’,接下来移位寄存器的各个位将在每个时钟上升沿依次出现在输出端口dout上,8位数据全部发送完毕后,输出端在下一次数据传输之前一直保持低电平。
---------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
---------------------------------------------------------
entity serial_converter is
port(
clk: in std_logic;
load: in std_logic;
d: in std_logic_vector(7 downto 0);
dout: out std_logic
);
end serial_converter;
---------------------------------------------------------
architecture serial_converter of serial_converter is
signal reg: std_logic_vector(7 downto 0);
begin
process(clk,load)
begin
if clk'event and clk = '1' then
if load = '1' then
reg <= d;
else
reg <= reg(6 downto 0)&'0';
end if;
end if;
end process;
dout <= reg(7);
end serial_converter;
---------------------------------------------------------
9.6 一个7段显示器的应用例题
利用SSD(seven-segment display,7段显示器)来设计一个小游戏,其中电路的顶层结构如下图所示,包括两个输入信号(clk和stop)和一个输出信号(dout(6:0)),输出信号连接到SSD上且分别对应着a~g。
所设计的电路要求如下:SSD的各个段(除去g段)连续地按照顺时针方向转动,为了使循环运动的视觉效应更连贯,相邻两端在点亮的时间上略微重叠。因此,点亮的次序应该是a-ab-b-bc-c-cd-d-de-e-ef-f-fa-a,其中系统在a、b、c等状态停留时间time1较长,在ab、bc、cd等状态停留时间time2较短。另外,如果stop为‘1’,则电路返回状态a,并在stop变低之前一直保持。状态图如下:
--------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
--------------------------------------------------------------
entity ssd_game2 is
port(
clk: in bit;
stop: in bit;
dout: out bit_vector(6 downto 0)
);
end ssd_game2;
--------------------------------------------------------------
architecture fsm of ssd_game2 is
constant time1: integer := 4;
constant time2: integer := 2;
type states is (a,ab,b,bc,c,cd,d,de,e,ef,f,fa);
signal present_state, next_state: states;
signal count: integer range 0 to time1;
signal flip: bit; --通过该信号来指出计数器该计数到time1还是time2
begin
-------------------Lower section of FSM-------------------
process(clk,stop)
begin
if stop = '1' then
present_state <= a;
elsif clk'event and clk = '1' then
if (flip = '1' and count = time1) or
(flip = '0' and count = time2) then --根据不同的计数器确定不同状态保持的时长
count <= 0;
present_state <= next_state;
else
count <= count+1;
end if;
end if;
end process;
-------------------Upper section of FSM-------------------
process(present_state)
begin
case present_state is
when a =>
dout <= "1000000"; --LSB即g段始终为'0',不亮
flip <= '1';
next_state <= ab;
when ab =>
dout <= "1100000";
flip <= '0';
next_state <= b;
when b =>
dout <= "0100000";
flip <= '1';
next_state <= bc;
when bc =>
dout <= "0110000";
flip <= '0';
next_state <= c;
when c =>
dout <= "0010000";
flip <= '1';
next_state <= cd;
when cd =>
dout <= "0011000";
flip <= '0';
next_state <= d;
when d =>
dout <= "0001000";
flip <= '1';
next_state <= de;
when de =>
dout <= "0001100";
flip <= '0';
next_state <= e;
when e =>
dout <= "0000100";
flip <= '1';
next_state <= ef;
when ef =>
dout <= "0000110";
flip <= '0';
next_state <= f;
when f =>
dout <= "0000010";
flip <= '1';
next_state <= fa;
when fa =>
dout <= "1000010";
flip <= '0';
next_state <= a;
end case;
end process;
end fsm;
9.7 信号发生器
要求如下图所示:
实现该电路需要4个寄存器,其中3个用于计数器,另外1个用于波形输出。
采用FSM进行设计
----------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
----------------------------------------------------------------------
entity signal_gen is
port(
clk: in std_logic;
wave: out std_logic
);
end signal_gen;
----------------------------------------------------------------------
architecture fsm of signal_gen is
type states is (zero, one, two, three, four, five,
six, seven);
signal present_state, next_state: states;
signal temp: std_logic;
begin
---------------------Lower section of FSM:------------------------
process(clk)
begin
if clk'event and clk = '1' then
present_state <= next_state;
wave <= temp; --采用状态机设计风格#2,在上升沿将寄存器的值输出,
end if; --因为在信号发生器中不允许出现毛刺。
end process;
---------------------Upper section of FSM:------------------------
process(present_state)
begin
case present_state is
when zero =>
temp <= '0';
next_state <= one;
when one =>
temp <= '1';
next_state <= two;
when two =>
temp <= '0';
next_state <= three;
when three =>
temp <= '1';
next_state <= four;
when four =>
temp <= '1';
next_state <= five;
when five =>
temp <= '1';
next_state <= six;
when six =>
temp <= '0';
next_state <= seven;
when seven =>
temp <= '0';
next_state <= zero;
end case;
end process;
end fsm;
------------------------------------------------------------------------
采用传统方法进行设计
-----------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-----------------------------------------------------------------------------------------
entity signal_gen1 is
port(
clk: in std_logic;
wave: out std_logic
);
end signal_gen1;
------------------------------------------------------------------------------------------
architecture arch1 of signal_gen1 is
begin
process
variable count: integer range 0 to 7;
begin
wait until clk'event and clk = '1';
case count is
when 0 => wave <= '0';
when 1 => wave <= '1';
when 2 => wave <= '0';
when 3 => wave <= '1';
when 4 => wave <= '1';
when 5 => wave <= '1';
when 6 => wave <= '0';
when 7 => wave <= '0';
end case;
count := count + 1;
end process;
end arch1;
--------------------------------------------------------------------------------------------
--由于在使用wait until语句时,process没有敏感信号列表,所以其必须是process中的第一条语句;
--wait until语句后面只有一个信号条件表达式,更适合用于实现同步电路;
--当wait until语句的条件满足时,process内部的代码就执行一遍。
--------------------------------------------------------------------------------------------
9.10 存储器设计
ROM(只读存储器)
ROM的原型结构图如下:
因为它是只读存储器,所以不需要时钟和写使能信号,且电路内部包括预先储存的内容,并且由输入的地址(addr)来选择将哪个存储空间中的内容传送给输出端。
实现该ROM时,由于没有使用时钟信号,所以没有占用寄存器资源。ROM是通过使用逻辑门构成查找表(LUT: Look Up Table)的方式来实现的。
-------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-------------------------------------------------------------------
entity rom is
generic(
bits: integer := 8; --# of bits per word
words: integer := 8 --# of words in the memory
);
port(
addr: in integer range 0 to words-1;
data: out std_logic_vector(bits-1 downto 0)
);
end rom;
-------------------------------------------------------------------
architecture rom of rom is
type vector_array is array (0 to words-1) of
std_logic_vector (bits-1 downto 0);
constant memory: vector_array := ("00000000",
"00000010",
"00000100",
"00001000",
"00010000",
"00100000",
"01000000",
"10000000");
begin
data <= memory(addr);
end rom;
-------------------------------------------------------------------
输入/输出数据总线分离的RAM
具有独立输入/输出数据总线的RAM(随机存储器)的结构如下:
如果写使能信号(wr_ena)有效,在一个时钟上升沿出现时,data_in上的数据将被存储到地址总线(addr)所选择的位置上。另外,data_out上始终显示当前地址总线(addr)所选择的存储单元中的内容。
----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
----------------------------------------------------------------
entity ram is
generic(
bits: integer := 8; -- #每字的字宽
words: integer := 16 -- #储存器中的字数
);
port(
clk: in std_logic;
wr_ena: in std_logic;
addr: in integer range 0 to words-1;
data_in: in std_logic_vector(bits-1 downto 0);
data_out: out std_logic_vector(bits-1 downto 0)
);
end ram;
----------------------------------------------------------------
architecture ram of ram is
type vector_array is array (0 to words-1) of
std_logic_vector (bits-1 downto 0);
signal memory: vector_array;
begin
process(clk,wr_ena)
begin
if wr_ena = '1' then
if clk'event and clk = '1' then
memory(addr) <= data_in;
end if;
end if;
end process;
data_out <= memory(addr);
end ram;
-----------------------------------------------------------------
具有双向I/O数据总线的RAM
总体结构如下图所示:
工作原理:当wr_ena为低时,寄存器的输出与它的输入相连,同时总线处于数据输出状态,相应地址选择的数据被输出到总线上。当wr_ena有效时,数据总线上的数据直接与d连接,在下一个始终周期的上升沿到达时,数据被写入到寄存器中。
----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
----------------------------------------------------------------
entity ram4 is
generic(
bits: integer := 8; -- #每字的字宽
words: integer := 16 -- #储存器中的字数
);
port(
clk: in std_logic;
wr_ena: in std_logic;
addr: in integer range 0 to words-1;
bidir: inout std_logic_vector(bits-1 downto 0)
);
end ram4;
----------------------------------------------------------------
architecture ram of ram4 is
type vector_array is array (0 to words-1) of
std_logic_vector (bits-1 downto 0);
signal memory: vector_array;
begin
process(clk,wr_ena)
begin
if wr_ena = '0' then
bidir <= memory(addr);
else
-- bidir <= (others => 'z');
if clk'event and clk = '1' then
memory(addr) <= bidir;
end if;
end if;
end process;
end ram;
-----------------------------------------------------------------
今天的文章《VHDL 数字电路设计教程》电工版/第9章:典型电路设计分析分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/12937.html