第一篇:VHDL 编程的一些心得体会
VHDL 编程的一些心得体会(转)http://www.dzjs.net/html/EDAjishu/2007/0131/1504.html
VHDL 是由美国国防部为描述电子电路所开发的一种语言,其全称为(Very High Speed Integrated Circuit)Hardware Description Language。与另外一门硬件描述语言 Verilog HDL 相比,VHDL 更善于描述高层的一些设计,包括系统级(算法、数据通路、控制)和行为级(寄存器传输级),而且 VHDL 具有设计重用、大型设计能力、可读性强、易于编译等优点逐渐受到硬件设计者的青睐。但是,VHDL 是一门语法相当严格的语言,易学性差,特别是对于刚开始接触 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’时,二.信号和变量
常数、信号和变量是 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输出会出现亚稳态,如下图所示。
当 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 中的重要性,对此专门做了一个总结如下:(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 设计使用的也只是整个标准中的一部分,这也正是VHDL 的“可综合子集”性质,它一定程度上限制了 VHDL 的广泛应用,但是随着综合技术的发展,这种情况会逐渐得以改善,VHDL 也将在各个领域中发挥出愈来愈重要的作用
第二篇:VHDL 编程的一些心得体会
VHDL 编程的一些心得体会(转)
VHDL 是由美国国防部为描述电子电路所开发的一种语言,其全称为(Very High Speed Integrated Circuit)Hardware Description Language。与另外一门硬件描述语言 Verilog HDL 相比,VHDL 更善于描述高层的一些设计,包括系统级(算法、数据通路、控制)和行为级(寄存器传输级),而且 VHDL 具有设计重用、大型设计能力、可读性强、易于编译等优点逐渐受到硬件设计者的青睐。但是,VHDL 是一门语法相当严格的语言,易学性差,特别是对于刚开始接触 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’时,二.信号和变量
常数、信号和变量是 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输出会出现亚稳态,如下图所示。
当 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 中的重要性,对此专门做了一个总结如下:
(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 设计使用的也只是整个标准中的一部分,这也正是VHDL 的“可综合子集”性质,它一定程度上限制了 VHDL 的广泛应用,但是随着综合技术的发展,这种情况会逐渐得以改善,VHDL 也将在各个领域中发挥出愈来愈重要的作用
第三篇:基于VHDL编程FPGA的地铁自动售票机
地铁自动售票机
一、设计要求
1、功能描述
用于模仿地铁售票自动售票,完成地铁售票的核心控制功能。
2、功能要求
售票机有两个进币孔,一个是输入硬币,识别的范围是一元硬币;一个是纸币,识别的范围是一元、两元、五元、十元、二十元。乘客可以连续多次投入钱币。乘客 一次只能选择一个出站口,购买车票时,乘客先选出站口,有六个出站口可供选择,再选择所需的票数,然后投币,投入的钱币达到或者超过所需金额时,售票机自 动出票,并找零。本次交易结束后,等待下一次交易。在选择出站口、所需票数以及在投币期间,乘客可以按取消键取消操作,钱币自动退出。
二、实验分析
1、买票时,乘客按下开始键,售票机进入站台选择程序,乘客选择出站口后,可以按取消键重新选择,否则售票机自动进入票数选择程序,同样这时可以按下取消键重新开始选择出站口以及票数。
2、当选择好出站口以及所需票数时,乘客可以投硬币或者用纸币,当所投的钱币总额大于或者等于票价时,售票机自动出票以及找零。期间,可以按下取消键重新开始选择,并退出所有的钱币。
3、乘客若还没选择出站口或者票数,就投币或者使用纸币,售票机会自动退出所有的钱币。
4、有六个站台可供乘客选择,每个乘客最多可以买3张票,六个站台编号为1到6,票价从2元依次递增到7。
三、系统流程图
四、程序源代码 LIBRARY IEEE;USE IEEE.std_logic_1164.ALL;USE IEEE.std_logic_arith.ALL;USE IEEE.std_logic_unsigned.ALL;ENTITY metrosell IS PORT(clk:in std_logic;startselect:in std_logic;sure:in std_logic;save your forward step(s)coin1y:in std_logic;pmoney1y:in std_logic;pmoney2y:in std_logic;pmoney5y:in std_logic;pmoney10y:in std_logic;money pmoney20y:in std_logic;money cancel:in std_logic;number:in std_logic_vector(3 downto 0);the tickets platform:in std_logic_vector(3 downto 0);want to reach moneystorage:out std_logic;acceptmo:out std_logic;stamp:out std_logic;--set the clock signal--start to select the platform--this button is to--1 yuan coin
--1 yuan paper money--2 yuan paper money--5 yuan paper money--10 yuan paper--20 yuan paper--cancel the forward step(s)--choose the number of--choose the platform you--to store the money--accept the money--stamp outgate charge:out std_logic_vector(3 downto 0);--the mount of charge,up to 15 yuan chargegate:out std_logic--charge outgate);END metrosell;ARCHITECTURE sell OF metrosell IS type state_type is(initial_type,selectp_type,selectnum_type,insert_type,stamp_type,charge_type);--define six types signal state:state_type;--define a shared state BEGIN main:process(clk,state,startselect,platform,number,coin1y,pmoney1y,pmoney2y,pmoney5y,pmoney10y,pmoney20y,cancel,sure)variable univalence :integer range 0 to 7;--the univalence of the ticket variable total_money :integer range 0 to 21;--the price of the ticket(s)variable selectp_alr:std_logic;--the flag of select platform type variable selectnum_alr:std_logic;--the flag of select number type variable stamp_alr:std_logic;--the flag of the stamp gate variable charge_alr:std_logic;--the flag of the charge gate variable money_reg:integer range 0 to 21;--the mount of money put in variable coin1y_f:std_logic;--the flag of one yuan coin variable pmoney1y_f:std_logic;--the flag of one yuan paper money variable pmoney2y_f:std_logic;--the flag of two yuan paper money variable pmoney10y_f:std_logic;--the flag of ten yuan paper money variable pmoney20y_f:std_logic;--the flag of twelve yuan paper money variable pmoney5y_f:std_logic;--the flag of five yuan paper money variable charge_reg:integer range 0 to 15;
begin if(rising_edge(clk))then case state is when initial_type => variables univalence:=0;selectp_alr:='0';selectnum_alr:='0';stamp_alr:='0';charge_alr:='0';money_reg:=0;total_money:=0;coin1y_f:='0';pmoney1y_f:='0';pmoney2y_f:='0';pmoney5y_f:='0';
--the register of charge--initialize some pmoney10y_f:='0';pmoney20y_f:='0';moneystorage<='0';stamp<='0';charge_reg:=0;charge<=“0000”;acceptmo<='0';chargegate<='0';if(startselect='1')then state<=selectp_type;end if;when selectp_type => if(selectp_alr='0'and cancel='0')then--choose the platform if(platform=“0001”)then univalence:=2;selectp_alr:='1';elsif(platform=“0010”)then univalence:=3;selectp_alr:='1';elsif(platform=“0011”)then univalence:=4;selectp_alr:='1';elsif(platform=“0100”)then univalence:=5;selectp_alr:='1';elsif(platform=“0101”)then univalence:=6;selectp_alr:='1';elsif(platform=“0110”)then univalence:=7;selectp_alr:='1';elsif(platform=“0000”)then univalence:=0;selectp_alr:='0';else null;end if;elsif(selectp_alr='1'and cancel='1')then state<=initial_type;elsif(selectp_alr='1'and sure='1')then state<=selectnum_type;end if;when selectnum_type =>--you can buy at most 3 tickets if(selectnum_alr='0'and cancel='0')then--choose the number of tickets if(number=“0001”)then if(univalence=2)then total_money:=2;selectnum_alr:='1';elsif(univalence=3)then total_money:=3;selectnum_alr:='1';elsif(univalence=4)then total_money:=4;selectnum_alr:='1';elsif(univalence=5)then total_money:=5;selectnum_alr:='1';elsif(univalence=6)then total_money:=6;selectnum_alr:='1';elsif(univalence=7)then total_money:=7;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;
if(number=“0010”)then if(univalence=2)then total_money:=4;selectnum_alr:='1';elsif(univalence=3)then total_money:=6;selectnum_alr:='1';elsif(univalence=4)then total_money:=8;selectnum_alr:='1';elsif(univalence=5)then total_money:=10;selectnum_alr:='1';elsif(univalence=6)then total_money:=12;selectnum_alr:='1';elsif(univalence=7)then total_money:=14;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;if(number=“0011”)then if(univalence=2)then total_money:=6;selectnum_alr:='1';elsif(univalence=3)then total_money:=9;selectnum_alr:='1';elsif(univalence=4)then total_money:=12;selectnum_alr:='1';elsif(univalence=5)then total_money:=15;selectnum_alr:='1';elsif(univalence=6)then total_money:=18;selectnum_alr:='1';elsif(univalence=7)then total_money:=21;selectnum_alr:='1';elsif(univalence=0)then total_money:=0;selectnum_alr:='0';else null;end if;end if;elsif(selectnum_alr='1'and cancel='1')then state<=initial_type;elsif(selectnum_alr='1'and sure='1')then state<=insert_type;end if;when insert_type => moneystorage<='1';if(money_reg
when 2 => charge<=“0010”;when 3 => charge<=“0011”;when 4 => charge<=“0100”;when 5 => charge<=“0101”;when 6 => charge<=“0110”;when 7 => charge<=“0111”;when 8 => charge<=“1000”;
end case;end if;
when 9 => charge<=“1001”;when 10 => charge<=“1010”;when 11 => charge<=“1011”;when 12 => charge<=“1100”;when 13 => charge<=“1101”;when 14 => charge<=“1110”;when 15 => charge<=“1111”;when others => charge<=“0000”;end case;if(charge_reg>0 and charge_alr='0')then chargegate<='1';charge_alr:='1';elsif(charge_reg=0 and charge_alr='0')then chargegate<='0';charge_alr:='1';else state<=initial_type;end if;end process main;END sell;
五、波形仿真
1、乘客按下开始按钮,进入选站台模式,选择二号站台,按下确定键,再选择票数为2张,按下确定键,售票机钱箱关闭,投入一张两元和五元纸币(对顺序没有要求),此时钱币总额大于票价,出两张票并找零一元。之后系统进入初始化状态。具体仿真如图 1 仿真1
图 1 仿真1
2、测试cancel键,当乘客按正确的操作完成选站台时,按下取消键,再重新选择,如图 2 cancel仿真,仿真波形如下。
图 2 cancel仿真
3、还是测试cancel键,当乘客选择好票数时,按下cancel键,然后重新选择两张单价为七块钱的六号站台票,投入一张20元和5元,找零六元。仿真波形如图 3 cancel仿真2
图 3 cancel仿真2
4、乘客选择五号站台,两张票,然后先后投入一元纸币,两元纸币,一元纸币,五元纸币,然后按下取消键,售票机自动放出所有的钱币。仿真如图 4 cancel仿真3。
图 4 cancel仿真3
六、心得体会
在我的设计中,有一个moneystorage信号量用于控制储存钱币箱的开与关,这个设计主要考虑到当乘客要求退币时,最好不是从售票机中取出投入的钱数,然后退还,设置了这个开关,就可以在按下取消键时,直接从储存钱币箱中退出钱币。
还有,乘客选择的站台以及票数,在售票机内部会自动将这两个信号传给出票系统,从而自动出票,以上写的程序只是让系统知道怎样收钱以及找零。
这次实验总体上来说比六人抢答器简单,但是因为这个售票机完全是自己写的,所以也不是想象中的那么简单。这也让我看出,要完全自己去做一件东西不是简单的,特别是要考虑很全面,还是要发一些时间的。
第四篇:VHDL实验报告
《创新实验》实验报告
—基于VHDL的编程和硬件实现
一、实验目的 1.2.3.4.熟悉和掌握硬件描述语言VHDL的基本语法及编写; 掌握软件Xilinx ISE 10.1的使用; 熟悉SDZ-6电子技术实验箱的使用;
了解节拍脉冲发生器等基本电路的实现;
5.了解八位二进制计数器的功能与设计; 6.学习键盘和七段数码管显示的控制和设计。
二、实验内容
1.Xilinx ISE 10.1软件的使用;
2.节拍脉冲发生器等基本电路的实现; 3.八位二进制计数器的实现 4.键盘扫描及显示的实现
三、实验器材
1、PC机
2、SDZ-6电子技术实验箱
3、正负5V电源
4、I/O接口线
四、软件的使用
在安装Xilinx10.1软件时,需要一个ID号,其实这个ID号是可以重复使用的,几个同学在官网注册后就可以共享ID号了。
安装完成之后就可以使用这个软件编写相应的VHDL的程序。1.新建工程
File—>New Project 弹出下面的对话框
输入工程名后单击Next。然后根据本实验的实验箱进行以下设置。
以后的步骤一般都是单击Next(有些资料上会介绍有些这些步骤的具体功能,但对于本实验不必用到),最后单击Finish,完成新建一个工程。在窗口的左边会出现刚刚新建的工程,如下:
2.新建一个VHDL的源文件。
在上图中,右击工程选择New Source,弹出如下对话框。
在对画框的左边选择VHDL Module,输入文件的名字(改名字最好是你定义的实体的名字)。单击Next。出现下面的对话框。
该对话框主要是对外部端口的编辑。可以直接跳过,即单击Next,在源文件上编辑端口。然后在接下来的对话框中单击Finish。完成建立一个源文件。窗口右边就会出现刚才编辑的源文件。
3.编写和编译代码
将事先编好的代码复制到源文件里,然后保存文件。选中左边的文件名,在窗体的左边出现如下编辑文档内容。
选择Synthesize —XST—》Check Syntax,双击Check Syntax,开始编译源文件。
4.软件仿真
其实仿真这一步可要可不要,很多程序都不需要仿真,有些程序即使仿真出错,但是最后结果却可以出来。因此,我们做实验时很少仿真,此处也不再赘述了。
5.综合
首先根据实验箱的安排布局,找到程序中外部接口的对应实验箱上的接口,进行接口对应,双击如下图所示的选项。
出现接口窗口如下,进行设置(具体参见老师发的文档SDZ电子实验箱的使用说明文档)保存,关闭即可
然后如下图从Implement Design开始依次双击综合。
6.下载
双击Configure Target Device综合完成之后,就出现下载对话框。右击鼠标键盘选择Add Xilinx Device,选择.bit文件。然后右击选择Program,就将程序烧录到实验板上了。
五、节拍脉冲发生器电路实现
1、实验题目:
参照时标系统的设计方法,用组合逻辑方法设计一个简单的节拍脉冲发生器,产生图1-6所示的节拍脉冲,并用单脉冲验证设计的正确性。在实验报告中画出完整电路,写出W1、W0和N1的表达式。
图1-6 简单的节拍脉冲发生器一周期的波形
设计提示:
1、由波形图求出节拍脉冲W1和W0的表达式,进而组合成N1的表达式。
2、注意节拍电平T1和T0的翻转时刻应在M0下降沿与M的上升沿同时出现的时刻。
3、注意D触发器的触发翻转要求。
2、实验步骤:
1.根据题目确定输出结果的逻辑表达式
W1M*M0*T1
W0M*M0*T1*S
N1W1W0
2.画出电路图
3.确定输入输出的外部端口 输入端口:M(由时钟产生)输出端口:W1,W0,N1 4.根据电路图写代码 5.编译,调试
3、实验代码 library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;——头文件
entity clk_div is
Port(clk : in STD_LOGIC;
w0 : out STD_LOGIC;
w1 : out STD_LOGIC;
N1 : out STD_LOGIC);end clk_div;
architecture Behavioral of clk_div is signal count : std_logic_vector(3 downto 0):=“0000”;signal a : std_logic;signal b : std_logic;signal temp : integer range 0 to 50;signal Q : std_logic;begin process(clk,Q)
begin if(clk'event and clk='1')then
——对clk进行分频
temp <= temp+1;if(temp =49)then
Q <= not Q;
end if;temp <= 0;end if;if(Q'event and Q='1')then
if(count =“1111”)then
count <=(others =>'0');else
count <=count+1;end if;end if;a <=(not clk and count(0))and count(1);
b <=(not clk and count(0))and(not count(1)and count(2));end process;w1 <= a;w0 <= b;N1 <=a or b;end Behavioral;
4、硬件实现与注意事项
硬件实现主要说的是外部端口和实验箱的对应问题。M:接的是时钟脉冲,即P150 W1:接LED灯显示结果,即P45 W0:接LED灯显示结果,即P44 N1:接LED灯显示结果,即P47 注意事项:
1.时钟脉冲频率太高,结果会显示的很快,因此首先对CLK进行50倍的分频。将频率降低以便观察结果。2.由于时钟频率过高,可能仿真不出来,因此就不必仿真。3.可能有些组编译通过但在综合时出现错误(是有关BUF的),这时就需要在CLK之前接入一个缓冲器。具体的加入代码如下: library UNISIM;
——头文件 use UNISIM.VComponents.all;entity test is
Port(clk : in STD_LOGIC;end test;
architecture Behavioral of test is signal ck:std_logic;
component IBUF
——定义缓冲器
port(I:in STD_LOGIC;
O:out STD_LOGIC);end component;begin UO:IBUF port map(I=>clk,O=>ck);——以后的ck代替clk 六、八位二进制计数器的实现 1. 实验题目
请用VHDL编写一个八位二进制计数器,具有异步清零功能、同步置数、计数功能。实验验证时,须用单脉冲进行验证。计数器的输出显示在显示器上。〖显示器可以是:①七段数码显示器,②LED发光二极管。〗
2. 实验代码
library IEEE;
——头文件 use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;library UNISIM;use UNISIM.VComponents.all;
entity Counter8 is
Port(set : in STD_LOGIC;
——低电平置数
reset : in STD_LOGIC;
——低电平异步清零
key : out STD_LOGIC;
——键盘输出口
clk : in STD_LOGIC;
——键盘的输入口,当成单脉冲使用
co : OUT STD_LOGIC;
——进位
architecture example of Counter8 is signal ck: std_logic;signal cc: std_logic;signal down : STD_LOGIC_VECTOR(7 DOWNTO 0):=“00000000”;signal kk : std_logic:='0';put : in STD_LOGIC_VECTOR(7 DOWNTO 0);——置数
load : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
——LED显示
end Counter8;
component IBUF
——设置缓冲器 port(I : in STD_LOGIC;
O : out STD_LOGIC);end component;
begin
key <=kk;load <=down;co <=cc;U0:IBUF port map(I=>clk,O=>ck);p0:PROCESS(ck)begin if(ck' event and ck='0')then
IF(set ='0')THEN
——低电平置数 down <=put;ELSE
down <=down+1;END IF;END IF;
IF(reset ='0')then
——低电平异步清零 down <=“00000000”;END IF;if(down=“11111111”)then
——进位设置 cc <='1';else cc <='0';end if;end process p0;end example;
3. 硬件实现与注意事项 硬件实现:
clk:接键盘的行或列,即P 29
key :接键盘的行或列与clk相对应,即P34 reset :接数字开关,即P62 set:接数字开关,即P61 co :接电平显示,即P45 put(0-7):全部接数字开关,即P73 P74 P70 P71 P68 P69 P63 P67 load(0-7):全部接电平显示,即P59 P60 P57 P58 P48 P49 P46 P47
注意事项: 1.由于在综合时出了问题,本实验在输入clk之前加入了一个缓冲器 2.在实验中发现数字开关的抖动比键盘大,就选用键盘作为单脉冲。3.本实验在题目的基础上,新增了进位显示功能。
七、键盘扫描及显示的实现 1.实验题目
请用VHDL编写一个键盘扫描程序,对实验箱上的4×4键盘(蓝色部分)进行扫描。当有某个键被按下时,该键的键值被显示在显示器上。〖显示器可以是:①七段数码显示器,②LED发光二极管。〗
2.实验代码
library IEEE;
——头文件 use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;library UNISIM;use UNISIM.VComponents.all;
ENTITY KEYDIS IS
PORT(clk
: IN std_logic;
——扫描时钟
row
: OUT std_logic_vector(3 DOWNTO 0);
column : IN std_logic_vector(3 DOWNTO 0);
dyp
: OUT std_logic_vector(7 DOWNTO 1));
——数码管显示 END KEYDIS;
ARCHITECTURE arch OF KEYDIS IS SIGNAL div_cnt : std_logic_vector(1 downto 0):=“00”;SIGNAL scan_key : std_logic_vector(3 DOWNTO 0):=“1110”;SIGNAL key_code : std_logic_vector(3 DOWNTO 0):=“0000”;
SIGNAL dyp_tmp : std_logic_vector(7 DOWNTO 1):=“0000001”;SIGNAL COUNT : INTEGER range 0 TO 30;signal ck : std_logic;component IBUF
——缓冲器的声明
port(I:in STD_LOGIC;
O:out STD_LOGIC);end component;BEGIN U1:IBUF port map(I=>clk,O=>ck);row <= scan_key;dyp <= dyp_tmp;PROCESS(ck)BEGIN
IF(ck' EVENT AND ck = '1')THEN
div_cnt <= div_cnt + 1;
END IF;
IF(ck' EVENT AND ck = '1')THEN
COUNT <= COUNT + 1;
PROCESS(div_cnt(1 downto 0))
——扫描行(out)输出,和时钟频率一样
BEGIN
CASE div_cnt(1 downto 0)IS
WHEN “00”=>
scan_key<=“1110”;WHEN “01”=> scan_key<=“1101”;WHEN “10”=> scan_key<=“1011”;WHEN “11”=>
IF COUNT = 30 THEN COUNT <= 0;END IF;END IF;END PROCESS;
scan_key<=“0111”;
WHEN OTHERS =>
NULL;
END CASE;END PROCESS;
PROCESS(ck)BEGIN IF(ck'EVENT AND ck='1')THEN
CASE scan_key IS
WHEN “1110” =>
CASE column IS
WHEN “1110” =>
key_code <= “0000”;
——编码器输入
WHEN “1101” =>
key_code <= “0001”;
WHEN “1011” =>
key_code <= “0010”;
WHEN “0111” =>
key_code <= “0011”;
WHEN OTHERS =>
NULL;
END CASE;
WHEN “1101” =>
CASE column IS
WHEN “1110” =>
key_code <= “0100”;
WHEN “1101” =>
key_code <= “0101”;
WHEN “1011” =>
key_code <= “0110”;
WHEN “0111” =>
key_code
WHEN OTHERS =>
NULL;
END CASE;
WHEN “1011” =>
CASE column IS
WHEN “1110” =>
key_code
WHEN “1101” =>
key_code
WHEN “1011” =>
key_code
WHEN “0111” =>
key_code
WHEN OTHERS =>
NULL;
END CASE;
WHEN “0111” =>
CASE column IS
WHEN “1110” =>
key_code
WHEN “1101” =>
key_code
WHEN “1011” =>
key_code
WHEN “0111” =>
key_code
WHEN OTHERS =>
NULL;
END CASE;
WHEN OTHERS =>
key_code <= “1111”;
END CASE;
END IF;
<= “0111”;
<= “1000”;
<= “1001”;
<= “1010”;
<= “1011”;
<= “1100”;
<= “1101”;
<= “1110”;
<= “1111”;
END PROCESS;
--显示键值
PROCESS(key_code)
BEGIN--延时防抖动
IF COUNT = 0 THEN--
IF key_code = NOT “0000” THEN
CASE key_code IS
WHEN “0000” =>
dyp_tmp <= “1111110”;
WHEN “0001” =>
dyp_tmp <= “0110000”;
WHEN “0010” =>
dyp_tmp <= “1101101”;
WHEN “0011” =>
dyp_tmp <= “1111001”;
WHEN “0100” =>
dyp_tmp <= “0110011”;
WHEN “0101” =>
dyp_tmp <= “1011011”;
WHEN “0110” =>
dyp_tmp <= “1011111”;
WHEN “0111” =>
dyp_tmp <= “1110000”;
WHEN “1000” =>
dyp_tmp <= “1111111”;
WHEN “1001” =>
dyp_tmp <= “1111011”;
WHEN “1010” =>
dyp_tmp <= “1110111”;
WHEN “1011” =>
dyp_tmp <= “0011111”;
WHEN “1100” =>
dyp_tmp <= “1001110”;
WHEN “1101” =>
dyp_tmp <= “0111101”;
WHEN “1110” =>
dyp_tmp <= “1001111”;
WHEN “1111” =>
dyp_tmp <= “1000111”;
WHEN OTHERS =>
NULL;
END CASE;
——编码器输出并且数码管显示
END IF;--END IF;
END PROCESS;END arch;
3.硬件实现与注意事项 硬件实现:
clk:接扫描时钟,即P150 column(0-3):对应于键盘的列值,即P34 P33 P36 P35 row(0-3): 对应于键盘的行值,即P30 P31 P27 P29 dyp(1-7):对应于数码管显示,即P123 P125 P127 P129 P132 P133 P134 注意事项:
1.扫描时钟与显示时钟是不对应的,扫描的时钟快一些,显示时钟是在扫描时钟基础上的延时,该功能由参数COUNT实现。扫描程序和显示程序是分开写的。2.行和列其实没什么区别,只要按照正确的秩序来排列column和row结果就出正确。从另一方面,要得到正确的,希望的扫描数值,就必须安排好这行和列。以上的硬件实现的安排,是我们组测试了几遍的结果。3.代码中有很多语法如When else、With select、Case,其中有很多的技巧值得我们举一反三的。比如,键盘扫描时如何显示1110 1101 1011 0111,我们可以用移位寄存器实现,也可以像程序代码那样引入一个变量div_cnt,让其跟着扫描脉冲自动循环四位。另外,显示部分引入了译码器的原理实现数码管的16数值的显示。
4.本实验使用静态数码管进行显示。首先用一个数码管显示16个键值0~f,然后再用双数码管显示键值,从01~16显示键盘的键值。
5.数码管显示参数从高位到地位分别对应实验箱数码管的a~f,最后一位是小数点,并且数码管是共阴的,即高电平是数码管对应的LED才会发光。实验箱上的数码管LED对应关系如下:
八、实验感想
经过这次的合作,我们深深的体会到团队合作的重要性。在本次实验中,我们组遇到了很多困难。不过,我们互帮互助,互相鼓励,最终我们组还是能在比较快的时间内把实验结果做出来。
第一次实验中也就是节拍脉冲发生器电路实现,由于实验箱上最慢的时钟频率是100Hz,结果显示的太快,就需要对时钟进行分频,我们组很快在写出了分频的代码,然后进行编译和仿真。但是仿真的结果怎么也出不来。当时我们组有三个人就有点不耐烦了,准备放弃下次再弄。但是另外一个同学坚持综合,下载的步骤,结果就在不经意间出来了。事后我们才知道这个实验仿真是出不来的,也就是不用仿真这一步的。只要编译,综合对了就能下载并且结果正确。我们当时想辛亏组里有一个坚持不懈的人,否则,我们还得拖一个星期才能检查。
第二次做八位二进制计数器的实现时,我们吸取上次的教训不做仿真。但是实验要求需要一个单脉冲,异步清零端,置数端,八个数值显示。这一算共需要十一个数字开关,但实验箱上却只有十个数字开关。不过我们首先先用试验箱上的100Hz接口代替单脉冲,并对他进行50倍分频,结果显示的非常好。然后我们将异步清零放在一个键盘上实现,单脉冲放在数字开关上实现,结果抖动的非常厉害。在和别的组同学交流之后,我们组将单脉冲放在键盘上实现,抖动现象明显缓解。另外我们组还在此基础上增加了一个进位显示的功能。
在实验显示这块,我们组希望尽可能多用实验箱上给我们提供的显示仪器(即LED电平显示和数码管显示)。我们把LED电平显示安排在八位二进制计数器的实现的实验上,把数码管显示安排在键盘扫描及显示的实现的实验上。
第三次做键盘扫描及显示的实现的实验是,由于这次程序比较复杂,我们组采取二种办法。一个人根据自己所学所看的资料写代码(前二个实验都是我们自己写的代码),另一个人在网上收资料。结果我们自己写的代码有些不够严谨,结果循环显示,显然代码没有编好,然后我们组四个就参考网上收的代码,先将代码的含义弄清楚,然后我们在对代码稍作修改,就完成了此次的代码编写。这次实验涉及的知识较前面二个实验都多一些。比如,如何扫描键盘,如何将结果显示在数码管上,如何使用数码管(是共阴的还是共阳的),如何防抖等等。具体看上面的键盘扫描及显示的实现的注意事项。
此次实验我们基本达到题目的要求,通过这次实验我们对VHDL有了更清晰的认识。虽然实验过程中我们成员之间有争论,综合、下载、调试时感觉很累,但挺一挺就过去了,困难过后才会感觉到成功的甘甜。
第五篇:VHDL体会
学习心得
——《eda技术实用教程》
本学期对《eda技术实用教程--vhdl版》的学习为我的专业知识学习打开了一个全新的窗口——微电子技术领域。对eda技术,我更是有了全新的认识。
微电子技术的进步主要表现在大规模集成电路加工技术即半导体工艺技术的发展上,使得表征半导体工艺水平的线宽已经达到了纳米级。所以,集成电路设计正在不断地向超大规模、极低功耗和超高速的方向发展。
而现代电子设计技术的核心已日趋转向基于计算机的电子设计自动化技术,即eda技术。eda技术就是依赖功能强大的计算机,在eda工具软件平台上,对以硬件描述语言hdl为系统逻辑描述手段完成的设计文件,自动地完成逻辑编译、化简、分割、综合、布局布线以及逻辑优化和仿真测试,直至实现既定的电子线路系统功能。eda技术使得设计者的工作仅限于利用软件的方式,即利用硬件描述语言和eda软件来完成对系统硬件功能的实现,这是电子设计技术的一个巨大进步。eda技术在进入21世纪后,得到了更大的发展。嵌入式处理器软核的成熟,使得sopc步入大规模应用阶段。电子技术领域全方位融入eda技术,除了日益成熟的数字技术外,传统的电路系统设计建模理念发生了重大的变化。同时,eda使得电子领域各学科的界限更加模糊,更加互为包容。这些都利于设计人员利用eda技术进行电子系统设计,如全定制或半定制asic设计,fpga/cpld开发应用和印制电路板。
从eda技术的特点不难看出,相比于传统的数字电子系统或ic设计,eda技术拥有独特的优势。在传统的数字电子系统或ic设计中,手工设计占了较大的比例。因此,也存在很多缺点。例如:复杂电路的设计、调试十分困难;由于无法进行硬件系统仿真,如果某一过程存在错误,查找和修改十分不便;设计过程中产生大量文档,不易管理;可移植性差等。相比之下,eda技术有很大不同。它运用hdl对数字系统进行抽象的行为与功能描述到具体的内部线路结构描述,从而可以在电子设计的各个阶段、各个层次进行计算机模拟验证,保证设计过程的正确性,可以大大降低设计成本,缩短设计周期。由于有各类库的支持,能够完成各种自动设计过程。它极大地简化了设计文档的管理,逻辑设计仿真测试技术也日益强大。vhdl在现在的eda设计中使用最多,也拥有几乎所有主流eda工具的支持。vhdl作为一个规范语言和建模语言,不仅可以作为系统模拟的建模工具,而且可以作为电路系统的设计工具,可以利用软件工具将vhdl源码自动地转化为文本方式表达的基本逻辑元件连接图,即网表文件。这种方法显然对于电路自动设计是一个极大的推进。它具有很强的电路描述和建模能力,能从多个层次对数字系统进行建模和描述,从而大大简化了硬件设计任务,提高了设计效率和可靠性。eda技术良好的可移植性与可测试性,将所有设计环节纳入统一的自顶向下的设计方案中。它不但在整个设计流程上充分利用计算机的自动设计能力、在各个设计层次上利用计算机完成不同内容的仿真模拟,而且在系统板设计结束后仍可利用计算机对硬件系统进行完整的测试。
书中通过大量的图示对pld硬件特性与编程技术进行了形象的讲解,不仅融合了之前学习的关于电路设计的知识还将eda的技术加入其中。对vhdl语言的详尽讲解更是让我深刻理解了vhdl语言的编程原理。由于本门课程是一门硬件学习课程,所以实验必不可少。通过课程最后实验,我体会一些vhdl语言相对于其他编程语言的特点。
相对于其它计算机语言的学习,如c 或汇编语言,vhdl 具有明显的特点。这不仅仅是由于vhdl 作为一种硬件描述语言的学习需要了解较多的数字逻辑方面的硬件电路知识,包括目标芯片基本结构方面的知识更重要的是由于vhdl 描述的对象始终是客观的电路系统。由于电路系统内部的子系统乃至部分元器件的工作状态和工作方式可以是相互独立、互不相关的,也可以是互为因果的。这表明,在任一时刻,电路系统可以有许多相关和不相关的事件同时并行发生。例如可以在多个独立的模块中同时入行不同方式的数据交换和控制信号传输,这种并行工作方式是任何一种基于cpu 的软件程序语言所无法描绘和实现的。传统的软件编程语言只能根据cpu 的工作方式,以排队式指令的形式来对特定的事件和信息进行控制或接收。在cpu 工作的任一时间段内只能完成一种操作。因此,任何复杂的程序在一个单cpu 的计算机中的运行,永远是单向和一维的。因而程序设计者也几乎只需以一维的思维模式就可以编程和工作了。vhdl 虽然也含有类似于软件编程语言的顺序描述语句结构,但其工作方式是完全不同的。软件语言的语句是根据cpu 的顺序控制信号,按时钟节拍对应的指令周期节拍逐条运行的,每运行一条指令都有确定的执行周期。但 vhdl 则不同,从表面上观,vhdl 的顺序语句与软件语句有相同的行为描述方式,但在标准的仿真执行中有很大的区别。vhdl 的语言描述只是综合器赖以构成硬件结构的一种依据,但进程语句结构中的顺序语句的执行方式决非是按时钟节拍运行的。实际情况是其中的每一条语句的执行时间几乎是0(但该语句的运行时间却不一定为0),即1000 条顺序语句与10 条顺序语句的执行时间是相同的。在此,语句的运行和执行具有不同的概念(在软件语言中,它们的概念是相同),的执行是指启动一条语句,允许它运行一次,而运行就是指该语句完成其设定的功能。
通过实验,我认识到理论要与实际结合,培养动手动脑能力的重要性,做事情要抱着一丝不苟的态度,这样才能做好事情。同时也入一步了解到eda的强大之处,硬件电路的优秀的地方,对硬件方面更感兴趣了。这门课程的学习,为我以后的专业知识的学习打下了良好的基础。篇二:vhdl 编程的一些心得体会 vhdl 编程的一些心得体会(转)vhdl 是由美国国防部为描述电子电路所开发的一种语言,其全称为(very high speed integrated circuit)hardware description language。与另外一门硬件描述语言 verilog hdl 相比,vhdl 更善于描述高层的一些设计,包括系统级(算法、数据通路、控制)和行为级(寄存器传输级),而且 vhdl 具有设计重用、大型设计能力、可读性强、易于编译等优点逐渐受到硬件设计者的青睐。但是,vhdl 是一门语法相当严格的语言,易学性差,特别是对于刚开始接触 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’时,二.信号和变量
常数、信号和变量是 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输出会出现亚稳态,如下图所示。
当 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)-贪吃蛇
一、课程设计目的
1)巩固和加深所学电子技术课程的基本知识,提高综合运用所学知识的能力; 2)培养根据课题需要选用参考书、查阅手册、图表和文献资料的能力,提高学生独立解决工程实际问题的能力 3)通过设计方案的分析比较、设计计算、元件选择及电路安装调试等环节.初步掌握简单实用电路的工程设计方法。4)提高动手能力.掌握常用仪器设备的正确使用方法,学会对简单实用电路的实验调试和对整机指标的测试方法,5)学习vhdl和verilog hdl语言,熟悉de0电路板。提高对软件与硬件之间关系的认识与了解
二、设计任务与要求
设计任务:设计一个贪吃蛇小游戏
要求和指标:
1.用ps2键盘作为输入设备,用lcd作为显示器。2.自定义蛇的图像和老鼠的图像,用四个按键控制蛇的运动方向,完成贪食蛇游戏,蛇撞“墙”、边或者游戏时间到,游戏结束。3.老鼠出现的地方是随机的,在某个地点出现的时间是蛇走15步的时间,如果15步之内没有被吃掉,它就会在其它地方随机出现。;4.在旁边显示得分情况和游戏的剩余时间。
三、方案设计与论证
1、vga显示
vga标准是一种计算机显示标准,最初是由ibm公司在1987 年提出的一种
视频传输标准,在彩色显示器领域得到了广泛应用。vga管脚中,vga_hs和vga_vs分别是水平扫描信号和竖直扫描信号,vga_r, vga_g和vga_b是颜色控制信号,控制当前显示的像素色彩。利用水平扫描信号和竖直扫描信号实现二维平面的像素扫描显示,程序中中我們利用cnt_h与cnt_v信号来控制,以确认程序正确的将色彩输出到屏幕上。将屏幕分成30*40的矩阵,每个矩阵块根据不同的值赋予不同的颜色。屏幕是从最左上角的(4,4)坐标开始扫描更新,可以将屏幕视为x-y平面來看,根据矩阵点值赋予不同颜色绘制游戏框架并且实时显示蛇与老鼠
在做vga显示前先进行了彩条显示,以确保颜色显示正确,结果如下:
根据彩条显示绘制游戏框架,并定义蛇与老鼠的颜色。