基于FPGA/CPLD设计与实现UART(VHDL)

[复制链接]
 楼主| cwvin 发表于 2009-4-4 18:04 | 显示全部楼层 |阅读模式
1&nbsp;引言<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于微电子学和计算机科学的迅速发展,给EDA(电子设计自动化)行业带来了巨大的变化。特别是进入20世纪90年代后,电子系统已经从电路板级系统集成发展成为包括ASIC、FPGA/CPLD和嵌入系统的多种模式。可以说EDA产业已经成为电子信息类产品的支柱产业。EDA之所以能蓬勃发展的关键因素之一就是采用了硬件描述语言(HDL)描述电路系统。就FPGA和CPLD开发而言,比较流行的HDL主要有Verilog&nbsp;HDL、VHDL、ABEL-HDL和&nbsp;AHDL&nbsp;等,其中VHDL和Verilog&nbsp;HDL因适合标准化的发展方向而最终成为IEEE标准。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面的设计就是用VHDL来完成实现的。<br /><br />2&nbsp;UART设计实例<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常设计数字电路大都采用自顶向下将系统按功能逐层分割的层次化设计方法,这比传统自下向上的EDA设计方法有更明显的优势(当时的主要设计文件是电路图)。因为由自顶向下的设计过程可以看出,从总体行为设计开始到最终逻辑综合,形成网络表为止。每一步都要进行仿真检查,这样有利于尽早发现系统设计中存在的问题,从而可以大大缩短系统硬件的设计周期。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面以UART的设计为例具体说明:(本设计只对本设计的总模块做各种基于MAX+PLUS&nbsp;II环境下的各种分析,对于各分模块只是作些必要的说明。)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART(即Universal&nbsp;Asynchronous&nbsp;Receiver&nbsp;Transmitter&nbsp;通用异步收发器)是一种应用广泛的短距离串行传输接口。UART允许在串行链路上进行全双工的通信。串行外设用到的RS232-C异步串行接口,一般采用专用的集成电路即UART实现。如8250、8251、NS16450等芯片都是常见的UART器件,这类芯片已经相当复杂,有的含有许多辅助的模块(如FIFO),有时我们不需要使用完整的UART的功能和这些辅助功能。或者设计上用到了FPGA/CPLD器件,那么我们就可以将所需要的UART功能集成到FPGA内部。使用VHDL将UART的核心功能集成,从而使整个设计更加紧凑、稳定且可靠。本文应用EDA技术,基于FPGA/CPLD器件设计与实现UART。<br /><br />2.1&nbsp;UART简介<br />2.1.1&nbsp;UART结构<br />&nbsp;&nbsp;&nbsp;&nbsp;UART主要有由数据总线接口、控制逻辑、波特率发生器、发送部分和接收部分等组成。本设计主要设计UART中最重要的发送部分和接收部分,其他部分设计不在赘述。<br />&nbsp;&nbsp;&nbsp;&nbsp;功能包括发送缓冲器(tbr)、发送移位寄存器(tsr)、帧产生、奇偶校验、并转串、数据接收缓冲器(rbr)、接收移位寄存器(rsr)、帧产生、奇偶校验、串转并。图1是UART的典型应用。<br />&nbsp;<br />图1<br />2.1.2&nbsp;UART的帧格式<br />UART的帧格式如图2所示。<br />&nbsp;<br />图2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;包括线路空闲状态(idle,高电平)、起始位(start&nbsp;bit,低电平)、5~8位数据位(data&nbsp;bits)、校验位(parity&nbsp;bit,可选)和停止位(stop&nbsp;bit,位数可为1、1.5、2位)。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这种格式是由起始位和停止位来实现字符的同步。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART内部一般有配置寄存器,可以配置数据位数(5~8位)、是否有校验位和校验的类型、停止位的位数(1,1.5,2)等设置。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本设计没有奇偶校验位,所设置的奇偶校验只是检验数据中是否有奇数或偶数个1。数据位为8位,停止位为1位。<br /><br />2.2&nbsp;UART的设计与实现<br />2.2.1&nbsp;UART发送器<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;发送器每隔16个CLK16时钟周期输出1位,次序遵循1位起始位、8位数据位、1位停止位。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPU何时可以往发送缓冲器tbr写入数据,也就是说CPU要写数据到tbr时必须判断当前是否可写,如果不判这个条件,发送的数据会出错。本设计由wrn控制。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据的发送是由微处理器控制,微处理器给出wrn信号,发送器根据此信号将并行数据din[7..0]锁存进发送缓冲器tbr[7..0],并通过发送移位寄存器tsr[7..0]发送串行数据至串行数据输出端sdo。在数据发送过程中用输出信号tbre、tsre作为标志信号,当一帧数据由发送缓冲器tbr[7..0]送到发送发送移位寄存器tsr[7..0]时,tbre信号为1,而数据由发送移位寄存器tsr[7..0]串行发送完毕时,tsre信号为1,通知CPU在下个时钟装入新数据。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;发送器端口信号如图3所示。<br />&nbsp;<br />图3<br />引入发送字符长度和发送次序计数器no_bits_sent,实现设计的源程序如下。<br /><br />library&nbsp;ieee&nbsp;;<br />use&nbsp;ieee.std_logic_1164.all&nbsp;;<br />use&nbsp;ieee.std_logic_arith.all&nbsp;;<br />entity&nbsp;txmit&nbsp;is<br />port&nbsp;(rst,clk16x,wrn&nbsp;:&nbsp;in&nbsp;std_logic&nbsp;;<br />din&nbsp;:&nbsp;in&nbsp;std_logic_vector(7&nbsp;downto&nbsp;0)&nbsp;;<br />tbre&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;;<br />tsre&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;;<br />sdo&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;)&nbsp;;<br />end&nbsp;txmit&nbsp;;<br /><br />architecture&nbsp;v1&nbsp;of&nbsp;txmit&nbsp;is<br />signal&nbsp;clk1x_enable&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;tsr&nbsp;:&nbsp;std_logic_vector&nbsp;(7&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;tbr&nbsp;:&nbsp;std_logic_vector&nbsp;(7&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;parity&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;clkdiv&nbsp;:&nbsp;unsigned&nbsp;(3&nbsp;downto&nbsp;0)&nbsp;;&nbsp;--用来控制数据采样时钟的<br />signal&nbsp;clk1x&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;no_bits_sent&nbsp;:&nbsp;unsigned&nbsp;(3&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;wrn1&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;wrn2&nbsp;:&nbsp;std_logic&nbsp;;<br />begin<br /><br />process&nbsp;(rst,clk16x)&nbsp;--对wrn进行脉宽处理,以防接收数据错误<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />wrn1&nbsp;&lt=&nbsp;'1'&nbsp;;<br />wrn2&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />wrn2&nbsp;&lt=&nbsp;wrn1&nbsp;;<br />wrn1&nbsp;&lt=&nbsp;wrn&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk16x)&nbsp;--对clk1x_enable进行控制<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />clk1x_enable&nbsp;&lt=&nbsp;'0'&nbsp;;<br />tbre&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;wrn1&nbsp;=&nbsp;'0'&nbsp;and&nbsp;wrn2&nbsp;=&nbsp;'1'&nbsp;then<br />tbre&nbsp;&lt=&nbsp;'0'&nbsp;;<br />clk1x_enable&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;std_logic_vector(no_bits_sent)&nbsp;=&nbsp;&quot;0010&quot;&nbsp;then<br />tbre&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;std_logic_vector(no_bits_sent)&nbsp;=&nbsp;&quot;1101&quot;&nbsp;then<br />clk1x_enable&nbsp;&lt=&nbsp;'0'&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,wrn)&nbsp;--接收数据至tbr<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />tbr&nbsp;&lt=&nbsp;(others&nbsp;=&gt&nbsp;'0')&nbsp;;<br />elsif&nbsp;wrn'event&nbsp;and&nbsp;wrn&nbsp;=&nbsp;'0'&nbsp;then<br />tbr&nbsp;&lt=&nbsp;din&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br />process&nbsp;(rst,clk16x,clk1x_enable)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />clkdiv&nbsp;&lt=&nbsp;&quot;0000&quot;&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;clk1x_enable&nbsp;=&nbsp;'1'&nbsp;then<br />clkdiv&nbsp;&lt=&nbsp;clkdiv&nbsp;+&nbsp;&quot;0001&quot;&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />clk1x&nbsp;&lt=&nbsp;clkdiv(3)&nbsp;;&nbsp;--产生clk1x时钟<br /><br />process&nbsp;(rst,clk1x,no_bits_sent,tbr)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />sdo&nbsp;&lt=&nbsp;'1'&nbsp;;<br />tsre&nbsp;&lt=&nbsp;'1'&nbsp;;<br />tsr&nbsp;&lt=&nbsp;&quot;00000000&quot;&nbsp;;<br />parity&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;clk1x'event&nbsp;and&nbsp;clk1x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;std_logic_vector(no_bits_sent)&nbsp;=&nbsp;&quot;0001&quot;&nbsp;then<br />tsr&nbsp;&lt=&nbsp;tbr&nbsp;;&nbsp;--发送缓冲器tbr数据进入发送移位寄存器tsr<br />tsre&nbsp;&lt=&nbsp;'0'&nbsp;;&nbsp;--发送移位寄存器空标志置“0”<br />elsif&nbsp;std_logic_vector(no_bits_sent)&nbsp;=&nbsp;&quot;0010&quot;&nbsp;then<br />sdo&nbsp;&lt=&nbsp;'0'&nbsp;;&nbsp;--发送起始位信号“0”<br />elsif&nbsp;std_logic_vector(no_bits_sent)&nbsp;&gt=&nbsp;&quot;0011&quot;&nbsp;and&nbsp;std_logic_vector(no_bits_sent)&nbsp;&lt=&nbsp;&quot;1010&quot;&nbsp;then<br />tsr&nbsp;&lt=&nbsp;tsr(6&nbsp;downto&nbsp;0)&nbsp;&&nbsp;'0'&nbsp;;&nbsp;--从低位到高位进行移位输出至串行输出端sdo<br />sdo&nbsp;&lt=&nbsp;tsr(7)&nbsp;;<br />parity&nbsp;&lt=&nbsp;parity&nbsp;xor&nbsp;tsr(7)&nbsp;;&nbsp;--数据位中的1校验<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk1x,clk1x_enable)&nbsp;--产生发送字符长度和发送次序计数器<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;or&nbsp;clk1x_enable&nbsp;=&nbsp;'0'&nbsp;then<br />no_bits_sent&nbsp;&lt=&nbsp;&quot;0000&quot;&nbsp;;<br />elsif&nbsp;clk1x'event&nbsp;and&nbsp;clk1x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;clk1x_enable&nbsp;=&nbsp;'1'&nbsp;then<br />no_bits_sent&nbsp;&lt=&nbsp;no_bits_sent&nbsp;+&nbsp;&quot;0001&quot;&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br />end&nbsp;;<br /><br />2.2.2&nbsp;UART接收器&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;串行数据帧和接收时钟是异步的,发送来的数据由逻辑1变为逻辑0可以视为一个数据帧的开始。接收器先要捕捉起始位,确定rxd输入由1到0,逻辑0要8个CLK16时钟周期,才是正常的起始位,然后在每隔16个CLK16时钟周期采样接收数据,移位输入接收移位寄存器rsr,最后输出数据dout。还要输出一个数据接收标志信号标志数据接收完。<br />接收器的端口信号如图4所示。<br />&nbsp;<br />图4<br />引入接收字符长度和接收次序计数器no_bits_rcvd,实现设计的源程序如下。由于与发送器的一些说明相似,这里就不再重复。<br /><br />library&nbsp;ieee&nbsp;;<br />use&nbsp;ieee.std_logic_1164.all&nbsp;;<br />use&nbsp;ieee.std_logic_arith.all&nbsp;;<br />entity&nbsp;rcvr&nbsp;is<br />port&nbsp;(rst,clk16x,rxd,rdn&nbsp;:&nbsp;in&nbsp;std_logic&nbsp;;<br />dout&nbsp;:&nbsp;out&nbsp;std_logic_vector&nbsp;(7&nbsp;downto&nbsp;0)&nbsp;;<br />data_ready&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;;<br />framing_error&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;;<br />parity_error&nbsp;:&nbsp;out&nbsp;std_logic&nbsp;)&nbsp;;<br />end&nbsp;rcvr&nbsp;;<br />architecture&nbsp;v1&nbsp;of&nbsp;rcvr&nbsp;is<br />signal&nbsp;rxd1&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;rxd2&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;clk1x_enable&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;clkdiv&nbsp;:&nbsp;unsigned&nbsp;(3&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;rsr&nbsp;:&nbsp;unsigned&nbsp;(7&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;rbr&nbsp;:&nbsp;unsigned&nbsp;(7&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;no_bits_rcvd&nbsp;:&nbsp;unsigned&nbsp;(3&nbsp;downto&nbsp;0)&nbsp;;<br />signal&nbsp;parity&nbsp;:&nbsp;std_logic&nbsp;;<br />signal&nbsp;clk1x&nbsp;:&nbsp;std_logic&nbsp;;<br />begin<br /><br />process&nbsp;(rst,clk16x)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />rxd1&nbsp;&lt=&nbsp;'1'&nbsp;;<br />rxd2&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />rxd2&nbsp;&lt=&nbsp;rxd1&nbsp;;<br />rxd1&nbsp;&lt=&nbsp;rxd&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk16x,rxd1,rxd2,no_bits_rcvd)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;or&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;=&nbsp;&quot;1100&quot;&nbsp;then<br />clk1x_enable&nbsp;&lt=&nbsp;'0'&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;rxd1&nbsp;=&nbsp;'0'&nbsp;and&nbsp;rxd2&nbsp;=&nbsp;'1'&nbsp;then<br />clk1x_enable&nbsp;&lt=&nbsp;'1'&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk16x,rdn,no_bits_rcvd)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;or&nbsp;rdn&nbsp;=&nbsp;'0'&nbsp;then<br />data_ready&nbsp;&lt=&nbsp;'0'&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;=&nbsp;&quot;1100&quot;&nbsp;then<br />data_ready&nbsp;&lt=&nbsp;'1'&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk16x,clk1x_enable)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />clkdiv&nbsp;&lt=&nbsp;&quot;0000&quot;&nbsp;;<br />elsif&nbsp;clk16x'event&nbsp;and&nbsp;clk16x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;clk1x_enable&nbsp;=&nbsp;'1'&nbsp;then<br />clkdiv&nbsp;&lt=&nbsp;clkdiv&nbsp;+&nbsp;&quot;0001&quot;&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />clk1x&nbsp;&lt=&nbsp;clkdiv(3)&nbsp;;<br /><br />process&nbsp;(clk1x,rst)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;then<br />rsr&nbsp;&lt=&nbsp;&quot;00000000&quot;&nbsp;;<br />rbr&nbsp;&lt=&nbsp;&quot;00000000&quot;&nbsp;;<br />parity&nbsp;&lt=&nbsp;'1'&nbsp;;<br />framing_error&nbsp;&lt=&nbsp;'0'&nbsp;;<br />parity_error&nbsp;&lt=&nbsp;'0'&nbsp;;<br />elsif&nbsp;clk1x'event&nbsp;and&nbsp;clk1x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;&gt=&nbsp;&quot;0001&quot;&nbsp;and&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;&lt&nbsp;&quot;1001&quot;&nbsp;then&nbsp;---&nbsp;数据帧数据由接收串行数据端移位入接收移位寄存器<br />rsr(0)&nbsp;&lt=&nbsp;rxd2&nbsp;;<br />rsr(7&nbsp;downto&nbsp;1)&nbsp;&lt=&nbsp;rsr(6&nbsp;downto&nbsp;0)&nbsp;;<br />parity&nbsp;&lt=&nbsp;parity&nbsp;xor&nbsp;rsr(0)&nbsp;;<br />elsif&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;=&nbsp;&quot;1010&quot;&nbsp;then<br />rbr&nbsp;&lt=&nbsp;rsr&nbsp;;&nbsp;--接收移位寄存器数据进入接收缓冲器<br />elsif&nbsp;parity&nbsp;=&nbsp;'0'&nbsp;then<br />parity_error&nbsp;&lt=&nbsp;'1'&nbsp;;<br />elsif&nbsp;std_logic_vector(no_bits_rcvd)&nbsp;=&nbsp;&quot;1001&quot;&nbsp;and&nbsp;rxd2&nbsp;=&nbsp;'0'&nbsp;then<br />framing_error&nbsp;&lt=&nbsp;'1'&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br /><br />process&nbsp;(rst,clk1x,clk1x_enable,no_bits_rcvd)<br />begin<br />if&nbsp;rst&nbsp;=&nbsp;'1'&nbsp;or&nbsp;(std_logic_vector(no_bits_rcvd)&nbsp;=&nbsp;&quot;1100&quot;&nbsp;and&nbsp;clk1x_enable&nbsp;=&nbsp;'0')&nbsp;then<br />no_bits_rcvd&nbsp;&lt=&nbsp;&quot;0000&quot;&nbsp;;<br />elsif&nbsp;clk1x'event&nbsp;and&nbsp;clk1x&nbsp;=&nbsp;'1'&nbsp;then<br />if&nbsp;clk1x_enable&nbsp;=&nbsp;'1'&nbsp;then<br />no_bits_rcvd&nbsp;&lt=&nbsp;no_bits_rcvd&nbsp;+&nbsp;&quot;0001&quot;&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;if&nbsp;;<br />end&nbsp;process&nbsp;;<br />dout&nbsp;&lt=&nbsp;std_logic_vector(rbr)&nbsp;when&nbsp;rdn&nbsp;=&nbsp;'0'&nbsp;else&nbsp;&quot;ZZZZZZZZ&quot;&nbsp;;<br />end&nbsp;;<br /><br />2.2.3&nbsp;UART设计总模块<br />&nbsp;&nbsp;将发送器和接收器模块组装起来,就能较容易地实现通用异步收发器总模块,而且硬件实现不需要很多资源,尤其能较灵活地嵌入到FPGA/CPLD的开发中。<br />以下给出从模块源代码:<br /><br />library&nbsp;ieee;<br />use&nbsp;ieee.std_logic_1164.all&nbsp;;<br />use&nbsp;ieee.std_logic_arith.all&nbsp;;<br />use&nbsp;ieee.std_logic_unsigned.all&nbsp;;<br />entity&nbsp;uart&nbsp;is<br />PORT&nbsp;(rst,clk16x,rxd,rdn,wrn&nbsp;:&nbsp;in&nbsp;std_logic;<br />din&nbsp;:&nbsp;in&nbsp;std_logic_vector(7&nbsp;downto&nbsp;0);<br />dout&nbsp;:&nbsp;out&nbsp;std_logic_vector(7&nbsp;downto&nbsp;0);<br />data_ready&nbsp;:&nbsp;out&nbsp;std_logic;<br />parity_error&nbsp;:&nbsp;out&nbsp;std_logic;<br />framing_error&nbsp;:&nbsp;out&nbsp;std_logic;<br />tbre&nbsp;:&nbsp;out&nbsp;std_logic;<br />tsre&nbsp;:&nbsp;out&nbsp;std_logic;<br />sdo&nbsp;:&nbsp;out&nbsp;std_logic);<br />end&nbsp;uart;<br />architecture&nbsp;v1&nbsp;of&nbsp;uart&nbsp;is<br />component&nbsp;txmit<br />port&nbsp;(rst,clk16x,wrn&nbsp;:&nbsp;in&nbsp;std_logic;<br />din&nbsp;:&nbsp;in&nbsp;std_logic_vector(7&nbsp;downto&nbsp;0);<br />tbre,tsre,sdo:&nbsp;out&nbsp;std_logic);<br />end&nbsp;component&nbsp;;<br />component&nbsp;rcvr<br />port&nbsp;(rst,clk16x,rxd,rdn&nbsp;:&nbsp;in&nbsp;std_logic;<br />data_ready,&nbsp;parity_error,&nbsp;framing_error&nbsp;:&nbsp;out&nbsp;std_logic;<br />dout&nbsp;:&nbsp;out&nbsp;std_logic_vector(7&nbsp;downto&nbsp;0));<br />end&nbsp;component&nbsp;;<br />begin<br />u1&nbsp;:&nbsp;txmit&nbsp;PORT&nbsp;MAP&nbsp;(rst&nbsp;=&gt&nbsp;rst,clk16x&nbsp;=&gt&nbsp;clk16x,din&nbsp;=&gt&nbsp;din,tbre&nbsp;=&gt&nbsp;tbre,tsre&nbsp;=&gt&nbsp;tsre,<br />sdo&nbsp;=&gt&nbsp;sdo);<br />u2&nbsp;:&nbsp;rcvr&nbsp;PORT&nbsp;MAP&nbsp;(rst&nbsp;=&gt&nbsp;rst,clk16x&nbsp;=&gt&nbsp;clk16x,rxd&nbsp;=&gt&nbsp;rxd,rdn&nbsp;=&gt&nbsp;rdn,data_ready&nbsp;=&gt&nbsp;data_ready,framing_error&nbsp;=&gt&nbsp;framing_error,parity_error&nbsp;=&gt&nbsp;parity_error,dout&nbsp;=&gt&nbsp;dout)&nbsp;;<br />end&nbsp;v1&nbsp;;<br /><br />总模块RTL图如图5<br />&nbsp;<br />图5<br />2.3&nbsp;程序在MAX+PLUS&nbsp;II环境下的分析<br />在此设计中我所采用的编程目标芯片是ALTERA公司的EPF10K10LC84-3.<br />2.3.1波形仿真<br />波形仿真图如图6所示:<br />&nbsp;<br />图6<br />由于条件限制,数据给的太多,从图6上是看不出来的,所以,为了说明设计的正确性,只给出了一个数据。通过波形仿真图我们可以清楚的看到UART的工作原理。<br /><br />2.3.2&nbsp;时序分析<br />&nbsp;&nbsp;&nbsp;&nbsp;我对设计在没有优化的情况下做了分析,首要的目的是验证用FPGA/CPLD设计的正确性,次要的目的主要是与优化后的分析进行比较,以说明用FPGA/CPLD设计的优越性。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;优化前的时序分析图如下:<br />&nbsp;&nbsp;<br />图7、延时矩阵图<br />&nbsp;<br />图8、建立/保持时序分析图<br />&nbsp;<br />图9、延时路径及寄存器时钟特性图&nbsp;<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对本设计采用MAX+PLUS&nbsp;II优化设计中的专门针对其ALTERA器件的优化。在逻辑综合类型中选择快速类型(Fast)。这种类型是对大部分的器件特殊结构进行优化,是对性能要求较高的设计采用的综合类型。但是编译适配要比普通类型(Normal)慢许多。对于适配FLEX/ACEX等系列器件,综合器会自动使用FLEX/ACEX中的级链、进位链结构(对于Normal是忽略的)。<br />优化后的时序分析图如下:<br />&nbsp;<br />图10、优化后的延时矩阵图<br />&nbsp;<br />图11、优化后的建立/保持时序分析图<br />&nbsp;<br />图12、延时路径及寄存器时钟特性图<br />从时序分析我们可看到本设计基本满足设计要求。(上面的时序分析图中,某些图中只包含了部分数据)<br />对于优化前与优化后的数据比较来看,虽然在某些数据上优化后反而不如优化前的,这是正常的。因为优化不可能照顾到每一个信号。<br /><br />2.3.3&nbsp;资源利用<br />对于资源利用的情况,也分优化前和优化后进行比较。<br />优化前的资源分布图如下:<br />&nbsp;<br />图13、资源利用分布图<br />由于FPGA/PLD的阵列结构,如果在设计中,将某些关联模块在适配的时候集中分配在一块,其性能会大大提高。因此,对本设计进行打包(Clique)(又称分组)。<br />优化后的资源分布图如下<br />&nbsp;<br />图14、优化后资源利用分布图<br /><br />从上面的比较中,我们很清楚的看到,优化后的资源利用率有了很大的提高。<br /><br />3&nbsp;总结<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本设计由于采用了VHDL语言作为输入方式并结合FPGA/CPLD,大大缩短了设计周期,提高了设计的可靠性、灵活性,使用户可根据自己的需求,方便、高效地设计出适合的串行接口电路。<br />
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

9

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

6

主题

9

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部