EDA技术实用教程--VHDL版本(第五版)潘松课后习题答案

更新时间:2023-04-12 20:05:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

《EDA技术实用教程(第五版)》习题

1 习题

1-1EDA技术与ASIC设计和FPGA开发有什么关系?FPGA在ASIC设计中有什么用

途?P3~4

EDA技术与ASIC设计和FPGA开发有什么关系?答:利用EDA技术进行电子系统设计的最后目标是完成专用集成电路ASIC的设计和实现;FPGA和CPLD是实现这一途径的主流器件。FPGA和CPLD的应用是EDA技术有机融合软硬件电子设计技术、SoC(片上系统)和ASIC设计,以及对自动设计与自动实现最典型的诠释。

FPGA在ASIC设计中有什么用途?答:FPGA和CPLD通常也被称为可编程专用IC,或可编程ASIC。FPGA实现ASIC设计的现场可编程器件。

1-2 与软件描述语言相比,VHDL有什么特点? P4~6

答:编译器将软件程序翻译成基于某种特定CPU的机器代码,这种代码仅限于这种CPU 而不能移植,并且机器代码不代表硬件结构,更不能改变CPU的硬件结构,只能被动地为其特定的硬件电路结构所利用。

综合器将VHDL程序转化的目标是底层的电路结构网表文件,这种满足VHDL设计程序功能描述的电路结构,不依赖于任何特定硬件环境;具有相对独立性。综合器在将VHDL(硬件描述语言)表达的电路功能转化成具体的电路结构网表过程中,具有明显的能动性和创造性,它不是机械的

一一对应式的“翻译”,而是根据设计库、工艺库以及预先设置的各类约束条件,选择最优的方式完成电路结构的设计。

l-3什么是综合?有哪些类型?综合在电子设计自动化中的地位是什么?P6

什么是综合? 答:在电子设计领域中综合的概念可以表示为:将用行为和功能层次表达的电

子系统转换为低层次的便于具体实现的模块组合装配的过程。

有哪些类型?答:(1)从自然语言转换到VHDL语言算法表示,即自然语言综合。(2)从算法表示转换到寄存器传输级(RegisterTransport Level,RTL),即从行为域到结构域的综合,即行为综合。(3)从RTL级表示转换到逻辑门(包括触发器)的表示,即逻辑综合。(4)从逻辑门表示转换到版图表示(ASIC设计),或转换到FPGA的配置网表文件,可称为版图综合或结构综合。

综合在电子设计自动化中的地位是什么?答:是核心地位(见图1-3)。综合器具有更复杂的工作环境,综合器在接受VHDL程序并准备对其综合前,必须获得与最终实现设计电路硬件特征相关的工艺库信息,以及获得优化综合的诸多约束条件信息;根据工艺库和约束条件信息,将VHDL程序转化成电路实现的相关信息。

1-4 在EDA技术中,自顶向下的设计方法的重要意义是什么? P8~10

答:在EDA技术应用中,自顶向下的设计方法,就是在整个设计流程中各设计环节逐步求精的过程。

1-5 IP在EDA技术的应用和发展中的意义是什么? P23~25

答:IP核具有规范的接口协议,良好的可移植与可测试性,为系统开发提供了可靠的保证。

1-6叙述EDA的FPGA/CPLD设计流程,以及涉及的EDA工具及其在整个流程中的作用。(P12~14)

答:1.设计输入(原理图/HDL文本编辑)(EDA设计输入器将电路系统以一定的表达方式输入计算机);2.综合(EDA综合器就是将电路的高级语言(如行为描述)转换成低级的,可与

FPGA/CPLD的基本结构相映射的网表文件或程序。);3.适配(EDA适配器的功能是将由综合器产生的网表文件配置于指定的目标器件中,使之产生最终的下载文件,如JEDEC、JAM格式的文件。);4.时序仿真(ED A时序仿真器就是接近真实器件运行特性的仿真,仿真文件中已包含了器件硬件特性参数,因而,仿真精度高。)与功能仿真(ED A功能仿真器直接对VHDL、原理图描述或其他描述形式的逻辑功能进行测试模拟,以了解其实现的功能是否满足原设计的要求,

仿真过程不涉及任何具体器件的硬件特性。);5.编程下载(EDA编程下载把适配后生成的下载或配置文件,通过编程器或编程电缆向FPGA或CPLD下载,以便进行硬件调试和验证(Hardware Debugging)。);6.硬件测试(最后是将含有载入了设计的FPGA或CPLD的硬件系统进行统一测试,以便最终验证设计项目在目标系统上的实际工作情况,以排除错误,改进设计。其中EDA的嵌入式逻辑分析仪是将含有载入了设计的FPGA 的硬件系统进行统一测试,并将测试波形在PC机上显示、观察和分析。)。

2 习题

2-1OLMC(输出逻辑宏单元)有何功能?说明GAL是怎样实现可编程组合电路与时序电路的。P34~36

OLMC有何功能? 答:OLMC单元设有多种组态,可配置成专用组合输出、专用输入、组合输出双向口、寄存器输出、寄存器输出双向口等。

说明GAL是怎样实现可编程组合电路与时序电路的? 答:GAL(通用阵列逻辑器件)是通过对其中的OLMC(逻辑宏单元)的编程和三种模式配置(寄存器模式、复合模式、简单模式),实现组合电路与时序电路设计的。

2-2什么是基于乘积项的可编程逻辑结构?P33~34,40什么是基于查找表的可编程逻辑结构?P40~42

什么是基于乘积项的可编程逻辑结构?答:GAL、CPLD之类都是基于乘积项的可编程结构;即包含有可编程与阵列和固定的或阵列的PAL(可编程阵列逻辑)器件构成。

什么是基于查找表的可编程逻辑结构?答:FPGA(现场可编程门阵列)是基于查找表的可编程逻辑结构。

2-3FPGA系列器件中的LAB有何作用? P42~44

答:FPGA(Cyclone/Cyclone II)系列器件主要由逻辑阵列块LAB、嵌入式存储器块(EAB)、I/O 单元、嵌入式硬件乘法器和PLL等模块构成;其中LAB(逻辑阵列块)由一系列相邻的LE(逻辑单元)构成的;FPGA可编程资源主要来自逻辑阵列块LAB。

2-4与传统的测试技术相比,边界扫描技术有何优点? P47~50

答:使用BST(边界扫描测试)规范测试,不必使用物理探针,可在器件正常工作时在系统捕获测量的功能数据。克服传统的外探针测试法和“针床”夹具测试法来无法对IC内部节点无法测试的难题。

2-5 解释编程与配置这两个概念。P51~56

答:编程:基于电可擦除存储单元的EEPROM或Flash技术。CPLD一股使用此技术进行编程。CPLD被编程后改变了电可擦除存储单元中的信息,掉电后可保存。电可擦除编程工艺的优点是编程后信息不会因掉电而丢失,但编程次数有限,编程的速度不快。

配置:基于SRAM查找表的编程单元。编程信息是保存在SRAM中的,SRAM在掉电后编程信息立即丢失,在下次上电后,还需要重新载入编程信息。大部分FPGA采用该种编程工艺。该类器件的编程一般称为配置。对于SRAM型FPGA来说,配置次数无限,且速度快;在加电时可随时更改逻辑;下载信息的保密性也不如电可擦除的编程。

2-6 请参阅相关资料,并回答问题:按本章给出的归类方式,将基于乘积项的可编程逻辑结构

的PLD器件归类为CPLD;将基于查找表的可编程逻辑结构的PLD器什归类为FPGA,那

么,APEX系列属于什么类型PLD器件? MAX II系列又属于什么类型的PLD器

件?为什么? P47~51

答:APEX(Advanced Logic Element Matrix)系列属于FPGA类型PLD器件;编程信息存于SRAM中。MAX II系列属于CPLD类型的PLD器件;编程信息存于EEPROM中。

3 习题

3-1 说明端口模式INOUT和BUFFER有何异同点。P60

INOUT : 具有三态控制的双向传送端口

BUFFER: 具有输出反馈的单向东湖出口。

3-2 画出与以下实体描述对应的原理图符号元件:

ENTITY buf3s IS --实体1:三态缓冲器

PORT(input:IN STD_LOGIC; --输入端

enable:IN STD_LOGIC; --使能端

output:OUT STD_LOGIC); --输出端

END buf3s ;

ENTITY mux21 IS --实体2: 2选1多路选择器

PORT(in0, in1,sel: IN STD_LOGIC;

output:OUT STD_LOGIC);

3-3 试分别用IF_THEN语句和CASE语句的表达方式写出此电路的VHDL程序,选择控制信号s1和s0的数据类型为STD_LOGIC_VECTOR;当s1=?0?,s0=?0?;s1=?0?,s0=?1?;

s1=?1?,s0=?0?和s1=?1?,s0=?1?时,分别执行y<=a、y<=b、y<=c、y<=d。

--解1:用IF_THEN语句实现4选1多路选择器

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux41 IS

PORT (a,b,c,d: IN STD_LOGIC;

s0: IN STD_LOGIC;

s1: IN STD_LOGIC;

y: OUT STD_LOGIC);

END ENTITY mux41;

ARCHITECTURE if_mux41 OF mux41 IS

SIGNAL s0s1 : STD_LOGIC_VECTOR(1 DOWNTO 0);--定义标准逻辑位矢量数据BEGIN s0s1<=s1&s0; --s1相并s0,即s1与s0并置操作

PROCESS(s0s1,a,b,c,d)

BEGIN

IF s0s1 = "00" THEN y <= a;

ELSIF s0s1 = "01" THEN y <= b;

ELSIF s0s1 = "10" THEN y <= c;

ELSE y <= d;

END IF;

END PROCESS;

END ARCHITECTURE if_mux41;

--解2:用CASE语句实现4选1多路选择器

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux41 IS

PORT (a,b,c,d: IN STD_LOGIC;

s0: IN STD_LOGIC;

s1: IN STD_LOGIC;

y: OUT STD_LOGIC);

END ENTITY mux41;

ARCHITECTURE case_mux41 OF mux41 IS

SIGNAL s0s1 : STD_LOGIC_VECTOR(1 DOWNTO 0);--定义标准逻辑位矢量数据类型BEGIN

s0s1<=s1&s0; --s1相并s0,即s1与s0并置操作

PROCESS(s0s1,a,b,c,d)

BEGIN

CASE s0s1 IS --类似于真值表的case语句

WHEN "00" => y <= a;

WHEN "01" => y <= b;

WHEN "10" => y <= c;

WHEN "11" => y <= d;

WHEN OTHERS =>NULL ;

END CASE;

END PROCESS;

END ARCHITECTURE case_mux41;

3-4 给出1位全减器的VHDL描述;最终实现8位全减器。要求:

1)首先设计1位半减器,然后用例化语句将它们连接起来,图4-20中h_suber是半减器,diff 是

输出差(diff=x-y),s_out是借位输出(s_out=1,x

图3-18 全减器结构图

--解(1.1):实现1位半减器h_suber(diff=x-y ;s_out=1,x

LIBRARY IEEE; --半减器描述(1):布尔方程描述方法

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY h_suber IS

PORT( x,y: IN STD_LOGIC;

diff,s_out: OUT STD_LOGIC);

END ENTITY h_suber;

ARCHITECTURE hs1 OF h_suber IS

BEGIN

Diff <= x XOR (NOT y);

s_out <= (NOT x) AND y;

END ARCHITECTURE hs1;

--解(1.2):采用例化实现图4-20的1位全减器

LIBRARY IEEE; --1位二进制全减器顺层设计描述

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY f_suber IS

PORT(xin,yin,sub_in: IN STD_LOGIC;

sub_out,diff_out: OUT STD_LOGIC);

END ENTITY f_suber;

ARCHITECTURE fs1 OF f_suber IS

COMPONENT h_suber --调用半减器声明语句

PORT(x, y: IN STD_LOGIC;

diff,s_out: OUT STD_LOGIC);

END COMPONENT;

SIGNAL a,b,c: STD_LOGIC; --定义1个信号作为内部的连接线。

BEGIN

u1: h_suber PORT MAP(x=>xin,y=>yin, diff=>a, s_out=>b);

u2: h_suber PORT MAP(x=>a, y=>sub_in, diff=>diff_out,s_out=>c);

sub_out <= c OR b;

END ARCHITECTURE fs1;

(2)以1位全减器为基本硬件,构成串行借位的8位减法器,要求用例化语句来完成此项设计(减法运算是x-y-sun_in=difft)。xin

yin a b diff_out c

解(2):采用例化方法,以1位全减器为基本硬件;实现串行借位的8位减法器(上图所示)。LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY suber_8 IS

PORT(x0,x1,x2,x3,x4,x5,x6,x7: IN STD_LOGIC;

y0,y1,y2,y3,y4,y5,y6,y7,sin: IN STD_LOGIC;

diff0,diff1,diff2,diff3: OUT STD_LOGIC;

diff4,diff5,diff6,diff7,sout: OUT STD_LOGIC);

END ENTITY suber_8;

ARCHITECTURE s8 OF suber_8 IS

COMPONENT f_suber --调用全减器声明语句

PORT(xin,yin,sub_in: IN STD_LOGIC;

sub_out,diff_out: OUT STD_LOGIC);

END COMPONENT;

SIGNAL a0,a1,a2,a3,a4,a5,a6: STD_LOGIC; --定义1个信号作为内部的连接线。BEGIN u0:f_suber PORT MAP(xin=>x0,yin=>y0,diff_out=>diff0,sub_in=>sin,sub_out=>a0);

u1:f_suber PORT MAP(xin=>x1,yin=>y1,diff_out=>diff1,sub_in=>a0,sub_out=>a1);

u2:f_suber PORT MAP(xin=>x2,yin=>y2,diff_out=>diff2,sub_in=>a1,sub_out=>a2);

u3:f_suber PORT MAP(xin=>x3,yin=>y3,diff_out=>diff3,sub_in=>a2,sub_out=>a3);

u4:f_suber PORT MAP(xin=>x4,yin=>y4,diff_out=>diff4,sub_in=>a3,sub_out=>a4);

u5:f_suber PORT MAP(xin=>x5,yin=>y5,diff_out=>diff5,sub_in=>a4,sub_out=>a5);

u6:f_suber PORT MAP(xin=>x6,yin=>y6,diff_out=>diff6,sub_in=>a5,sub_out=>a6);

u7:f_suber PORT MAP(xin=>x7,yin=>y7,diff_out=>diff7,sub_in=>a6,sub_out=>sout); END ARCHITECTURE s8;

3-5 用VHDL 设计一个3-8译码器,要求分别用(条件)赋值语句、case 语句、if else 语句或移位操作符来完成。比较这4种方式中,哪一种最节省逻辑资源。

解(1):条件赋值语句

--3-5 3到8译码器设计(条件赋值语句实现)

diff0 diff1 sout diff7 串行借位的8位减法器

DOUT<="00000001" WHEN 0,

"00000010" WHEN 1,

"00000100" WHEN 2,

"00001000" WHEN 3,

"00010000" WHEN 4,

"00100000" WHEN 5,

"01000000" WHEN 6,

"10000000" WHEN 7,

UNAFFECTED WHEN OTHERS;

END behave;

解(2):case语句

--3-5 3到8译码器设计(case语句实现)

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL; --为使用类型转换函数,打开此程序包。

ENTITY decoder3to8 IS

port( DIN: IN STD_LOGIC_VECTOR(2 DOWNTO 0);

DOUT: OUT BIT_VECTOR(7 DOWNTO 0));

END decoder3to8;

ARCHITECTURE behave OF decoder3to8 IS

BEGIN

PROCESS (DIN)

BEGIN

CASE CONV_INTEGER(DIN) IS

WHEN 0 => DOUT<="00000001";

WHEN 1 => DOUT<="00000010";

WHEN 2 => DOUT<="00000100";

WHEN 3 => DOUT<="00001000";

WHEN 4 => DOUT<="00010000";

WHEN 5 => DOUT<="00100000";

WHEN 6 => DOUT<="01000000";

WHEN 7 => DOUT<="10000000";

WHEN OTHERS => NULL;

END CASE;

END decoder3to8;

ARCHITECTURE behave OF decoder3to8 IS

BEGIN

PROCESS (DIN)

BEGIN

IF CONV_INTEGER(DIN)=0 THEN DOUT<="00000001";

ELSIF CONV_INTEGER(DIN)=1 THEN DOUT<="00000010";

ELSIF CONV_INTEGER(DIN)=2 THEN DOUT<="00000100";

ELSIF CONV_INTEGER(DIN)=3 THEN DOUT<="00001000";

ELSIF CONV_INTEGER(DIN)=4 THEN DOUT<="00010000";

ELSIF CONV_INTEGER(DIN)=5 THEN DOUT<="00100000";

ELSIF CONV_INTEGER(DIN)=6 THEN DOUT<="01000000";

ELSIF CONV_INTEGER(DIN)=7 THEN DOUT<="10000000";

END IF;

END PROCESS;

END behave;

解(4):移位操作符

--3-5 3到8译码器设计(移位操作实现)

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL; --为使用类型转换函数,打开此程序包。ENTITY decoder3to8 IS

port( DIN: IN STD_LOGIC_VECTOR(2 DOWNTO 0);

DOUT: OUT BIT_VECTOR(7 DOWNTO 0));

END decoder3to8;

ARCHITECTURE behave OF decoder3to8 IS

BEGIN

DOUT<="00000001" SLL CONV_INTEGER(DIN); --被移位部分是常数

END behave;

3-6 设计一个比较电路,当输入的8421BCD码大于5时输出1,否则输出0。

--解:3-6 设计一个比较电路,当输入的8421BCD码大于5时输出1,否则输出0。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY g_5_cmp IS

PORT( d_in : IN STD_LOGIC_VECTOR(3 DOWNTO 0); --输入数据

cmp_out : OUT STD_LOGIC); --比较输出(1:输入数据>5) END g_5_cmp;

ARCHITECTURE BHV OF g_5_cmp IS

BEGIN

PROCESS(d_in)

BEGIN

IF(d_in>"0101") THEN

cmp_out<='1'; --输入数据大于5,比较输出1。

else

cmp_out<='0'; --输入数据小于等于5,比较输出0。

END IF;

END PROCESS;

END BHV;

3-7 利用if语句设计一个全加器。

--3-7 利用if语句设计一个全加器

LIBRARY IEEE; --1位二进制全加器顶层设计描述

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY f_adder IS

PORT (ain,bin,cin : IN STD_LOGIC;

cout,sum : OUT STD_LOGIC );

END ENTITY f_adder;

ARCHITECTURE fd1 OF f_adder IS

BEGIN

PROCESS (ain,bin,cin)

BEGIN

IF ain='1' XOR bin='1' XOR cin='1' THEN sum<='1'; ELSE sum<='0'; END IF;

IF (ain='1' AND bin='1')OR(ain='1' AND cin='1')OR(bin='1' AND cin='1')OR(ain='1' AND bin='1' AND cin='1')

THEN cout<='1';

ELSE cout<='0';

END IF;

END PROCESS;

END ARCHITECTURE fd1;

3-8 设计一个求补码的程序,输入数据是一个有符号的8位二进制数。

--解:3-8 设计一个求补码的程序,输入数据是一个有符号的8位二进制数。LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY org_patch IS

PORT( org_data : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--原码输入

patch_data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));--补码输出

END PROCESS;

END BHV;

3-9 设计一个格雷码至二进制数的转换器。

--3-9 设计一个格雷码至二进制数的转换器。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL; --为使用类型转换函数,打开此程序包。ENTITY grayTObinary IS

port( DIN: IN STD_LOGIC_VECTOR(3 DOWNTO 0);

DOUT: OUT BIT_VECTOR(3 DOWNTO 0));

END grayTObinary;

ARCHITECTURE behave OF grayTObinary IS

BEGIN

PROCESS (DIN)

BEGIN

CASE DIN IS

WHEN "0000" => DOUT<="0000";

WHEN "0001" => DOUT<="0001";

WHEN "0011" => DOUT<="0010";

WHEN "0010" => DOUT<="0011";

WHEN "0110" => DOUT<="0100";

WHEN "0111" => DOUT<="0101";

WHEN "0101" => DOUT<="0110";

WHEN "0100" => DOUT<="0111";

WHEN "1100" => DOUT<="1000";

WHEN "1101" => DOUT<="1001";

WHEN "1111" => DOUT<="1010";

WHEN "1110" => DOUT<="1011";

WHEN "1010" => DOUT<="1100";

WHEN "1011" => DOUT<="1101";

WHEN "1001" => DOUT<="1110";

WHEN "1000" => DOUT<="1111";

WHEN OTHERS => NULL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY COMP IS

PORT( A,B: IN STD_LOGIC_VECTOR(2 DOWNTO 0); --两个3位输入

LT: OUT STD_LOGIC; --小于输出

GT: OUT STD_LOGIC; --大于输出

EQ: OUT STD_LOGIC); --等于输出

END ENTITY COMP;

ARCHITECTURE ONE OF COMP IS

BEGIN

PROCESS(A,B)

BEGIN

IF (A

IF (A>B) THEN GT<='1';ELSE GT<='0';END IF;

IF (A=B) THEN EQ<='1';ELSE EQ<='0';END IF;

END PROCESS;

-- LT <= (A

-- GT <= (A>B); --大于

-- EQ <= (A=B); --等于

END ARCHITECTURE ONE;

3-11 利用8个全加器,可以构成一个8位加法器。利用循环语句来实现这项设计。并以此项设计为例,使用GENERIC参数传递的功能,设计一个32位加法器。

--3-11 利用GENERIC参数和循环语句将8个全加器构成成8位加法器

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY ADDER8B IS

GENERIC(S: INTEGER:=8); --定义参数S为整数类型,且等于4

PORT(A,B: IN STD_LOGIC_VECTOR(S-1 DOWNTO 0);

CIN: IN STD_LOGIC;

SUM: OUT STD_LOGIC_VECTOR(S-1 DOWNTO 0);

COUT: OUT STD_LOGIC);

END ENTITY ADDER8B;

ARCHITECTURE ONE OF ADDER8B IS

BEGIN

PROCESS(A,B,CIN)

V ARIABLE S1: STD_LOGIC_VECTOR(S-1 DOWNTO 0);

V ARIABLE C1: STD_LOGIC;--_VECTOR(S DOWNTO 0);

BEGIN

C1:=CIN;

--C1(0):=CIN;

FOR i IN 1 TO S LOOP

IF A(i-1)='1' XOR B(i-1)='1' XOR C1='1' THEN S1(i-1):='1'; ELSE S1(i-1):='0'; END IF;

IF (A(i-1)='1' AND B(i-1)='1')OR(A(i-1)='1' AND C1='1')OR(B(i-1)='1' AND

C1='1')OR(A(i-1)='1' AND B(i-1)='1' AND C1='1')

THEN C1:='1';

ELSE C1:='0';

END IF;

END LOOP;

SUM<=S1;COUT<=C1;

END PROCESS;

END ARCHITECTURE ONE;

3-12 设计一个2位BCD码减法器。注意可以利用BCD码加法器来实现。因为减去一个二进制数,等于加上这个数的补码。只是需要注意,作为十进制的BCD码的补码获取方式与普通二进制数稍有不同。我们知道二进制数的补码是这个数的取反加1。假设有一个4位二进制数是0011,其取补实际上是用1111减去0011,再加上l。相类似,以4位二进制表达的BCD码的取补则是用9(1001)减去这个数再加上1。

--3-12 设计2位BCD码减法器(利用减去数等于加上该数补码方法) (a-b=a+[-b]补码) LIBRARY IEEE; --待例化元件

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_arith.ALL;

USE IEEE.STD_LOGIC_unsigned.ALL;

ENTITY SUB2BCD IS

PORT(a,b: IN STD_LOGIC_VECTOR(7 DOWNTO 0);

diff: out STD_LOGIC_VECTOR(7 DOWNTO 0);

sout: OUT STD_LOGIC);

END SUB2BCD;

ARCHITECTURE behave OF SUB2BCD IS

BEGIN

PROCESS(a,b)

V ARIABLE cc: STD_LOGIC_VECTOR(7 DOWNTO 0);

BEGIN

IF a

cc:="10011010"-b;

IF cc(3 DOWNTO 0) > "1001" THEN cc:=cc+"00000110";END IF;

IF cc(7 DOWNTO 4) > "1001" THEN cc:=cc+"01100000";END IF;

cc:=a+cc;

IF cc(3 DOWNTO 0) > "1001" THEN cc:=cc+"00000110";END IF;

IF cc(7 DOWNTO 4) > "1001" THEN cc:=cc+"01100000";END IF;

IF a

cc:="10011010"-cc;

IF cc(3 DOWNTO 0) > "1001" THEN cc:=cc+"00000110";END IF;

IF cc(7 DOWNTO 4) > "1001" THEN cc:=cc+"01100000";END IF;

END IF;

diff<=cc;

END PROCESS;

END behave;

3-13 设计一个4位乘法器,为此首先设计一个加法器,用例化语句调用这个加法器,用移位相加的方式完成乘法。并以此项设计为基础,使用GENERIC参数传递的功能,设计一个16位乘法器。

--3-13 4位移位相加型乘法器设计(例化调用加法器)

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY MULT4B IS

GENERIC( S: INTEGER:=4); --定义参数S为整数类型,且等于4

PORT( R: OUT STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

A,B: IN STD_LOGIC_VECTOR(S-1 DOWNTO 0));

END ENTITY MULT4B;

ARCHITECTURE ONE OF MULT4B IS

COMPONENT addern IS

PORT(a,b: IN STD_LOGIC_VECTOR;

result: out STD_LOGIC_VECTOR);

END COMPONENT;

SIGNAL A0: STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

SIGNAL RR3,RR2,RR1,RR0,ZZ1,ZZ0: STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

BEGIN

A0<=CONV_STD_LOGIC_VECTOR(0,S) & A;

PROCESS(A,B)

BEGIN

IF(B(0)='1')THEN RR0<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 0);ELSE RR0<=(OTHERS=>'0');END IF;

IF(B(1)='1')THEN RR1<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 1);ELSE RR1<=(OTHERS=>'0');END IF;

IF(B(2)='1')THEN RR2<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 2);ELSE RR2<=(OTHERS=>'0');END IF;

IF(B(3)='1')THEN RR3<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 3);ELSE RR3<=(OTHERS=>'0');END IF;

END PROCESS;

u0: addern PORT MAP(a=>RR0,b=>RR1,result=>ZZ0);

u1: addern PORT MAP(a=>ZZ0,b=>RR2,result=>ZZ1);

u2: addern PORT MAP(a=>ZZ1,b=>RR3,result=>R);

END ARCHITECTURE ONE;

--3-13a 16位乘法器(通过底层3-13_MULTSB和顶层GENERIC参数和传递例化语句实现) LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY MULT16B IS

PORT(D1,D2: IN STD_LOGIC_VECTOR(15 DOWNTO 0);

Q: OUT STD_LOGIC_VECTOR(31 DOWNTO 0));

END;

ARCHITECTURE BHV OF MULT16B IS

COMPONENT MULTSB --MULTS8模块的调用声明

GENERIC(S: integer); --照抄MULTSB实体中关于参数“端口”定义的语句

PORT(R: OUT std_logic_vector(2*S-1 DOWNTO 0);

A,B: IN std_logic_vector(S-1 DOWNTO 0));

END COMPONENT ;

BEGIN

u1: MULTSB GENERIC MAP(S=>16) PORT MAP(R=>Q,A=>D1,B=>D2);

END;

3-14 用循环语句设计一个7人投票表决器。

--解:3-14 用循环语句设计一个7人投票表决器,及一个4位4输出最大数值检测电路。LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY vote_7 IS

PORT( DIN: IN STD_LOGIC_VECTOR(6 DOWNTO 0);--7位表决输入(1:同意,0:不同意) G_4: OUT STD_LOGIC; --超过半数指示

CNTH: OUT STD_LOGIC_VECTOR(2 DOWNTO 0));--表决结果统计数END vote_7; ARCHITECTURE BHV OF vote_7 IS

BEGIN

PROCESS(DIN)

V ARIABLE Q: STD_LOGIC_VECTOR(2 DOWNTO 0);

BEGIN

Q:="000";

FOR n IN 0 TO 6 LOOP -- n是LOOP的循环变量

IF(DIN(n)='1') THEN Q:=Q+1; END IF;

END LOOP;

CNTH<=Q;

IF Q>=4 THEN G_4<='1'; ELSE G_4<='0'; END IF;

END PROCESS;

END BHV;

3-15 设计一个4位4输入最大数值检测电路。

--3-15 设计一个4位4输入最大数值检测电路。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY MAXDATA IS

PORT(A: IN STD_LOGIC_VECTOR(3 DOWNTO 0);

MAXOUT: OUT STD_LOGIC);

END ENTITY MAXDATA;

ARCHITECTURE ONE OF MAXDA TA IS

BEGIN

PROCESS(A)

BEGIN

IF A="1111" THEN MAXOUT<='1';ELSE MAXOUT<='0';END IF;

END PROCESS;

END ARCHITECTURE ONE;

3-16 设计VHDL程序,实现两个8位二进制数相加,然后将和左移或右移4位,并分别将移位后的值存入变量AA和BB中。

--3-16 设计VHDL程序,实现两个8位二进制数相加,然后将和左移或右移4位,并分别将移位后的值存入变量A和B中。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY ADDER8B IS

GENERIC(S: INTEGER:=8); --定义参数S为整数类型,且等于4

PORT(A,B: IN STD_LOGIC_VECTOR(S-1 DOWNTO 0);

CIN: IN STD_LOGIC;

SUM: OUT STD_LOGIC_VECTOR(S-1 DOWNTO 0);

COUT: OUT STD_LOGIC;

AA,BB: OUT STD_LOGIC_VECTOR(S-1+4 DOWNTO 0));

END ENTITY ADDER8B;

ARCHITECTURE ONE OF ADDER8B IS

BEGIN

PROCESS(A,B,CIN)

V ARIABLE S1: STD_LOGIC_VECTOR(S-1 DOWNTO 0);

V ARIABLE C1: STD_LOGIC;

V ARIABLE AB: STD_LOGIC_VECTOR(S-1+4 DOWNTO 0);

BEGIN

C1:=CIN;

FOR i IN 1 TO S LOOP

IF A(i-1)='1' XOR B(i-1)='1' XOR C1='1' THEN S1(i-1):='1'; ELSE S1(i-1):='0'; END IF;

IF (A(i-1)='1' AND B(i-1)='1')OR(A(i-1)='1' AND C1='1')OR(B(i-1)='1' AND

C1='1')OR(A(i-1)='1' AND B(i-1)='1' AND C1='1')

THEN C1:='1';

ELSE C1:='0';

END IF;

END LOOP;

SUM<=S1;COUT<=C1;

AA<=TO_STDLOGICVECTOR(TO_BITVECTOR("0000"&S1) SLL 4);

BB<=TO_STDLOGICVECTOR(TO_BITVECTOR("0000"&S1) SRL 4);

END PROCESS;

END ARCHITECTURE ONE;

3-17 举例说明GENERIC说明语句(在实体定义语句中定义类属常数)和GENERIC映射语句(在例化语句中将类属常数赋予新值)有何用处。P82

3-18 表达式C<=A+B中,A、B和C的数据类型都是STD_LOGIC_VECTOR,是否能直接进行加法运算?说明原因和解决方法。能(第一种将A、B转换成整型数相加结果再转换成逻辑位矢后送C P89;第二种使用USE IEEE.SDT_LOGIC_UNSIGNED.ALL语句打开重载运算符程序包。P70,P130)

3-19 VHDL中有哪三种数据对象?详细说明它们的功能特点以及使用方法,举例说明数据对象与数据类型的关系。信号,变量,常量P71

3-20 能把任意一种进制的值向一整数类型的数据对象赋值吗?如果能,怎样做? 能(若

A,B,C,D是信号整数类型,A<=16#df#;B<=8#23#;C<=2#01#;D<=10)P83

3-21 回答有关BIT和BOOLEAN数据类型的问题:P59

(1)解释BIT(…0?;…1?)和BOOLEAN(“TRUE”,“FALSE”)类型的区别。

(2)对于逻辑操作应使用哪种类型?BIT

(3)关系操作的结果为哪种类型? BOOLEAN

(4)IF语句测试的表达式是哪种类型? BOOLEAN

3-22 用两种方法设计8位比较器,比较器的输入是两个待比较的8位数A=[A7..A0]和

B=[B7..80],输出是D、E、F。当A=B时D=1;当A>B时E=1;当A

--3-22 比较器的输入是两个待比较的8位数A=[A7..A0]和B=[B7..80],输出是EQ、GT、F。当A=B时EQ=1;当A>B时GT=1;当A

--第一种设计方案是常规的比较器设计方法,即直接利用关系操作符进行编程设计。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY COMP IS

PORT( A,B: IN STD_LOGIC_VECTOR(7 DOWNTO 0); --两个3位输入

LT: OUT STD_LOGIC; --小于输出

GT: OUT STD_LOGIC; --大于输出

EQ: OUT STD_LOGIC); --等于输出

END ENTITY COMP;

ARCHITECTURE ONE OF COMP IS

BEGIN

PROCESS(A,B)

BEGIN

IF (A

IF (A>B) THEN GT<='1';ELSE GT<='0';END IF;

IF (A=B) THEN EQ<='1';ELSE EQ<='0';END IF;

END PROCESS;

END ARCHITECTURE ONE;

--3-22 比较器的输入是两个待比较的8位数A=[A7..A0]和B=[B7..80],输出是EQ、GT、F。当A=B时EQ=1;当A>B时GT=1;当A

--第二种设计方案是利用减法器来完成,通过减法运算后的符号和结果来判别两个被比较值的大小。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY COMP IS

PORT( A,B: IN STD_LOGIC_VECTOR(7 DOWNTO 0); --两个3位输入

LT: OUT STD_LOGIC; --小于输出

GT: OUT STD_LOGIC; --大于输出

EQ: OUT STD_LOGIC); --等于输出

END ENTITY COMP;

ARCHITECTURE ONE OF COMP IS

SIGNAL C: STD_LOGIC_VECTOR(7 DOWNTO 0);

SIGNAL D,E,F,G: INTEGER RANGE 255 DOWNTO 0;

BEGIN

C<=A-B;

D<=10;

E<=16#D9#;

F<=8#72#;

G<=2#11010010#;

PROCESS(A,B)

BEGIN

IF (C(7)='1') THEN LT<='1';ELSE LT<='0';END IF;

IF (C=0) THEN EQ<='1';

ELSE EQ<='0';

IF(C(7)='0')THEN GT<='1';ELSE GT<='0';END IF;

END IF;

END PROCESS;

END ARCHITECTURE ONE;

3-23 根据图3-19,用两种不同描述方式设计一4选1多路选择器。在设计中需要体现此电路由三个2选l多路选择器构成。解1:层次例化;解2:单层3进程。

--解1:层次例化。底层元件mux21a.vhd程序如下: LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux21a IS

PORT(a,b,s: IN STD_LOGIC;

y: OUT STD_LOGIC);

END ENTITY mux21a;

ARCHITECTURE one OF mux21a IS

BEGIN

PROCESS(a,b,s)

BEGIN

IF s='0' THEN

y<=a;

ELSE

y<=b;

END IF;

END PROCESS;

END ARCHITECTURE one;

--解1:层次例化。顶层mux41b.vhd程序如下: LIBRARY ieee; USE ieee.std_logic_1164.all;

ENTITY mux41b IS

port(X0,X1,X2,X3: IN STD_LOGIC;

S0,S1: IN STD_LOGIC;

OUTY: OUT STD_LOGIC);

END mux41b;

ARCHITECTURE bdf_type OF mux41b IS

component mux21a

PORT(a,b,s: IN STD_LOGIC;

y: OUT STD_LOGIC);

end component;

signal N0,N1: STD_LOGIC;

BEGIN

u1: mux21a PORT MAP(a=>X0,b=>X1,s=>S0,y=>N0);

u2: mux21a PORT MAP(a=>X2,b=>X3,s=>S0,y=>N1);

u3: mux21a PORT MAP(a=>N0,b=>N1,s=>S1,y=>OUTY); END; --解2:单层结构mux41a.vhd程序如下:

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY mux41a IS

PORT(x1,x2,x3,x4,s0,s1: IN STD_LOGIC;

y: OUT STD_LOGIC);

END ENTITY mux41a;

ARCHITECTURE one OF mux41a IS

signal N0,N1: STD_LOGIC;

BEGIN

com1: PROCESS(x1,x2,s0)

BEGIN

IF s0='0' THEN

N0<=x1;

ELSE

N0<=x2;

END IF;

END PROCESS;

com2: PROCESS(x3,x4,s0)

BEGIN

IF s0='0' THEN

N1<=x3;

ELSE

N1<=x4;

END IF;

END PROCESS;

com3: PROCESS(N0,N1,s1)

BEGIN

IF s1='0' THEN

y<=N0;

ELSE

y<=N1;

END IF;

END PROCESS;

END ARCHITECTURE one;

4 习题

4-1 归纳利用Quartus II进行VHDL文本输入设计的流程:从文件输入一直到硬件功能测试。P96~P110

答:1 建立工作库文件夹和编辑设计文件;2 创建工程;3 编译前设置;4 全程编译;5 时序仿真;6 引脚锁定;7 配置文件下载;8 打开SignalTap II编辑窗口;9 调入SignalTap II的待测信号;10 SignalTap II参数设置;11 SignalTap II参数设置文件存盘;12 带有SignalTap II测试信息的编译下载;13 启动SignalTap II进行采样与分析;

14 SignalTap II的其他设置和控制方法。

4-2 参考Quartus II的Help,详细说明Assignments菜单中Settings对话框的功能。

(1)说明其中的Timing Requirements & Qptions的功能、使用方法和检测途径。

(2)说明其中的Compilation Process的功能和使用方法。

(3)说明Analysis & Synthesis Setting的功能和使用方法,以及其中的Synthesis Netlist Optimization的功能和使用方法。

(1)说明其中的Timing Requirements&Qptions的功能、他用方法和检测途经。

Specifying Timing Requirements and Options (Classic Timing Analyzer)

You can specify timing requirements for Classic timing analysis that help you achieve the desired speed performance and other timing characteristics for the entire project, for specific design entities, or for inpidual clocks, nodes, and pins.

When you specify either project-wide or inpidual timing requirements, the Fitter optimizes the placement of logic in the device in order to meet your timing goals.

You can use the Timing wizard or the Timing Analysis Settings command to easily specify all project-wide timing requirements, or you can use the Assignment Editor to assign inpidual clock or I/O timing requirements to specific entities, nodes, and pins, or to all valid nodes included in a wildcard or assignment group assignment.

To specify project-wide timing requirements:

1.On the Assignments menu, click Settings.

2.In the Category list, select Timing Analysis Settings.

3.To specify project-wide t SU, t H, t CO, and/or t PD timing requirements, specify values

under Delay requirements.

4.To specify project-wide minimum delay requirements, specify options under

Minimum delay requirements.

5.Under Clock Settings, select Default required fmax.

6.In the Default required fmax box, type the value of the required f MAX and select a time

unit from the list.

7.If you want to specify options for cutting or reporting certain types of timing paths

globally, enabling recovery/removal analysis, enabling clock latency, and reporting unconstrained timing paths, follow these steps:

8.Click OK.

To specify clock settings:

1.On the Assignments menu, click Settings.

2.In the Category list, select Timing Analysis Settings.

3.Under Clock Settings, click Inpidual Clocks.

4.Click New.

5.In the New Clock Settings dialog box, type a name for the new clock settings in the

Clock settings name box.

6.To assign the clock settings to a clock signal in the design, type a clock node name in

the Applies to node box, or click Browse... to select a node name using the Node

Finder.

7.If you want to specify timing requirements for an absolute clock, follow these steps:

8.If you have already specified timing requirements for an absolute clock, and you want

to specify timing requirements for a derived clock, follow these steps:

9.In the New Clock Settings dialog box, click OK.

10.In the Inpidual Clocks dialog box, click OK.

11.In the Settings dialog box, click OK.

To specify inpidual timing requirements:

1.On the Assignments menu, click Assignment Editor.

2.In the Category bar, select Timing to indicate the category of assignment you wish to

make.

3.In the spreadsheet, select the To cell and perform one of the following steps:

?Type a node name and/or wildcard that identifies the destination node(s) you want to assign.

?Double-click the To cell and click Node Finder to use the Node Finder to enter

a node name.

Double-click the To cell, click the arrow that appears on the right side of the cell, and click Select Assignment Group to enter an existing assignment

group name.

4.To specify an assignment source, repeat step 3 to specify the source name in the

From cell.

5.In the spreadsheet, double-click the Assignment Name cell and select the timing

assignment you wish to make.

6.For assignments that require a value, double-click the Value cell and type or select

the appropriate assignment value.

To specify timing analysis reporting restrictions:

1.On the Assignments menu, click Settings.

2.In the Category list, double-click Timing Analysis Settings.

3.Click Timing Analyzer Reporting.

4.To specify the range of timing analysis information reported, specify one or more

options in the Timing Analyzer Reporting page.

5.Click OK.

(2)说明其中的Compilation Process的功能和使用方法。

Compilation Process Settings Page (Settings Dialog Box)

Allows you to direct the Compiler to use smart compilation, save synthesis results for the current design's top-level entity, disable the OpenCore Plus hardware evaluation feature, or export version-compatible database files. You can also control the amount of disk space used for compilation.

Use Smart compilation:

Preserve fewer node names to save disk space:

Run Assembler during compilation:

Save a node-level netlist of the entire design into a persistent source file:

Export version-compatible database:

Display entity name for node name:

Disable OpenCore Plus hardware evaluation feature:

(3)说明Analysis&Synthesis Setting的功能和使用方法,以及其中的Synthesis Netlist Optimization的功能和使用方法。

Analysis & Synthesis Settings Page (Settings Dialog Box)

Allows you to specify options for logic synthesis.

Create debugging nodes for IP cores:

More Settings:

Other options:

Message Level:

Advanced:

Synthesis Netlist Optimizations Page (Settings Dialog Box)

Specifies the following options for optimizing netlists during synthesis:

Perform WYSIWYG primitive resynthesis:

Perform gate-level register retiming:

Allow register retiming to trade off Tsu/Tco with Fmax:

4-3 概述Assignments菜单中Assignment Editor的功能,举例说明。

About the Assignment Editor

User Interface and Functionality:

Customizing the User Interface:

Pin Information:

LogicLock Assignments:

Assignment Validation and Output:

Integration with the Pin Planner:

4-4 全程编译主要包括哪几个功能模块?这些功能模块各有什么作用?P99~101

4-5 有哪三种引脚锁定的方法?详细说明这三种方法的使用流程和注意事项,并说明它们各自的特点。提示,第三种方法是选择Assignments中的Pins对话框,进行引脚设置。P103~105 4-6 详细说明通过JTAG口对FPGA的配置Flash EPCS器件的间接编程方法和流程。P106~107 4-7 对第3章的习题3-13和习题3-14的设计结果,用本章介绍的方法,分别在Quartus Ⅱ上进行仿真,验证其正确性;然后在EP3C55芯片中进行硬件测试和验证。

--3-13 4位移位相加型乘法器设计(例化调用加法器)

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_UNSIGNED.ALL;

USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY MULT4B IS

GENERIC( S: INTEGER:=4); --定义参数S为整数类型,且等于4

PORT( R: OUT STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

A,B: IN STD_LOGIC_VECTOR(S-1 DOWNTO 0));

END ENTITY MULT4B;

ARCHITECTURE ONE OF MULT4B IS

COMPONENT addern IS

PORT(a,b: IN STD_LOGIC_VECTOR;

result: out STD_LOGIC_VECTOR);

END COMPONENT;

SIGNAL A0: STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

SIGNAL RR3,RR2,RR1,RR0,ZZ1,ZZ0: STD_LOGIC_VECTOR(2*S-1 DOWNTO 0);

BEGIN

A0<=CONV_STD_LOGIC_VECTOR(0,S) & A;

PROCESS(A,B)

BEGIN

IF(B(0)='1')THEN RR0<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 0);ELSE RR0<=(OTHERS=>'0');END IF;

IF(B(1)='1')THEN RR1<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 1);ELSE RR1<=(OTHERS=>'0');END IF;

IF(B(2)='1')THEN RR2<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 2);ELSE RR2<=(OTHERS=>'0');END IF;

IF(B(3)='1')THEN RR3<=TO_STDLOGICVECTOR(TO_BITVECTOR(A0) SLL 3);ELSE RR3<=(OTHERS=>'0');END IF;

END PROCESS;

u0: addern PORT MAP(a=>RR0,b=>RR1,result=>ZZ0);

u1: addern PORT MAP(a=>ZZ0,b=>RR2,result=>ZZ1);

u2: addern PORT MAP(a=>ZZ1,b=>RR3,result=>R);

END ARCHITECTURE ONE;

--解:3-14 用循环语句设计一个7人投票表决器,及一个4位4输出最大数值检测电路。

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

本文来源:https://www.bwwdw.com/article/ef6l.html

Top