chapter 10
10.16. 二进制加法。实现两个十六进制数相加 2A + 3C
2A + 3C == 66Hex = 102Dec
10.18. 位计数电路。用全加器设计一个电路,接受一个7位输入,输出一个表示输入中1的个数的3位二进制数。
设计思路:从输入的低位开始扫描序列,设计的全加器为3位,将输入的每一位的高2位补0,并与上一次输入的结果一同输入到一个新的全加器中,若该位为1则结果加1,若该位为0则结果不变,这样最终累加的结果将保存再ypp(6)中,ypp是一个二维数组。
仿真结果图所示,当输入为9时,即 0001001,其中1的个数为2,输出结果y也为2,符合设计要求,其他的输入也同样符合要求,可知设计正确。
代码如下所示。其中FA是加法器,count1是技术电路,count_test是计数电路。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity FA is
generic(n: integer := 8);
port (
a,b: in std_logic_vector(n-1 downto 0);
cin: in std_logic;
cout: out std_logic;
s:out std_logic_vector(n -1 downto 0)
) ;
end FA;
architecture impl of FA is
signal sum: std_logic_vector(n downto 0);
begin
sum <= ('0' & a) + ('0' & b) + cin;
cout <= sum(n);
s <= sum(n-1 downto 0);
end impl ; -- impl
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity count1 is
port (
a: in std_logic_vector(6 downto 0);
y: out std_logic_vector(2 downto 0)
) ;
end count1;
architecture impl of count1 is
type PartialP is array(6 downto 0) of std_logic_vector ( 2 downto 0);
signal ypp : PartialP;
signal cout: std_logic;
signal xin: PartialP;
begin
xin(0) <= "00" & a(0);
d0: entity work.FA generic map(3) port map(xin(0), "000", '0',cout, ypp(0));
xin(1) <= "00" & a(1);
d1: entity work.FA generic map(3) port map(xin(1), ypp(0), '0',cout, ypp(1));
xin(2) <= "00" & a(2);
d2: entity work.FA generic map(3) port map(xin(2), ypp(1), '0',cout, ypp(2));
xin(3) <= "00" & a(3);
d3: entity work.FA generic map(3) port map(xin(3), ypp(2), '0',cout, ypp(3));
xin(4) <= "00" & a(4);
d4: entity work.FA generic map(3) port map(xin(4), ypp(3), '0',cout, ypp(4));
xin(5) <= "00" & a(5);
d5: entity work.FA generic map(3) port map(xin(5), ypp(4), '0',cout, ypp(5));
xin(6) <= "00" & a(6);
d6: entity work.FA generic map(3) port map(xin(6), ypp(5), '0',cout, ypp(6));
y <= ypp(6);
end impl ; -- impl
--pragma translate_off
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity count_test is
end count_test;
architecture impl of count_test is
signal a: std_logic_vector(6 downto 0);
signal y: std_logic_vector(2 downto 0);
begin
p1: entity work.count1 port map(a, y);
process begin
for i in 0 to 2**7 - 1 loop
a <= std_logic_vector(to_unsigned(i, 7));
wait for 10 ns;
end loop;
end process;
end impl ; -- test
--pragma translate_on
10.20. 饱和加法器设计。在一些应用中,特别是信号处理中,希望加法器饱和,再溢出状态下产生2n-1 的结果,而不是模运算后的结果。设计一个饱和加法器,可以使用n位加法器和n位多路复用器作为基本器件
饱和加法器,当正向溢出的时候输出输出最大正数,当负向溢出的时候输出最小负数。分析可知,当符号位进位为’1‘,数据最高位进位为‘0‘时发生负向溢出,即两个负数相加超出最小负数表示范围,当符号进位为’0‘且数据最高位进位为’1‘时,发生正向溢出,即两个正数相加超过最大正数表示范围。
因此可以改造全加器,当发生正向溢出时符号位设置为’0‘,数据位全设置为‘1’,表示最大正数;当发生负向溢出时,符号位设置为‘1’,数据位全设置为‘0’表示最小负数
仿真结果如下所示,设计的前20ns位两组特殊的数据,前10ns为 1000 + 1010 发生负向溢出,应该输出1000,仿真结果符合预期,10-20ns输入为0111+ 0010,为正向溢出,输出结果为0111,符合预期,之后输入a从0010开始每隔40ns加1,输入b从0001开始每隔10ns加1,通过观察发现,输出的结果也是符合预期,说明设计正确。
代码如下所示
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity fulladd is
generic(N: integer := 8);
port (
a,b: in std_logic_vector(n-1 downto 0);
sub: in std_logic;
s: out std_logic_vector(n-1 downto 0);
ovf: out std_logic
) ;
end fulladd;
architecture impl of fulladd is
signal c1, c2: std_logic;
signal c1n: std_logic_vector(n-1 downto 0);
signal c2s: std_logic_vector(1 downto 0);
begin
ovf <= c1 xor c2;
c1n <= ('0' & a(n-2 downto 0)) + ('0' & (b(n -2 downto 0) xor (n-2 downto 0 => sub))) + sub;
-- s(n-2 downto 0) <= c1n(n-2 downto 0);
c1 <= c1n(n - 1);
c2s <= ('0' & a(n-1)) + ('0' & (b(n - 1) xor sub)) + c1;
-- s(n - 1) <= c2s(0);
c2 <= c2s(1);
s(n - 2 downto 0) <= (n-2 downto 0 => '1') when c1 = '1' and c2 = '0'
else (n-2 downto 0 => '0') when c2 = '1' and c1 = '0'
else c1n(n -2 downto 0);
s(n - 1) <= '0' when c1 = '1' and c2 = '0'
else '1' when c2 = '1' and c1 = '0'
else c2s(0);
end impl ; -- impl
--pragma translate_off
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity fulladd_test is
end fulladd_test;
architecture impl of fulladd_test is
signal a: std_logic_vector(3 downto 0);
signal b: std_logic_vector(3 downto 0);
signal y: std_logic_vector(3 downto 0);
signal ovf: std_logic;
begin
p1: entity work.fulladd generic map(4) port map(a, b, '0', y, ovf);
process begin
a <= "1000";
b <= "1010";
wait for 10 ns;
a <= "0111";
b <= "0010";
wait for 10 ns;
for i in 2 to 2**4 -1 loop
a <= std_logic_vector(to_unsigned(i, 4));
for j in 1 to 2**4 -1 loop
b <= std_logic_vector(to_unsigned(j, 4));
wait for 10 ns;
end loop;
end loop;
end process;
end impl ; -- test
--pragma translate_on
10.44. 倍5电路。使用加法器,组合构建块和门,设计一个接收4位基2补码二进制输入a(3 downto 0)的电路,并输入一个7位基2补码输出b(6 downto 0),输出是输入的5倍。不能使用乘法器,使用尽可能少的加法器。
设计思路:将输入左移两位,得到原输入的四倍,在使用一个加法器加上原来输入元素,得到原输入的五倍,需要注意的是,输入的是基2的补码,最高位表示符号位,在左移两位后需要对原数据进行符号扩展。
如下所示,当输入由0000-0111时,输入为正数,输出直接扩大五倍,当输入为1000时,表示的时-8,输出为58Hex 转换为十进制的数为-40,符合题意,同理验证其他复数也符合5倍的要求,可知电路设计正确。
设计代码如下所示
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity addsub is
generic(N: integer := 8);
port (
a,b: in std_logic_vector(n-1 downto 0);
sub: in std_logic;
s: out std_logic_vector(n-1 downto 0);
ovf: out std_logic
) ;
end addsub;
architecture impl of addsub is
signal c1, c2: std_logic;
signal c1n: std_logic_vector(n-1 downto 0);
signal c2s: std_logic_vector(1 downto 0);
begin
ovf <= c1 xor c2;
c1n <= ('0' & a(n-2 downto 0)) + ('0' & (b(n -2 downto 0) xor (n-2 downto 0 => sub))) + sub;
s(n-2 downto 0) <= c1n(n-2 downto 0);
c1 <= c1n(n - 1);
c2s <= ('0' & a(n-1)) + ('0' & (b(n - 1) xor sub)) + c1;
s(n - 1) <= c2s(0);
c2 <= c2s(1);
end impl ; -- impl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fives is
port (
num: in std_logic_vector(3 downto 0);
y: out std_logic_vector(6 downto 0)
) ;
end fives;
architecture impl of fives is
signal num_sll_2, num_temp: std_logic_vector(6 downto 0) := "0000000";
signal ovf: std_logic;
begin
num_temp <= "111" & num when num(3) = '1' else "000" & num ;
num_sll_2(5 downto 0) <= num & "00";
num_sll_2(6) <= '1' when num(3) = '1' else '0';
e0: entity work.addsub generic map(7) port map(num_temp, num_sll_2, '0', y, ovf);
end impl ; -- impl
--pragma translate_off
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity fives_test is
end fives_test;
architecture impl of fives_test is
signal a: std_logic_vector(3 downto 0);
signal y: std_logic_vector(6 downto 0);
begin
p1: entity work.fives port map(a, y);
process begin
for i in 0 to 2**4 - 1 loop
a <= std_logic_vector(to_unsigned(i, 4));
wait for 10 ns;
end loop;
end process;
end impl ; -- test
--pragma translate_on
chapter 11
11.6. 定点数表示。将0.3775转化到最近的s1.5格式定点数表示,给出绝对跟相对误差
0.3775 * 25 = 12.08 ≈ 12 = 01100
转为s1.5的形式为0.01100 = 0.375
绝对误差 = | 0.375 - 0.3775 | = 0.0025
相对误差为(0.3775 - 0.375) / 0.3775 = 0.0066
11.11. 选择定点表示方案。以0.1PSI的精度表示一个范围从-10PSI到10PSI的相对压力信号。选择一个指定精度的并且以最少位数覆盖此范围的定点表示方法
由于2-4 < 0.1 所以小数部分可以用四位二进制表示,由于要表示正负数,需要一位符号位,整数位可以用4位二进制数表示,因此最终表示格式位9位:s4.4
11.18. 浮点表示。将100 000转化成偏移量为8,格式为s3E5的浮点数,并给出相对误差跟绝对误差
s3E5从左到右为1位符号,5位指数,3位小数,将(100,000)10 转化为2进制数位 1 1000 0110 1010 0000 = 1.1000011010100000 * 21 0000
由于偏移量为8,指数部分需要加上1000,最终得到指数位1 1000
要求保留三位小数,可得小数部分为100
最终得到的s3E5浮点数为 0 11000 100,表示为十进制数为98,304
绝对误差 = 100,000 - 98,304 = 1,696
相对误差为(100,000 - 98,000) / 100,000 = 0.01696
复习题
1. 噪声容限,VOL = 0.1V, VOH = 0.9V, VIL = 0.5V, VIH = 0.7V
-
噪声容限的最大值和最小值是多少?
VNMH = VOH - VIH = 0.2V
VNML = VIL - VOL = 0.4V
-
电源电压(相对于GND)的允许容限如何估算?
电源电压的最小值不能小于器件允许的最小值,不能超过器件允许的最大值,同时避免在(VIL, VIH)之间
-
假定 VIH-VIL >= 0.2V,如何调整这些?
增大VIH 减小VIL ,但若需要保证传输曲线增益不变根据
VOH - VIL
也需要相应的增大
2. 为了用数字技术处理信号,信号怎么表示
-
单一信号可以如何表示?举例说明
单一信号可以用1bit表示,如白天跟晚上,0便是白天,1表示晚上
-
集合信号可以如何表示?举例说明
集合信号可以用01集合进行编码,如红绿蓝紫,可以用2bit表示,00表示红,01表示绿,10表示蓝,11表示紫色。
-
讨论如何表示棋盘
-
围棋棋盘
可以使用位图表示,其中每一位包括2bit信息,00表示没有棋子,01表示有白子,10表示有黑子。
-
中国象棋棋盘
象棋棋盘同样也可以用位图表示,位图中每一位有8bit数据,8b'0表示一个位子没有数据,若不全为0,最高位1表示红方,0表示蓝方,剩下的7位分别对卒车马象帅等棋子进行编码
-
3. 化简逻辑函数
-
f = (x & y & z) | (x & y) | (x’ & y & z)
= (y & z & x ) | (y & z & x') | (x & y)
= (y & z) & (x | x') | (x & y)
= (y & z) | (y & x)
= y & (x | z)
-
f = (x & y & z) | (x & y’) | (x & z’)
= (x & y & z) | [x & (y & z)']
= x & [(y & z) | (y & z)']
= x
4. 对偶与互补
给定一个逻辑函数 f(a,b,c),其互补函数写作f’ = f’(a,b,c),对偶函 数写作fD = f’(a’,b’,c’)
-
假定 f = AND (与运算), 其互补函数是 _____?对偶函数是_____?
互补函数是 OR
对偶函数是 NOR
-
假定 f = 3-bit 质数函数,f 输入为1,2,3,5,7时输出为1(Ture)
f函数的真值表如下所示
c\ba | 00 | 01 | 11 | 10 |
---|---|---|---|---|
0 | 0 | 1 | 1 | 1 |
1 | 0 | 1 | 1 | 0 |
f = a | ( b & c')
-
互补函数f’ 在输入为_______时产生输出“1”?
f’ = a & ( b | c')
1,3,7
-
对偶函数fD 在输入围_______时产生输出“1”?
fD = a‘ & ( b’ | c)
0,4,6
5. 6. 手工组合逻辑电路设计(感觉第五第六题再说一个东西,没太明白题意)
从设计规范入手,写出卡诺图,找出关键蕴含项( prime implicants ), 选择覆盖逻辑函数的关键蕴含项的最小集
-
试图设计组合逻辑电路,实现4-bit 输入的Fibonacci 数列判断 (给出设计过程,一种电路图,一种VHDL描述)
不是设计电路产生Fibonacci数列
是类似讲义中质数(素数)的判断
-
斐波那契数列(Fibonacci ),又称黄金分割数列 “兔子数列”。这个序列的前几项是这样的:0,1,1,2,3,5,8,13,21,34,⋯在数学上,斐波纳契数列以如下被以递归的方法定义:
F(0)=0
F(1)=1
-
F(n)=F(n−1)+F(n−2) ,(n≥2,n∈N)
4-输入信号的Fibonacci(斐波那契数列)电路 当输入(dcba)为1,2,3,5,8, 及 13时,输出为True
-
补充其他方法,至少包含一种VHDL描述
将每个位1的项或起来直接输出
library ieee; use ieee.std_logic_1164.all; entity fib_condition is port ( num : in std_logic_vector(3 downto 0); is_fib: out std_logic); end fib_condition; architecture fib_condition_impl of fib_condition is begin process( num ) begin case num is when "0000" | "0001" | "0010" | "0011" | "0101" | "1000" | "1101" => is_fib <= '1'; when others => is_fib <= '0'; end case; end process ; end fib_condition_impl;
7. 写出 该电路行为的一种 VHDL描述
library ieee;
use ieee.std_logic_1164.all;
entity fib_condition is
port (
num : in std_logic_vector(3 downto 0);
is_fib: out std_logic);
end fib_condition;
architecture fib_condition_impl of fib_condition is
begin
process( num )
begin
case num is
when "0000" | "0001" | "0010" | "0011" | "0101" | "1000" | "1101"
=> is_fib <= '1';
when others => is_fib <= '0';
end case;
end process ;
end fib_condition_impl;
8. 写出 该电路行为的一种 VHDL描述
library ieee;
use ieee.std_logic_1164.all;
entity test is
port (
num : in std_logic_vector(3 downto 0);
is_fib: out std_logic);
end fib_condition;
architecture fib_condition_impl of test is
begin
process( num )
begin
case num is
when "0111" | "1100" | "1101" | "1111" | "1110" | "1011" => is_fib <= '1';
when others => is_fib <= '0';
end case;
end process ;
end fib_condition_impl;
9. 组合逻辑电路模块(单元)的利用
-
提高抽象层次,使用组件(组合逻辑单元)而不是直接使用卡诺图设计电路
- 假定组合逻辑电路来自预定义的电路单元
- 编码器Encoder – 将one-hot信号转换为2进制
- 复接器(多路选择器)Multiplexer – 根据One-hot信号选择某个输入信号
- 仲裁器Arbiter – 选择第一个Ture
- 比较器Comparators – 相等或者幅度大小
- 只读存储器ROMs
-
采用划分的方式由小的电路单元构造大的电路单元
Decoder, encoder, multiplexer
基于复接器和译码器的逻辑电路(FPGA中查表的基础)
位片(Bit-slice)编码风格
-
如何得到求三个数的中间数的电路?复习练习09:写出这个电路的VHDL模型。
vhdl代码如下所示,复用三个比较器,agb代表a大于b,agc代表a大于c,bgc代表b大于c,三者两两之间比较之后,可以得到三者之间得大小关系,若a位mid,则agb xor agc为1,即a只大于两个中的一个;若b为mid,agb xor bgc 为0,也是表示b只大于两个中的一个,同理若c为mid,agc xor bgc 为1,仿真结果如下图所示。result输出中间的数,可知结果正确。
代码如下所示
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_misc.all; entity magComp is generic(k: integer := 8); port ( a,b: in std_logic_vector(k-1 downto 0); gt: out std_logic ) ; end magComp; architecture impl of magComp is signal eqi, gti: std_logic_vector(k-1 downto 0); signal gta, eqa: std_logic_vector(k downto 0); begin eqi <= a xnor b; gti <= a and not b; gta <= '0' & (gta(k downto 1) or (gti and eqa(k downto 1))); eqa <= '1' & (eqa(k downto 1) and eqi); gt <= or_reduce(gta); end impl ; -- impl library ieee; use ieee.std_logic_1164.all; entity midle is generic(k : integer := 8); port ( a,b,c: in std_logic_vector(k-1 downto 0); mid: out std_logic_vector(k-1 downto 0) ) ; end midle; architecture impl of midle is signal agb, agc, bgc: std_logic; begin p1: entity work.magComp generic map(k) port map(a, b, agb); p2: entity work.magComp generic map(k) port map(a, c, agc); p3: entity work.magComp generic map(k) port map(b, c, bgc); mid <= a when (agb xor agc) = '1' else b when (agb xor bgc) = '0' else c when (agc xor bgc) = '1' else (k-1 downto 0 => '-'); end impl ; -- impl --pragma translate_off library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; use std.textio.all; use ieee.std_logic_textio.all; entity midletest is end midletest; architecture test of midletest is signal a, b, c, result: std_logic_vector(3 downto 0); begin p0: entity work.midle generic map (4) port map(a, b, c, result); process is begin for i in 0 to 10 loop a <= std_logic_vector(to_signed(i, 4)); b <= std_logic_vector(to_signed(i + 1 , 4)); c <= std_logic_vector(to_signed(i + 2 , 4)); wait for 10 ns; end loop; end process; end test ; -- test --pragma translate_on
组合逻辑电路单元的问题: 复习练习10
-
设计一个组合逻辑电路,输入为4个4-bit One-hot信号, 输出为4个信号中最高有效位位置为“1”对应的数字
如下图所示,使用比较器跟多路复用器构造电路,最高有效位为1表示最大的数,将a与b,c与d比较,输出较大的,在比较这两个输出,选出大的一个。
-
电路的输入是4个4-bit数字(任意设定数据格式),输出是“1的个数最少的那个输入信号”
如图所示,使用比特加法器,统计输入内有多少个1,在使用与上一题一样的结构,输出四个输入中最小的那个数。
复习练习11
-
设计一个电路,实现将输入a变换成-2a
-
方法:左移1位 (2x),诸位求反,再+1
如图所示的电路,将输入左移两位,得到输入的两倍,在通过与ff异或得到反码,在加一的到其补码电路。
-
-
将10进制浮点数35.6转化为IEEE 754 二进制s8.3格式浮 点数,写出变换步骤
我理解成指数部分3位小数部分8位的浮点数,没有给偏移量,先将整数部分表示为10 0011,小数部分表示为0.1001 1001,该数可以表示为10 0011.1001 1001,格式化为1.0001 1100 1100 * 25 ,故指数部分为101,s为0,故IEEE754格式可以写成0 101 0001 1100