最近在用VHDL设计简易CPU,想用总线式的,这就要求端口模式必须是INOUT,之前没接触过。在网上搜到了博主jiangyi_love 的一篇文章,转载过来,我们大家共同学习。
在工程应用中,双向电路是设计者不得不面对的问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
.在实际应用中,数据总线往往是双向的.如何正确处理数据总线是进行时序逻辑电路设计的基础.在程序设计过程中,关键技术在于:实体部分必须对端口属性进行申明,端口属性必须为inout类型,在构造体需要对输出信号进行有条件的高阻控制.在双向电路的处理问题上,常用的处理方式有两种,在介绍双向电路的处理方式之前,先看看双向电路的基本格式:
ENTITY bidir_pin IS
(
bidir : INOUT std_logic;
oe, clk, from_core : IN std_logic;
to_core : OUT std_logic;
……
END bidir_pin;
ARCHITECTURE behavior OF bidir_pin IS
BEGIN
bidir <= from_core WHEN oe=‘1’ ELSE “ZZZZ”;
to_core <= bidir;
END behavior;
该程序揭示了双向电路的处理技巧,首先在实体部分bidir属于双向信号,在端口定义时,端口属性为inout类型,即把bidir信号作为输入三态输出. 语句“bidir <= from_core WHEN oe=‘1’ ELSE “ZZZZ”;”
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示bidir信号三态输出,语句”to_core <= bidir;”把bidir信号作为输入信号.
由此可见,双向电路在程序设计中,didir输入当着普通的in类型,而在输出时,需要加一定的控制条件,三态输出.问题的关键在于:如何确定这个条件?
1)双向信号作一个信号的输入,作另一信号的输出
ENTITY bidir IS
PORT(
bidir : INOUT STD_LOGIC_VECTOR (7 DOWNTO 0);
oe, clk : IN STD_LOGIC;
from_core : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
to_core : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END bidir;
ARCHITECTURE logic OF bidir IS
SIGNAL a : STD_LOGIC_VECTOR (7 DOWNTO 0);
SIGNAL b : STD_LOGIC_VECTOR (7 DOWNTO 0);
BEGIN
PROCESS (clk)
BEGIN
IF clk = '1' AND clk'EVENT THEN
a <= from_core;
to_core <= b;
END IF;
END PROCESS;
PROCESS (oe, bidir)
BEGIN
IF( oe = '0') THEN
bidir <= "ZZZZZZZZ";
b <= bidir;
ELSE
bidir <= a;
b <= bidir;
END IF;
END PROCESS;
END logic;
这种设计方式叫做寄存双向信号的方法.本设计中bidir为双向信号,from_core为数据输入端,to_core为数据输出端,oe为三态输出使能,clk为读写数据的时钟.在程序设计中,需要定义两个signal a和b信号.a信号用于输入数据from_core的寄存器,b用于输出数据to_core的寄存器.采用寄存器的方法需要设计两个进程,一个进程把a,b信号在时钟的控制下负责端口的输入信号from_core和端口输出信号to_core的连接,这一步实现了寄存双向的功能.另外一个进程则负责信号a,b和双向口之间的赋值关系.本设计只揭示了简单的双向信号操作方式,即bidir既可以作为from_core的输出,又可以作为to_core的输入
2)双向信号既做输出又做输出
上例是最简单的双向信号应用的特例.在实际的工程中,双向信号既做信号的输入,又做信号的输出,常见的数据总线就是这种操作模式.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity dir_data is
port(
clk : in STD_LOGIC;
rst : in STD_LOGIC;
rw : in STD_LOGIC;
address : in STD_LOGIC_VECTOR(1 downto 0);
data : inout STD_LOGIC_VECTOR(7 downto 0)
);
end dir_data;
architecture arc_dir of dir_data is
signal data_in : STD_LOGIC_VECTOR(7 downto 0);
signal data_out: STD_LOGIC_VECTOR(7 downto 0);
signal reg_a: STD_LOGIC_VECTOR(7 downto 0);
signal reg_b: STD_LOGIC_VECTOR(7 downto 0);
begin
data_in<=data;
d1:process(clk,rst,rw)
begin
if rst='1' then
reg_a<= (others=>'0');
reg_b<= (others=>'0');
elsif clk'event and clk='1' then
if rw='1' then
if address="00" then
reg_a<=data_in;
elsif address="01" then
reg_b<=data_in;
else null;
end if;
else null;
end if;
else null;
end if;
end process d1;
d2:process(clk,rw,reg_a,reg_b)
begin
if clk'event and clk='1' then
if rw='0' then
if address="00" then
data_out<=reg_a;
elsif address="01" then
data_out<=reg_b;
else null;
end if;
else null;
end if;
else null;
end if;
end process d2;
data<=data_out when (rw='0' and address(1)='0') else
(others=>'Z');
end arc_dir;
针对这个程序,我编了一个仿真波形,仅供参考!
在程序设计中,首先需要定义data_in, data_out, reg_a, reg_b四个signal,我们把data_in叫做输入寄存器,它是从双向信号data接收数据的寄存器,data_out叫做输出寄存器,它是向双向信号data发送信号的寄存器,reg_a和reg_b叫做操作寄存器,它们是在一定的时序控制下把data_in数据送给reg_a,reg_b,在一定的时序控制下从reg_a和reg_b读出数据的.这样的处理方式必须有两个进程,因为在architecture arc_dir of dir_data is和begin之间定义了data_in, data_out, reg_a, reg_b四个signal,它在同一进程内不支持既赋值,又调用,也就是说它不支持在d1进程中对信号reg_a, reg_b赋值,又在d1进程中又调用reg_a, reg_b.首先有语句”data_in<=data;”它表示输入寄存器无条件的接收双先信号的数据.在d1进程中,首先在rst信号有效时,对操作寄存器reg_a,和reg_b进行清零操作,然后在时钟(clk)的控制下,在写(rw)信号有效的情况下,对reg_a, reg_b寄存器在不同的地址控制下写入不同的data_in值.在d2进程中,在时钟(clk)的控制下,在读(rw)信号有效的时候,把不同地址的reg_a, reg_b的值送进data_out中.最关键的是最后一句:“data<=data_out when (rw='0' and address(1)='0') else (others=>'Z');”它表示双向信号的三态输出,而最最关键的是when后面的条件,如果条件限制太宽,就会错误占用双向信号总线,引起总线的误操作,如果条件限制太窄,输出寄存器的数据就不能够正确的送到数据总线上去,会引起数据的丢失.也就是说,只有正确的限制了when语句后面的条件,才能够把输出寄存器的数据正确地送到数据总线上去.仔细查看此条件,有如下的规律:when语句后的条件是操作寄存器写入输出寄存器的条件的公共条件.如:rw=’0’是操作寄存器的数据写入输出寄存器的读使能信号,address(1)是地址线的公共部分.在实际工程应用中,需要设计者在分配地址总线的时候掌握一定的技巧,尽量从地址的低位到到高位,保证地址总线有更多位的公共部分,比如只对四个寄存器操作时,地址线分配为”100”,”010”,”110”,”001”是不科学的,而”000”,”001”,”010”和”011”则是理想的.两者不同的是前者地址线没有公共部分,这样的设计无法用when语句对条件进行直接的控制,如果置之不理,由于列举不全,在逻辑综合时,电路会利用器件的乘积项和查找表的资源形成一个Latch, Latch不仅会把电路的时序变得复杂,而且电路存在潜在的危险性.虽然when语句后的条件不能够对条件进行直接的控制,但是可以使用枚举法一一把用到的地址线罗列出来,表示只有在这样的地址线的情况下才会用到数据总线,否则其他状态对数据总线送高阻,表示不占用数据总线.
总而言之,双向信号是程序设计中尤其重要的基础,设计者在设计程序的时候,要尤其注意,何时会占用数据总线,何时不占用数据总线。
《vhdl实验心得体会》简介:
一. 关于端口VHDL共定义了5种类型的端口,分别是In, Out,Inout, Buffer及Li
《vhdl实验心得体会》正文开始>>
一. 关于端口
VHDL共定义了5种类型的端口,分别是In, Out,Inout, Buffer及Linkage,实际设计时只会用到前四种。In和Out 端口的使用相对简单。这里,我们主要讲述关于buffer和inout使用时的注意事项。
与Out 端口比,Buffer端口具有回读功能,也即内部反馈,但在设计时最好不要使用buffer,因为buffer类型的
端口不能连接到其他类型的端口上,无法把包含该类型端口的设计作为子模块元件例化,不利于大型设计和程序的可读性。若设计时需要实现某个输出的回读功能,可以通过增加中间信号作为缓冲,由该信号完成回读功能。
双向端口Inout是四种端口类型中最为特殊的一种,最难以学习和掌握,为此专门提供一个简单程序进行阐述,部分程序如下:
① DataB<=Din when CE=’1’ and Rd=’0’ else
② (others=>’Z’);
③ Dout<=DataB when CE=’1’ and Rd=’1’ else
④ ( others=>’1’ );
… …
程序中DataB为双向端口,编程时应注意的是,当DataB作为输出且空闲时,必须将其设为高阻态挂起,即有类似第②行的语句,否则实现后会造成端口死锁。而当DataB作为有效输入时, DataB输出必须处于高阻态,对于该例子中即,当 CE=’1’ and Rd=’1’时,输出DataB应处于高阻态。
二.信号和变量
常数、信号和变量是VHDL中最主要的对象,分别代表一定的物理意义。常数对应于数字电路中的电源或地;信号对应某条硬件连线;变量通常指临时数据的局部存储。信号和变量功能相近,用法上却有很大不同。
表1 信号与变量主要区别
信号 变量
赋值延迟 至少有△延时 无,立即变化
相关信息 有,可以形成波形 无,只有当前值
进程敏感 是 否
全局性 具有全局性,可存在于多个进程中 只能在某个进程或子程序中有效
相互赋值关系 信号不能给变量赋值 变量可以给信号赋值
对于变量赋值操作无延迟,初学者认为这个特性对VHDL设计非常有利,但这只是理论上的。基于以下几点原因,我们建议,编程时还是应以信号为主,尽量减少变量的使用。
(1)变量赋值无延时是针对进程运行而言的,只是一个理想值,对于变量的操作往往被综合成为组合逻辑的形式,而硬件上的组合逻辑必然存在输入到输出延时。当进程内关于变量的操作越多,其组合逻辑就会变得越大越复杂。假设在一个进程内,有关于变量的3个 级连操作,其输出延时分别为5ns,6ns,7ns,则其最快的时钟只能达到18ns。相反,采用信号编程,在时钟控制下,往往综合成触发器的形式,特别是对于FPGA芯片而言,具有丰富的触发器结构,易形成流水作业,其时钟频率只受控于延时最大的那一级,而不会与变量一样层层累积。假设某个设计为3级流水作业,其每一级延时分别为10ns,11ns,12ns,则其最快时钟可达12ns。因此,采用信号反而更能提高设计的速度。
(2)由于变量不具备信息的相关性,只有当前值,因此也无法在仿真时观察其波形和状态改变情况,无法对设计的运行情况有效验证,而测试验证工作量往往会占到整个设计70%~80%的工作量,采用信号则不会存在这类问题。
(3)变量有效范围只能局限在单个进程或子程序中,要想将其值带出与其余进程、子模块之间相互作用,必须借助信号,这在一定程度上会造成代码不够简洁,可读性下降等缺点。
当然,变量也具有其特殊的优点,特别是用来描述一些复杂的算法,如图像处理,多维数组变换等。
三.位(矢量)与逻辑(矢量)
bit 或其矢量形式bit_vector只有’0’和’1’两种状态,数字电路中也只有’0’和’1’两种逻辑,因此会给初学者一个误区,认为采用位(矢量)则足够设计之用,而不必像std_logic那样出现’X’,’U’,’W’各种状态,增加编程难度。但实际情况却并非如此,以一个最简单D型触发器设计为例
… …
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Q<=D;
⑤ end if;
⑥ end process;
… …
实际中clk对数据端D的输入有一定的时间限制,即在clk上升沿附近(建立时间和保持时间之内),D必须保持稳定,否则Q输出会出现亚稳态,如下图所示。
图1 建立时间和保持时间
当clk和D时序关系不满足时,由于bit只有’0’或’1’,系统只能随机的从’0’和’1’中给Q输出,这样的结果显然是不可信的;而采用std_logic类型,则时序仿真时会输出为一个’X’,提醒用户建立保持时间存在问题,应重新安排D和clk之间时序关系。
此外,对于双向总线设计(前面已提及)、 FPGA/CPLD上电配置等问题,如果没有’Z’,’X’等状态,根本无法进行设计和有效验证。
四.关于进程
进程(Process)是VHDL中最为重要的部分,大部分设计都会用到Process结构,因此掌握Process的使用显得尤为重要。以下是初学和使用Process经常会出错的例子。
1. 多余时钟的引入
在设计时往往会遇到这种情况,需要对外部某个输入信号进行判断,当其出现上跳或下跳沿时,执行相应的操作,而该信号不像正常时钟那样具有固定占空比和周期,而是很随机,需要程序设计判断其上跳沿出现与否。这时,很容易写出如下程序:
① process(Ctl_a) -- Ctl_a即为该输入信号
② begin
③ if Ctl_a’event and Ctl_a=’1’ then
④ … … ; --执行相应操作
⑤ end if ;
⑥ end process;
由于出现第③行这类语句,综合工具自动默认Ctl_a为时钟,某些FPGA更会强行将该输入约束到时钟引脚上。而设计者的初衷只是想将其作为下位机的状态输入以进行判断。上面的程序容易造成多时钟现象,增加设计的难度。解决的办法可以如下,将Ctl_a增加一级状态Ctl_areg寄存,通过对Ctl_a和 Ctl_areg状态判断上跳与否,改正程序如下:
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Ctl_areg<=Ctl_a;--产生相邻状态
⑤ if Ctl_areg=’0’ and Ctl_a=’1’ then--上跳判断
⑥ … … ; --执行相应操作
⑦ end if;
⑧ end if;
⑨ end process;
程序中第④行用以产生两个相邻状态,第⑤行对前后状态进行判断是否有上跳现象发生。其中,需注意的是clk的时钟频率应明显快于Ctl_a信号的变化频率,以保证正确采样。
2. 输出多驱动
误用Process经常会引起输出多驱动源的发生,即在两个以上的进程内对同一信号赋值操作。以下程序就出现了这类情况:
⑴ Proc_a: process(clk)
⑵ begin
⑶ if clk’event and clk=’1’ then
⑷ Dout<=Din_A;
⑸ end if
⑹ end process;;
⑺
⑻ Proc_b:process(sel_en)
⑼ begin
⑽ if sel_en=’1’ then
⑾ Dout<=Din_B;
⑿ end if;
⒀ end process;
进程Proc_a和Proc_b中都出现了对Dout的赋值语句,设计者原本的想法是,只要合理控制好clk和sel_en输入,使其不发生冲突,即clk 上升沿时sel_en不为’1’;sel_en为’1’时,不出现clk的上升沿,这样Proc_a,Proc_b两个进程就不会发生冲突。但综合时,综合工具会将所有可能情况全部罗列进去,包括第⑶行和第⑽行同时成立的情况,此时对于Dout就有Din_A和Din_B两个输入驱动,Dout不知接收哪一个,因此该程序无法综合,改正的方法是只要将两个进程合并成一个即可。
由于进程在VHDL中的重要性,对此专门做了一个
总结
初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf
如下:
(1)一个进程中不允许出现两个时钟沿触发,(Xilinx公司CoolRunner系列CPLD支持单个时双钟的双触发沿除外)
(2)对同一信号赋值的语句应出现在单个进程内,不要在时钟沿之后加上else语句,如
if clk’event and clk=’1’ then - else … 的结构,现有综合工具支持不了这种特殊的触发器结构
(3)当出现多层IF语句嵌套时,最好采用CASE语句替代,一是减少多层嵌套带来的延时,二来可以增强程序的可读性
(4)顺序语句如IF语句、CASE语句、LOOP语句、变量赋值语句等必须出现在进程、函数或子程序内部,而不能单独出现在进程之外
(5)进程内部是顺序执行的,进程之间是并行运行的;VHDL中的所有并行语句都可以理解为特殊的进程,只是不以Process结构出现,其输入信号和判断信号就是隐含的敏感表
五.关于VHDL学习中的几点说明
与软件语言相比,VHDL最重要的特点就在于它的并行运行特性,当设计好的电路上电后,器件内部所有信号将同时并发工作,而不会以软件方式按照程序顺序执行,即使在进程内部也是趋向并行工作的。例如以下程序:
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ <= ;
⑤ <= ;
⑥ end if;;
⑦ end process;
综合的结果两个独立的D型触发器,虽然进程内部应按顺序执行,但是硬件实现后,只要采样到时钟上升沿, 和 状态会同时翻转,而不会先执行的变化,然后才会去执行的转变。因此,VHDL学习过程中,应加强硬件概念的理解,没有硬件概念或是硬件概念不强,在设计时,往往会将VHDL设计以软件编程的方式来处理,而得出一些不可思议的结果。
作为一门硬件描述语言,VHDL几乎可以用来描述现有的大型系统数字电路、算法以及其它设计。但是,限于目前综合工具的水平,VHDL中的许多语法还不能支持,例如:
dout<=din after 5 ns;
综合时就无法达到如此精度,因此这条语句主要用来编写测试激励,而很少出现在设计实体中。类似的情况还有很多,目前VHDL设计使用的也只是整个
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
中的一部分,这也正是VHDL的“可综合子集”性质,它一定程度上限制了VHDL的广泛应用,但是随着综合技术的发展,这种情况会逐渐得以改善,VHDL也将在各个领域中发挥出愈来愈重要的作用。
我所做的是一个双向总线的vhdl实现,其程序如下:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY bidir IS
PORT(
bidir : INOUT STD_LOGIC_VECTOR (7 DOWNTO 0);
oe, clk : IN STD_LOGIC;
inp : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
outp : OUT STD_LOGIC_VECTOR (7 DOWNTO 0));
END bidir;
ARCHITECTURE jiegou OF bidir IS
SIGNAL a : STD_LOGIC_VECTOR (7 DOWNTO 0);
SIGNAL b : STD_LOGIC_VECTOR (7 DOWNTO 0);
BEGIN
PROCESS(clk)
BEGIN
IF clk = '1' AND clk'EVENT THEN -- 上升沿触发
a <= inp;
outp <= b;
END IF;
END PROCESS;
PROCESS (oe, bidir)
BEGIN
IF( oe = '0') THEN
bidir <= "ZZZZZZZZ";
b <=bidir;
ELSE
bidir <= a;
b <= bidir;
END IF;
END PROCESS;
END jiegou;
在程序中,先是需调用库函数的说明,然后定义实体bidir,在其中定义了一个双向传输端口名bidir,时钟clk,选通端口oe,8位输入端口inp,8位输出端口outp;
其中bidir,inp outp的数据类型为std_logic_vector;而oe和clk的数据类型为std_logic.
接下来是结构体定义。在这里定义了一个名为jiegou的结构体;内部信号中用a表示8位输入,用b表示8位输出,接下来是并行处理语句begin开始。
在本例中有两个进程。第一个以时钟为信号量,这个进程表达了以上升沿为触发的数据由inp向a传输和由b向outp的传输;第二个进程表示在传输过程中的总线控制功能,语句含义是当总线不被选通的时候,对总线的输入输出是高阻状态;
当总线选通后实现数据的内部正常传输。
程序仿真时序如下:
总结:1。vhdl实体名必须和文件的存储名一样,否则编译通不过。文件必须存为vhd格式才能争确进行编译。
2.Vhdl对应各种实体有固定的名称,如本文所述的总线,我用其它实体名都不能正确完成编译,而必须用bidir。但是结构名可以随便取。
3.须把端口信号转换成内部定义的指定信号量才可以正确的进行程序。 4..不能把inp和outp代入进程中,而其它端口信号缺一不可。说明凡是中间变量都是必不可少的。而输入输出则是无需代入进程当中。
5.上升沿的表达可以前后颠倒。即and前后的表述可以互换。
036096356朱明辉
2003.12.19
(注:由于时间和水平的关系,我没能完成一份像样的大作业,而只能那这么个小程序来充数,实在汗颜,还望郭老师能够谅解!)