第一篇:Verilog HDL 的入门学习
先记下来:
1、不使用初始化语句;
2、不使用延时语句;
3、不使用循环次数不确定的语句,如:forever,while等;
4、尽量采用同步方式设计电路;
5、尽量采用行为语句完成设计;
6、always过程块描述组合逻辑,应在敏感信号表中列出所有的输入信号;
7、所有的内部寄存器都应该可以被复位;
8、用户自定义原件(UDP元件)是不能被综合的。一:基本
Verilog中的变量有线网类型和寄存器类型。线网型变量综合成wire,而寄存器可能综合成WIRE,锁存器和触发器,还有可能被优化掉。二:verilog语句结构到门级的映射
1、连续性赋值:assign 连续性赋值语句逻辑结构上就是将等式右边的驱动左边的结点。因此连续性赋值的目标结点总是综合成由组合逻辑驱动的结点。Assign语句中的延时综合时都将忽视。
2、过程性赋值:
过程性赋值只出现在always语句中。
阻塞赋值和非阻塞赋值就该赋值本身是没有区别的,只是对后面的语句有不同的影响。
建议设计组合逻辑电路时用阻塞赋值,设计时序电路时用非阻塞赋值。过程性赋值的赋值对象有可能综合成wire, latch,和flip-flop,取决于具体状况。如,时钟控制下的非阻塞赋值综合成flip-flop。过程性赋值语句中的任何延时在综合时都将忽略。建议同一个变量单一地使用阻塞或者非阻塞赋值。
3、逻辑操作符:
逻辑操作符对应于硬件中已有的逻辑门,一些操作符不能被综合:===、!==。
4、算术操作符:
Verilog中将reg视为无符号数,而integer视为有符号数。因此,进行有符号操作时使用integer,使用无符号操作时使用reg。
5、进位:
通常会将进行运算操作的结果比原操作数扩展一位,用来存放进位或者借位。如: Wire [3:0] A,B;Wire [4:0] C;Assign C=A+B;C的最高位用来存放进位。
6、关系运算符: 关系运算符:<,>,<=,>= 和算术操作符一样,可以进行有符号和无符号运算,取决于数据类型是reg,net还是integer。
7、相等运算符:==,!= 注意:===和!==是不可综合的。
可以进行有符号或无符号操作,取决于数据类型
8、移位运算符:
左移,右移,右边操作数可以是常数或者是变量,二者综合出来的结果不同。
9、部分选择:
部分选择索引必须是常量。
10、BIT选择:
BIT选择中的索引可以用变量,这样将综合成多路(复用)器。
11、敏感表:Always过程中,所有被读取的数据,即等号右边的变量都要应放在敏感表中,不然,综合时不能正确地映射到所用的门。
12、IF:
如果变量没有在IF语句的每个分支中进行赋值,将会产生latch。如果IF语句中产生了latch,则IF的条件中最好不要用到算术操作。Case语句类似。Case的条款可以是变量。
如果一个变量在同一个IF条件分支中先赎值然后读取,则不会产生latch。如果先读取,后赎值,则会产生latch。
13、循环:
只有for-loop语句是可以综合的。
14、设计时序电路时,建议变量在always语句中赋值,而在该always语句外使用,使综合时能准确地匹配。建议不要使用局部变量。
15、不能在多个always块中对同一个变量赎值
16、函数
函数代表一个组合逻辑,所有内部定义的变量都是临时的,这些变量综合后为wire。
17、任务:
任务可能是组合逻辑或者时序逻辑,取决于何种情况下调用任务。
18、Z:
Z会综合成一个三态门,必须在条件语句中赋值
19、参数化设计:
优点:参数可重载,不需要多次定义模块 四:模块优化
1、资源共享:
当进程涉及到共用ALU时,要考虑资源分配问题。可以共享的操作符主要有:关系操作符、加减乘除操作符。通常乘和加不共用ALU,乘除通常在其内部共用。
2、共用表达式: 如:C=A+B;
D=G+(A+B);两者虽然有共用的A+B,但是有些综合工具不能识别.可以将第二句改为:D=G+C;这样只需两个加法器.
3、转移代码:
如循环语句中没有发生变化的语句移出循环.
4、避免latch:
两种方法:
1、在每一个IF分支中对变量赋值。
2、在每一个IF语句中都对变量赋初值。5:模块:
综合生成的存储器如ROM或RAM不是一种好方法,只是成堆的寄存器,很费资源。最好用库自带的存储器模块。
五、验证: 1、敏感表:
在always语句中,如果敏感表不含时钟,最好将所有的被读取的信号都放在敏感表中。2、异步复位:
建议不要在异步时对变量读取,即异步复位时,对信号赋以常数值。
Averilog的流行,有两方面的原因;B verilog与VHDL相比的优点 C典型的verilog模块 D verilog语法要点
A)verilog的流行,有两方面的原因: 1它是cadence的模拟器verilog-XL的基础,cadence的广泛流行使得verilog在90年代深入人心;2它在硅谷获得广泛使用;B)verilog与VHDL相比的优点二者的关系仿佛C与FORTRAN,具体而言: 1 verilog的代码效率更高: 比较明显的对比: VHDL在描述一个实体时采用entity/architecture模式, verilog在描述一个实体时只需用一个“module/edumodule”语句块.此外verilog的高效性还在很多地方体现出来;2 verilog支持二进制的加减运算: VHDL在进行二进制的加减运算时使用conv_***函数或者进行其他的定义,总之必须通知编译器;verilog直接用形如“c=a+b”的表示二进制的加减运算;3综合时可控制性好: VHDL对信号不加区分地定义为“signal”, 而verilog区分为register类型的和wire类型的;但是也有人支持VHDL,认为verilog和VHDL的关系仿佛C和C++.C)典型的verilog模块 讨论以下典型电路的verilog描述: *与非门;*加法器;//即全加器 * D触发器;*计数器;//**分频的counter * latch;*时序机;*RAM;//用synopsys的 *模块引用;*预编译;*与非门的verilog描述如下: //verilog使用和C语言相同的注释方法
module nd02(a1,a2,zn);//一个verilog模块总是以module开始,以endmodule 结束,nd02是模块名,a1,a2,zn是模块的3个输入输出信号
input a1,a2;//告诉编译器a1,a2对此模块而言是输入,并且数据类型是“bit” output zn;//告诉编译器zn对此模块而言是输出,数据类型也是“bit” nand(zn,a1,a2);//我理解nand是运算符,我们不必深究verilog中的正式术语是什 么了吧,总之这种形式表示zn=~(a1 && a2);你一定已经想到类似的运算符还有“not”,“and”,“or”,“nor”,“xor”了吧;除了“not”,括号里的信号数可以任意,例如or(z,f,g,h)表示z=f || g || h,并且延时是3个单位时间,#x表示延时x个单位时间;endmodule
*加法器的verilog描述如下: module ad03d1(A,B,CI,S,CO);input [2:0] A,B;//表示A,B是输入信号,并且是3位矢量,上界是2,下界是0 input CI;output [2:0] S;output CO;assign {CO,S}=A+B+CI;//一对“{”和“}”表示链接,即将CO和S合并成4位矢量 endmodule
*带异步清零端的D触发器的verilog描述如下: module dfctnb(d,cp,cdn,q,qn);input d,cp,cdn;output q,qn;reg q,qn;//关键字“reg”表示q和qn是“register”类型的信号;verilog中有两种类型的信号:“register”类型和“wire”类型.你可以简单地把register类型的信号想象为某个D触发器的输出,而wire类型的的信号是组合逻辑的输出.二者的最大区别在于:你可以对register类型的信号进行定时赋值(用wait语句在特定时刻的赋值,详见下面always语句),而对于wire类型的信号则不可.always wait(cdn==0)//表示每当cdn=0时,将要对D触发器清零,“always”和“wait”嵌套,“wait”和“@”是verilog的两个关键字,表示一旦有某事发生;则执行下面的语句块,“always”有点象C语言中的“if...then...”,“wait”和“@”的区别:请参考本模块.wait表示本语句块的进程停止,直到“cdn=0”的条件出现才继续;我理解在verilog中,每个最外层语句块都是一个***的进程;“@”(请看下个always语句)也表示本语句块的进程停止,直到后面定义“posedge cp”(即出现cp的上升沿)的事件出现才继续;也许wait和@可以合二为一吧,但至少到目前verilog中wait表示“条件”,@表示“事件”;具体运用中,wait总是用于类似“wait(xxx=1)”之类的场合,@总是用于类似“@(xxx)”或“@(posedge/negedge xxx)”之类的场合整句话的意思是“每当cdn等于0时,则作以下事情” begin //begin...end结构的用法类似于pascal语言
q=0;
qn=1;
wait(cdn==1);end always @(posedge cp)//“@(posedge cp)”中有两个关键字:“@(x)”表示“每当事件x发
生”,“posedge x”表示“x的上升沿,”negedge x“表示”x的下降沿“,整句话的意思是”每当cp的上升沿,则作以下事情“
if(cdn)//如果cdn=1(意味着清零端无效)
begin
q=d;
qn=~q;//”~“表示反相
end endmodule *计数器的verilog描述如下: module count(in,set,cp,out);//此计数器,在cp的上升沿将输入赋给输出,在cp的上升沿使输出加一 input [15:0] in;input set,cp;output [15:0] out;reg [15:0] out;always @(posedge set)out = in;always @(posedge cp)out = out+1;//verilog容许一个信号同时出现在等号两端,只要它是reg类型的 endmodule
*latch的描述如下: always @(clk or d)
if(clk)q = d;
*时序机的verilog描述如下: always @(posedge CLK)//D是下一个状态,Q是当前状态,e1,e2是输入,a,b是输出 Q=D;always @(Q or othercase)begin //当Q变化或输入e1,e2变化时D要相应变化 D = Q;//note1 a = 0;b = 0;......case(Q)q1:begin q1 action;if(e1)D=d1;if(e2)D=d2;else D=d3;a = 1;//note 2 end q2:begin b = 1;......end default:begin a = 0;b = 0;......end end---annotations---note 1: This is a custom expression,after reset,D should be equal to Q;note 2: In this state machine,a is only equal to 1 at state q1,in other state,a is equal to 0;* RAM的verilog描述如下: module ram(din,ain,dout,aout,rd,wr);//这是一个双口RAM,分别有:输入端:输入地址ain;输入数据din;上升沿有效的写信号wr;/输出端:输出地址aout;输出数据dout;高电平有效的读信号rd;inout [7:0] din;input [7:0] ain,aout;input rd,wr;output [7:0] dout;reg [7:0] memory [0:255];//请注意这是存储阵列的描述方法,描述了一个共有2 56个字的存储阵列,每个字是8位
assign dout = rd ? memory[aout] : 8'bz;//”assign“关键字表示并行赋值语句的 开始”?“运算符的作用和在C语言中一样”8'bz“是一个常量,表示一个字节的高阻态,其中8表示长度是8bit,”'“是固定分割符,”b“表示后面的数据是以比特形式给出的,”z“表示高阻;举例:4'ha表示长4bit的数”1010“。类似的还可举出5'b10111,6'o33等等
always @(posedge wr)memory[ain] = din;endmodule *模块引用
假设在前面(可以是别的模块)定义了module ram(din,ain,dout,aout,rd,wr),则引用此
模块时只需写 ram myram(din_in_map,ain_in_map,dout_in_map,aout_in_map,rd_in_map,wr_in_map);//其中”ram“是所引用的module名,”myram“是你起的instance名,”din_in_map“等等是图中的节点名,和器件(module)中的”din...“进行”虚实结合“;*预编译
类似C语言,只需写
`include ”
“,反上撇号”`“是verilog的预编译符,类似C中的”#“.D)verilog语法要点 *基本原则
设计时应该把你的系统划分为计数器,触发器,时序机,组合逻辑等等可综合的单元,对此不同的IC公司和EDA开发商可能根据自己的见解和经验提出不同的要求,并且对verilog程序的细节进行自己的规定,但有一点是对的:即写硬件描述语言不象写C语言那样符合语法就行.单单符合verilog语法的程序可能被拒绝综合,甚至被拒绝模拟;*最外层可以写什么? 这里所说的最外层是指module语句后的第一层,在这一层可以写这些可执行语句: assign和nand等定义组合逻辑的语句, always语句, 模块引用语句, 一些以”$“开头的系统定义语句.特别注意不可以写if语句.if语句只能放在always内部.不推荐写wait语句,因为不能综合.*不可以在多个always语句中对一个信号赋值.1.强烈建议用同步设计 2.在设计时总是记住时序问题
3.在一个设计开始就要考虑到地电平或高电平复位、同步或异步复位、上升沿或下降沿触发等问题,在所有模块中都要遵守它
4.在不同的情况下用if和case,最好少用if的多层嵌套(1层或2层比较合适,当在3层以上时,最好修改写法,因为这样不仅可以reduce area,而且可以获得好的timing)
5.在锁存一个信号或总线时要小心,对于整个design,尽量避免使用latch,因为在DFT时很难test。
6.确信所有的信号被复位,在DFT时,所有的FlipFlop都是controllable,7.永远不要再写入之前读取任何内部存储器(如SRAM)
8.从一个时钟到另一个不同的时钟传输数据时用数据缓冲,他工作像一个双时钟FIFO(是异步的),可以用Async SRAM搭建Async FIFO。
9.在VHDL中二维数组可以使用,它是非常有用的。在VERILOG中他仅仅可以使用在测试模块中,不能被综合 10.遵守register-in register-out规则
11.像synopsys的DC的综合工具是非常稳定的,任何bugs都不会从综合工具中产生 12.确保FPGA版本与ASIC的版本尽可能的相似,特别是SRAM类型,若版本一致是最理想的,但是在工作中FPGA版本一般用FPGA自带的SRAM,ASIC版本一般用厂商提供的SRAM。13.在嵌入式存储器中使用BIST 14.虚单元和一些修正电路是必需的
15.一些简单的测试电路也是需要的,经常在一个芯片中有许多测试模块 16.除非低功耗不要用门控时钟,强烈建议不要在design中使用gate clock 17.不要依靠脚本来保证设计。但是在脚本中的一些好的约束能够起到更好的性能(例如前向加法器)
18.如果时间充裕,通过时钟做一个多锁存器来取代用MUX 19.不要用内部tri-state, ASIC需要总线保持器来处理内部tri-state,如IO cell。20.在top level中作pad insertion 21.选择pad时要小心(如上拉能力,施密特触发器,5伏耐压等),选择合适的IO cell 22.小心由时钟偏差引起的问题 23.不要试着产生半周期信号
24.如果有很多函数要修正,请一个一个地作,修正一个函数检查一个函数 25.在一个计算等式中排列每个信号的位数是一个好习惯,即使综合工具能做 26.不要使用HDL提供的除法器
27.削减不必要的时钟。它会在设计和布局中引起很多麻烦,大多数FPGA有1-4个专门的时钟通道
良好代码编写风格可以满足信、达、雅的要求。在满足功能和性能目标的前提下,增强代码的可读性、可移植性,首要的工作是在项目开发之前为整个设计团队建立一个命名约定和缩略语清单,以文档的形式记录下来,并要求每位设计人员在代码编写过程中都要严格遵守。良好代码编写风格的通则概括如下:(1)对所有的信号名、变量名和端口名都用小写,这样做是为了和业界的习惯保持一致;对常量名和用户定义的类型用大写;(2)使用有意义的信号名、端口名、函数名和参数名;(3)信号名长度不要太长;(4)对于时钟信号使用clk 作为信号名,如果设计中存在多个时钟,使用clk 作为时钟信号的前缀;
(5)对来自同一驱动源的信号在不同的子模块中采用相同的名字,这要求在芯片总体设计时就定义好顶层子模块间连线的名字,端口和连接端口的信号尽可能采用相同的名字;
(6)对于低电平有效的信号,应该以一个下划线跟一个小写字母b 或n 表示。注意在同一个设计中要使用同一个小写字母表示低电平有效;
(7)对于复位信号使用rst 作为信号名,如果复位信号是低电平有效,建议使用rst_n;
(8)当描述多比特总线时,使用一致的定义顺序,对于verilog 建议采用bus_signal[x:0]的表示;
(9)尽量遵循业界已经习惯的一些约定。如*_r 表示寄存器输出,*_a 表示异步信号,*_pn 表示多周期路径第n 个周期使用的信号,*_nxt 表示锁存前的信号,*_z 表示三态信号等;
(10)在源文件、批处理文件的开始应该包含一个文件头、文件头一般包含的内容如下例所示:文件名,作者,模块的实现功能概述和关键特性描述,文件创建和修改的记录,包括修改时间,修改的内容等;
(11)使用适当的注释来解释所有的always 进程、函数、端口定义、信号含义、变量含义或信号组、变量组的意义等。注释应该放在它所注释的代码附近,要求简明扼要,只要足够说明设计意图即可,避免过于复杂;
(12)每一行语句独立成行。尽管VHDL 和Verilog 都允许一行可以写多个语句,当时每个语句独立成行可以增加可读性和可维护性。同时保持每行小于或等于72 个字符,这样做都是为了提高代码得可读性;
(13)建议采用缩进提高续行和嵌套语句得可读性。缩进一般采用两个空格,如西安交通大学SOC 设计中心2 如果空格太多则在深层嵌套时限制行长。同时缩进避免使用TAB 键,这样可以避免不同机器TAB 键得设置不同限制代码得可移植能力;
(14)在RTL 源码的设计中任何元素包括端口、信号、变量、函数、任务、模块等的命名都不能取Verilog 和VHDL 语言的关键字;
(15)在进行模块的端口申明时,每行只申明一个端口,并建议采用以下顺序: 输入信号的clk、rst、enables other control signals、data and address signals。然后再申明输出信号的clk、rst、enalbes other control signals、data signals;(16)在例化模块时,使用名字相关的显式映射而不要采用位置相关的映射,这样可以提高代码的可读性和方便debug 连线错误;
(17)如果同一段代码需要重复多次,尽可能使用函数,如果有可能,可以将函数通用化,以使得它可以复用。注意,内部函数的定义一般要添加注释,这样可以提高代码的可读性;
(18)尽可能使用循环语句和寄存器组来提高源代码的可读性,这样可以有效地减少代码行数;
(19)对一些重要的always 语句块定义一个有意义的标号,这样有助于调试。注意标号名不要与信号名、变量名重复;
(20)代码编写时的数据类型只使用IEEE 定义的标准类型,在VHDL 语言中,设计者可以定义新的类型和子类型,但是所有这些都必须基于IEEE 的标准;(21)在设计中不要直接使用数字,作为例外,可以使用0 和1。建议采用参数定义代替直接的数字。同时,在定义常量时,如果一个常量依赖于另一个常量,建议在定义该常量时用表达式表示出这种关系;
(22)不要在源代码中使用嵌入式的dc_shell 综合命令。这是因为其他的综合工具并不认得这些隐含命令,从而导致错误的或较差的综合结果。即使使用Design Compiler,当综合策略改变时,嵌入式的综合命令也不如放到批处理综合文件中易于维护。这个规则有一个例外的综合命令,即编译开关的打开和关闭可以嵌入到代码中;
(23)在设计中避免实例化具体的门级电路。门级电路可读性差,且难于理解和维护,如果使用特定工艺的门电路,设计将变得不可移植。如果必须实例化门电路,我们建议采用独立于工艺库的门电路,如SYNOPSYS 公司提供的GTECH 库包含了高质量的常用的门级电路;(24)避免冗长的逻辑和子表达式;
(25)避免采用内部三态电路,建议用多路选择电路代替内部三态电路。
规则 #1: 建立时序逻辑模型时,采用非阻塞赋值语句。规则 #2: 建立latch模型时,采用非阻塞赋值语句。规则 #3: 在always块中建立组合逻辑模型时,采用阻塞赋值语句。
规则 #4: 在一个always块中同时有组合和时序逻辑时时,采用非阻塞赋值语句。规则 #5: 不要在一个always块中同时采用阻塞和非阻塞赋值语句。规则 #6: 同一个变量不要在多个always块中赋值。
规则 #7: 调用$strobe系统函数显示用非阻塞赋值语句赋的值。规则 #8: 不要使用#0延时赋值。组合逻辑
1,敏感变量的描述完备性
Verilog中,用always块设计组合逻辑电路时,在赋值表达式右端参与赋值的所有信号都必须在always @(敏感电平列表)中列出,always中if语句的判断表达式必须在敏感电平列表中列出。如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,在综合时将会为没有列出的信号隐含地产生一个透明锁存器。这是因为该信号的变化不会立刻引起所赋值的变化,而必须等到敏感电平列表中的某一个信号变化时,它的作用才表现出来,即相当于存在一个透明锁存器,把该信号的变化暂存起来,待敏感电平列表中的某一个
信号变化时再起作用,纯组合逻辑电路不可能作到这一点。综合器会发出警告。Example1: input a,b,c;reg e,d;always @(a or b or c)
begin
e=d&a&b;/*d没有在敏感电平列表中,d变化时e不会立刻变化,直到a,b,c中某一个变化*/
d=e |c;
end Example2: input a,b,c;reg e,d;always @(a or b or c or d)
begin
e=d&a&b;/*d在敏感电平列表中,d变化时e立刻变化*/
d=e |c;
end 2,条件的描述完备性
如果if语句和case语句的条件描述不完备,也会造成不必要的锁存器。Example1: if(a==1'b1)q=1'b1;//如果a==1'b0,q=? q将保持原值不变,生成锁存器!Example2: if(a==1'b1)q=1'b1;else
q=1'b0;//q有明确的值。不会生成锁存器!Example3: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;//如果a==2'b10或a==2'b11,q=? q将保持原值不变,锁存器!
endcase Example4: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;
default: q=2'b00;//q有明确的值。不会生成锁存器!
endcase Verilog中端口的描述
1,端口的位宽最好定义在I/O说明中,不要放在数据类型定义中; Example1: module test(addr,read,write,datain,dataout)input[7:0] datain;input[15:0] addr;input
read,write;output[7:0] dataout;//要这样定义端口的位宽!wire addr,read,write,datain;reg dataout;Example2: module test(addr,read,write,datain,dataout)input datain,addr,read,write;output dataout;wire[15:0] addr;wire[7:0] datain;wire
read,write;reg[7:0] dataout;//不要这样定义端口的位宽!2,端口的I/O与数据类型的关系:
端口的I/O 端口的数据类型
module内部 module外部
input
wire
wire或reg
output
wire或reg
wire
inout
wire
wire 3,assign语句的左端变量必须是wire;直接用”=“给变量赋值时左端变量必须是reg!Example: assign a=b;//a必须被定义为wire!******** begin a=b;//a必须被定义为reg!end VHDL中STD_LOGIC_VECTOR和INTEGER的区别
例如A是INTEGER型,范围从0到255;B是STD_LOGIC_VECTOR,定义为8位。A累加到255时,再加1就一直保持255不变,不会自动反转到0,除非令其为0;而B累加到255时,再加1就会自动反转到0。所以在使用时要特别注意!
以触发器为例说明描述的规范性 1,无置位/清零的时序逻辑
always @(posedge CLK)
begin
Q<=D;
end 2,有异步置位/清零的时序逻辑
异步置位/清零是与时钟无关的,当异步置位/清零信号到来时,触发器的输出立即 被置为1或0,不需要等到时钟沿到来才置位/清零。所以,必须要把置位/清零信号 列入always块的事件控制表达式。
always @(posedge CLK or negedge RESET)
begin
if(!RESET)
Q=0;
else
Q<=D;
end 3,有同步置位/清零的时序逻辑
同步置位/清零是指只有在时钟的有效跳变时刻置位/清零,才能使触发器的输出分
别转换为1或0。所以,不要把置位/清零信号列入always块的事件控制表达式。但是
必须在always块中首先检查置位/清零信号的电平。
always @(posedge CLK)
begin
if(!RESET)
Q=0;
else
Q<=D;
end 结构规范性
在整个芯片设计项目中,行为设计和结构设计的编码是最重要的一个步骤。它对逻辑综合和布线结果、时序测定、校验能力、测试能力甚至产品支持都有重要的影响。考虑到仿真器和真实的逻辑电路之间的差异,为了有效的 进行仿真测试:
1,避免使用内部生成的时钟
内部生成的时钟称为门生时钟(gated clock)。如果外部输入时钟和门生时钟同时驱动,则不可避免的两者的步调不一致,造成逻辑混乱。而且,门生时钟将会增加测试的难度
和时间。
2,绝对避免使用内部生成的异步置位/清零信号
内部生成的置位/清零信号会引起测试问题。使某些输出信号被置位或清零,无法正常
测试。3,避免使用锁存器
锁存器可能引起测试问题。对于测试向量自动生成(ATPG),为了使扫描进行,锁存器需要置为透明模式(transparent mode),反过来,测试锁存器需要构造特定的向量,这可非同一般。4,时序过程要有明确的复位值
使触发器带有复位端,在制造测试、ATPG以及模拟初始化时,可以对整个电路进行
快速复位。5,避免模块内的三态/双向
内部三态信号在制造测试和逻辑综合过程中难于处理.近日读 J.Bhasker 的
例外情况:变量的赋值和引用都仅出现在一条always语句中,则该变量被视为中
间变量而不是触发器。
4.对于无时钟事情的always语句(即组合逻辑建模),其时间表应包括该alwa语
句引用的所有变量,否则会出现RTL与Netlist的不一致
芯片外部引脚很多都使用inout类型的,为的是节省管腿。一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。就是一个端口同时做输入和输出。inout在具体实现上一般用三态门来实现。三态门的第三个状态就是高阻'Z'。当inout端口不输出时,将三态门置高阻。这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.1 使用inout类型数据,可以用如下写法: inout data_inout;input data_in;reg data_reg;//data_inout的映象寄存器 reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门
//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况: Wire data_out;Assign data_out_t=(!link)?data_inout:1’bz;else,in RTL inout use in top module(PAD)dont use inout(tri)in sub module 也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。理由是:在非顶层模块用双向口的话,该双向口必然有它的上层跟它相连。既然是双向口,则上层至少有一个输入口和一个输出口联到该双向口上,则发生两个内部输出单元连接到一起的情况出现,这样在综合时往往会出错。
对双向口,我们可以将其理解为2个分量:一个输入分量,一个输出分量。另外还需要一个控制信号控制输出分量何时输出。此时,我们就可以很容易地对双向端口建模。例子: CODE: module dual_port(....inout_pin,....);inout inout_pin;wire inout_pin;wire input_of_inout;wire output_of_inout;wire out_en;assign input_of_inout = inout_pin;assign inout_pin = out_en ? output_of_inout : 高阻;endmodule 可见,此时input_of_inout和output_of_inout就可以当作普通信号使用了。在仿真的时候,需要注意双向口的处理。如果是直接与另外一个模块的双向口连接,那么只要保证一个模块在输出的时候,另外一个模块没有输出(处于高阻态)就可以了。如果是在ModelSim中作为单独的模块仿真,那么在模块输出的时候,不能使用force命令将其设为高阻态,而是使用release命令将总线释放掉
很多初学者在写testbench进行仿真和验证的时候,被inout双向口难住了。仿真器老是提示错误不能进行。下面是我个人对inout端口写testbench仿真的一些总结,并举例进行说明。在这里先要说明一下inout口在testbench中要定义为wire型变量。
先假设有一源代码为: module xx(data_inout ,........);inout data_inout;........................assign data_inout=(!link)?datareg:1'bz;endmodule 方法一:使用相反控制信号inout口,等于两个模块之间用inout双向口互连。这种方法要注意assign 语句只能放在initial和always块内。module test();wire data_inout;reg data_reg;reg link;initial begin..........end assign data_inout=link?data_reg:1'bz;endmodule 方法二:使用force和release语句,但这种方法不能准确反映双向端口的信号变化,但这种方法可以反在块内。module test();wire data_inout;reg data_reg;reg link;#xx;//延时
force data_inout=1'bx;
//强制作为输入端口...............#xx;release data_inout;//释放输入端口 endmodule 很多读者反映仿真双向端口的时候遇到困难,这里介绍一下双向端口的仿真方法。一个典型的双向端口如图1所示。
其中inner_port与芯片内部其他逻辑相连,outer_port为芯片外部管脚,out_en用于控制双向端口的方向,out_en为1时,端口为输出方向,out_en为0时,端口为输入方向。
用Verilog语言描述如下:
module bidirection_io(inner_port,out_en,outer_port);input out_en;inout[7:0] inner_port;inout[7:0] outer_port;assign outer_port=(out_en==1)?inner_port:8'hzz;assign inner_port=(out_en==0)?outer_port:8'hzz;endmodule
用VHDL语言描述双向端口如下: library ieee;use IEEE.STD_LOGIC_1164.ALL;entity bidirection_io is port(inner_port : inout std_logic_vector(7 downto 0);out_en : in std_logic;outer_port : inout std_logic_vector(7 downto 0));end bidirection_io;architecture behavioral of bidirection_io is begin outer_port<=inner_port when out_en='1' else(OTHERS=>'Z');inner_port<=outer_port when out_en='0' else(OTHERS=>'Z');end behavioral;
仿真时需要验证双向端口能正确输出数据,以及正确读入数据,因此需要驱动out_en端口,当out_en端口为1时,testbench驱动inner_port端口,然后检查outer_port端口输出的数据是否正确;当out_en端口为0时,testbench驱动outer_port端口,然后检查inner_port端口读入的数据是否正确。由于inner_port和outer_port端口都是双向端口(在VHDL和Verilog语言中都用inout定义),因此驱动方法与单向端口有所不同。
验证该双向端口的testbench结构如图2所示。
这是一个self-checking testbench,可以自动检查仿真结果是否正确,并在Modelsim控制台上打印出提示信息。图中Monitor完成信号采样、结果自动比较的功能。
testbench的工作过程为
1)out_en=1时,双向端口处于输出状态,testbench给inner_port_tb_reg信号赋值,然后读取outer_port_tb_wire的值,如果两者一致,双向端口工作正常。2)out_en=0时,双向端口处于输如状态,testbench给outer_port_tb_reg信号赋值,然后读取inner_port_tb_wire的值,如果两者一致,双向端口工作正常。用Verilog代码编写的testbench如下,其中使用了自动结果比较,随机化激励产生等技术。
`timescale 1ns/10ps module tb();reg[7:0] inner_port_tb_reg;wire[7:0] inner_port_tb_wire;reg[7:0] outer_port_tb_reg;wire[7:0] outer_port_tb_wire;reg out_en_tb;integer i;initial begin out_en_tb=0;inner_port_tb_reg=0;outer_port_tb_reg=0;i=0;repeat(20)begin #50 i=$random;out_en_tb=i[0];//randomize out_en_tb inner_port_tb_reg=$random;//randomize data outer_port_tb_reg=$random;end end
//**** drive the ports connecting to bidirction_io assign inner_port_tb_wire=(out_en_tb==1)?inner_port_tb_reg:8'hzz;assign outer_port_tb_wire=(out_en_tb==0)?outer_port_tb_reg:8'hzz;
//instatiate the bidirction_io module bidirection_io bidirection_io_inst(.inner_port(inner_port_tb_wire),.out_en(out_en_tb),.outer_port(outer_port_tb_wire));
//***** monitor ****** always@(out_en_tb,inner_port_tb_wire,outer_port_tb_wire)begin #1;if(outer_port_tb_wire===inner_port_tb_wire)begin $display(”n **** time=%t ****“,$time);$display(”OK!out_en=%d“,out_en_tb);$display(”OK!outer_port_tb_wire=%d,inner_port_tb_wire=%d“, outer_port_tb_wire,inner_port_tb_wire);end else begin $display(”n **** time=%t ****“,$time);$display(”ERROR!out_en=%d“,out_en_tb);$display(”ERROR!outer_port_tb_wire!= inner_port_tb_wire“);$display(”ERROR!outer_port_tb_wire=%d, inner_port_tb_wire=%d“, outer_port_tb_wire,inner_port_tb_wire);end end endmodule 今天重新回顾了一下阻塞赋值和非阻塞赋值的概念,感觉又有所收获。
一、特点:
阻塞赋值:
1、RHS的表达式计算和LHS的赋值更新,这两个动作之间不能插入其他动作,即所谓计算完毕,立即更新。
2、所谓阻塞就是指在一个“begin...end”块中的多个阻塞赋值语句内,只有上一句完全执行完毕后,才会执行下一语句,否则阻塞程序的执行。
非阻塞赋值:RHS的表达式计算和LHS的赋值更新分两个节拍执行,首先,应该是RHS的表达式计算,得到新值后并不立即赋值,而是放在事件队列中等待,直到当前仿真时刻的后期才执行(原因下文会提到)。
二、Verilog的分层事件队列:
在Verilog中,事件队列可以划分为5个不同的区域,不同的事件根据规定放在不同的区域内,按照优先级的高低决定执行的先后顺序,下表就列出了部分Verilog分层事件队列。其中,活跃事件的优先级最高(最先执行),而监控事件的优先级最低,而且在活跃事件中的各事件的执行顺序是随机的(注:为方便起见,在一般的仿真器中,对同一区域的不同事件是按照调度的先后关系执行的)。当前仿真 时间事件
活跃事件
阻塞赋值,非阻塞赋值的RHS计算…… 非活跃事件
显式0延时的阻塞赋值…… 非阻塞赋值更新事件
由非阻塞语句产生的一个非阻塞赋值更新事件,并被调入当前仿真时刻。监控事件
$monitor和$strobe等系统任务 将来仿真
时间事件
被调度到将来仿真时间的事件
三、结论:
由上表就可以知道,阻塞赋值属于活跃事件,会立刻执行,这就是阻塞赋值“计算完毕,立刻更新”的原因。此外,由于在分层事件队列中,只有将活跃事件中排在前面的事件调出,并执行完毕后,才能够执行下面的事件,这就可以解释阻塞赋值的第二个特点。
同样是由上表知,非阻塞赋值的RHS计算属于活跃事件,而非阻塞赋值更新事件排在非活跃事件之后,因此只有仿真队列中所有的活跃事件和非活跃事件都执行完毕后,才轮到非阻塞赋值更新事件,这就是非阻塞赋值必须分两拍完成的原因。
以上就是我今天的读书笔记,写得仓促,如有不对,敬请指出。一.强调Verilog代码编写风格的必要性。
强调Verilog代码编写规范,经常是一个不太受欢迎的话题,但却是非常有必要的。
每个代码编写者都有自己的编写习惯,而且都喜欢按照自己的习惯去编写代码。与自己编写风格相近的代码,阅读起来容易接受和理解。相反和自己编写风格差别较大的代码,阅读和接受起来就困难一些。
曾有编程大师总结说,一个优秀的程序员,能维护的代码长度大约在1万行数量级。代码的整洁程度,很大程度上影响着代码的维护难度。
遵循代码编写规范书写的代码,很容易阅读、理解、维护、修改、跟踪调试、整理文档。相反代码编写风格随意的代码,通常晦涩、凌乱,会给开发者本人的调试、修改工作带来困难,也会给合作者带来很大麻烦。
(实际上英文Coding Style有另一层涵义,更偏重的是,某一个电路,用那一种形式的语言描述,才能将电路描述得更准确,综合以后产生的电路更合理。本文更偏重的是,编写Verilog代码时的书写习惯。)
二.强调编写规范的宗旨。缩小篇幅 提高整洁度
便于跟踪、分析、调试 增强可读性,帮助阅读者理解 便于整理文档 便于交流合作
三.变量及信号命名规范。1.系统级信号的命名。
系统级信号指复位信号,置位信号,时钟信号等需要输送到各个模块的全局信号;系统信号以字符串Sys开头。
2.低电平有效的信号后一律加下划线和字母n。如:SysRst_n;FifoFull_n; 3.经过锁存器锁存后的信号,后加下划线和字母r,与锁存前的信号区别。如CpuRamRd信号,经锁存后应命名为CpuRamRd_r。
低电平有效的信号经过锁存器锁存后,其命名应在_n后加r。如CpuRamRd_n信号,经锁存后应命名为CpuRamRd_nr 多级锁存的信号,可多加r以标明。如CpuRamRd信号,经两级触发器锁存后,应命名为CpuRamRd_rr。4.模块的命名。
在系统设计阶段应该为每个模块进行命名。命名的方法是,将模块英文名称的各个单词首字母组合起来,形成3到5个字符的缩写。若模块的英文名只有一个单词,可取该单词的前3个字母。各模块的命名以3个字母为宜。例如: Arithmatic Logical Unit模块,命名为ALU。Data Memory Interface模块,命名为DMI。Decoder模块,命名为DEC。5.模块之间的接口信号的命名。
所有变量命名分为两个部分,第一部分表明数据方向,其中数据发出方在前,数据接收方在后,第二部分为数据名称。两部分之间用下划线隔离开。
第一部分全部大写,第二部分所有具有明确意义的英文名全部拼写或缩写的第一个字母大写,其余部分小写。
举例:CPUMMU_WrReq,下划线左边是第一部分,代表数据方向是从CPU模块发向存储器管理单元模块(MMU)。下划线右边Wr为Write的缩写,Req是Request的缩写。两个缩写的第一个字母都大写,便于理解。整个变量连起来的意思就是CPU发送给MMU的写请求信号。模块上下层次间信号的命名也遵循本规定。
若某个信号从一个模块传递到多个模块,其命名应视信号的主要路径而定。6.模块内部信号:
模块内部的信号由几个单词连接而成,缩写要求能基本表明本单词的含义; 单词除常用的缩写方法外(如:Clock->Clk, Write->Wr, Read->Rd等),一律取该单词的前几个字母(如:Frequency->Freq, Variable->Var 等); 每个缩写单词的第一个字母大写;
若遇两个大写字母相邻,中间添加一个下划线(如DivN_Cntr); 举例:SdramWrEn_n;FlashAddrLatchEn;四.编码格式规范。
1.分节书写,各节之间加1到多行空格。如每个always,initial语句都是一节。每节基本上完成一个特定的功能,即用于描述某几个信号的产生。在每节之前有几行注释对该节代码加以描述,至少列出本节中描述的信号的含义。
2.行首不要使用空格来对齐,而是用Tab键,Tab键的宽度设为4个字符宽度。行尾不要有多余的空格。3.注释。
使用//进行的注释行以分号结束;
使用/* */进行的注释,/*和*/各占用一行,并且顶头; 例:
// Edge detector used to synchronize the input signal; 4.空格的使用:
不同变量,以及变量与符号、变量与括号之间都应当保留一个空格。Verilog关键字与其它任何字符串之间都应当保留一个空格。如: Always @(……)
使用大括号和小括号时,前括号的后边和后括号的前边应当留有一个空格。逻辑运算符、算术运算符、比较运算符等运算符的两侧各留一个空格,与变量分隔开来;单操作数运算符例外,直接位于操作数前,不使用空格。
使用//进行的注释,在//后应当有一个空格;注释行的末尾不要有多余的空格。例:
assign SramAddrBus = { AddrBus[31:24], AddrBus[7:0] };assign DivCntr[3:0] = DivCntr[3:0] + 4’b0001;assign Result = ~Operand;5.同一个层次的所有语句左端对齐;Initial、always等语句块的begin关键词跟在本行的末尾,相应的end关键词与Initial、always对齐;这样做的好处是避免因begin独占一行而造成行数太多; 例:
always @(posedge SysClk or negedge SysRst)begin if(!SysRst)DataOut <= 4'b0000;else if(LdEn)begin DataOut <= DataIn;End else DataOut <= DataOut + 4'b0001;end 6.不同层次之间的语句使用Tab键进行缩进,每加深一层缩进一个Tab; 8.在endmodule,endtask,endcase等标记一个代码块结束的关键词后面要加上一行注释说明这个代码块的名称;
9.在task名称前加tsk以示标记。在function的名称前加func以示标记。例如: task tskResetSystem; ……
endtask //of tskResetSystem 五.小结:
以上列出的代码编写规范无法覆盖代码编写的方方面面,还有很多细节问题,需要在实际编写过程中加以考虑。并且有些规定也不是绝对的,需要灵活处理。并不是律条,但是在一个项目组内部、一个项目的进程中,应该有一套类似的代码编写规范来作为约束。总的方向是,努力写整洁、可读性好的代码 二.reg型
在“always”块内被赋值的每一个信号都必须定义成reg型。reg型数据的缺省初始值是不定值。
reg型只表示被定义的信号将用在“always”块内,理解这一点很重要。并不是说reg型信号一定是寄存器或触发器的输出。虽然reg型信号常常是寄存器或触发器的输出,但并不一定总是这样。三.memory型
memory型数据是通过扩展reg型数据的地址范围来生成的。其格式如下: reg [n-1:0] 存储器名[m-1:0]; 或
reg [n-1:0] 存储器名[m:1];
在这里,reg[n-1:0]定义了存储器中每一个存储单元的大小,即该存储单元是一个n位的寄存器。存储器名后的[m-1:0]或[m:1]则定义了该存储器中有多少个这样的寄存器。
reg [7:0] mema[255:0];这个例子定义了一个名为mema的存储器,该存储器有256个8位的存储器。该存储器的地址范围是0到255。注意:对存储器进行地址索引的表达式必须是常数表达式。
尽管memory型数据和reg型数据的定义格式很相似,但要注意其不同之处。如一个由n个1位寄存器构成的存储器组是不同于一个n位的寄存器的。见下例: reg [n-1:0] rega;//一个n位的寄存器
reg mema [n-1:0];//一个由n个1位寄存器构成的存储器组
一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。见下例:
rega =0;
//合法赋值语句 mema =0;
//非法赋值语句
如果想对memory中的存储单元进行读写操作,必须指定该单元在存储器中的地址。下面的写法是正确的。mema[3]=0;
//给memory中的第3个存储单元赋值为0。3.3.1.基本的算术运算符
在Verilog HDL语言中,算术运算符又称为二进制运算符,共有下面几种: 1)+(加法运算符,或正值运算符,如 rega+regb,+3)2)
-(减法运算符,或负值运算符,如 rega-3,-3)3)×(乘法运算符,如rega*3)4)/(除法运算符,如5/3)5)%(模运算符,或称为求余运算符,要求%两侧均为整型数据。如7%3的值为1)注意:
在进行算术运算操作时,如果某一个操作数有不确定的值x,则整个结果也为不定值x。1)~
//取反 2)&
//按位与 3)|
//按位或 4)^
//按位异或 5)^~
//按位同或(异或非)在Verilog HDL语言中存在三种逻辑运算符: 1)&&逻辑与 2)|| 逻辑或 3)!逻辑非
关系运算符共有以下四种: a < b
a小于b a > b
a大于b a <= b a小于或等于b a >= b a大于或等于b 3.3.5.等式运算符 3.3.6.移位运算符
3.3.7.位拼接运算符(Concatation)3.3.10.关键词 在Verilog HDL中,所有的关键词是事先定义好的确认符,用来组织语言结构。关键词是用小写字母定义的,因此在编写原程序时要注意关键词的书写,以避免出错。下面是Verilog HDL中使用的关键词(请参阅附录:Verilog语言参考手册): always,and,assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive, endspecify, endtable,endtask,event,for,force,forever,fork,function,highz0,highz1, if,initial, inout, input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,notifl, or, output, parameter, pmos, posedge, primitive, pull0, pull1, pullup, pulldown, rcmos, reg, releses, repeat, mmos, rpmos, rtran, rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0, strong1, supply0, supply1, table, task, time, tran, tranif0, tranif1, tri, tri0, tri1, triand, trior,trireg,vectored,wait,wand,weak0,weak1,while,wire,wor, xnor,xor(1).非阻塞(Non_Blocking)赋值方式(如 b <= a;)1)
块结束后才完成赋值操作。2)b的值并不是立刻就改变的。
3)
这是一种比较常用的赋值方法。(特别在编写可综合模块时)(2).阻塞(Blocking)赋值方式(如 b = a;)1)
赋值语句执行完后,块才结束。
2)b的值在赋值语句执行完后立刻就改变的。3)
可能会产生意想不到的结果。一.顺序块
顺序块有以下特点:
1)
块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。
2)
每条语句的延迟时间是相对于前一条语句的仿真时间而言的。3)
直到最后一条语句执行完,程序流程控制才跳出该语句块。
顺序块的格式如下: begin 语句1;语句2;......语句n;end 其中:
块名即该块的名字,一个标识名。其作用后面再详细介绍。
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句。二.并行块
并行块有以下四个特点:
1)
块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。
2)
块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间的。
3)
延迟时间是用来给赋值语句提供执行时序的。
4)
当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。并行块的格式如下: fork 语句1;语句2;.......语句n;join 其中:
块名即标识该块的一个名字,相当于一个标识符。•
块内说明语句可以是参数说明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句、time型变量声明语句、事件(event)说明语句。
在fork_join块内,各条语句不必按顺序给出,因此在并行块里,各条语句在前还是在后是无关紧要的。见下例: 三.块名
在VerilgHDL语言中,可以给每个块取一个名字,只需将名字加在关键词begin或fork后面即可。这样做的原因有以下几点。
1)
这样可以在块内定义局部变量,即只在块内使用的变量。2)
这样可以允许块被其它语句调用,如被disable语句。
3)
在Verilog语言里,所有的变量都是静态的,即所有的变量都只有一个唯一的存储地址,因此进入或跳出块并不影响存储在变量内的值。基于以上原因,块名就提供了一个在任何仿真时刻确认变量值的方法。casez语句用来处理不考虑高阻值z的比较过程,casex语句则将高阻值z和不定值都视为不必关心的情况。
如果用到if语句,最好写上else项。如果用case语句,最好写上default项。遵循上面两条原则,就可以避免发生这种错误,使设计者更加明确设计目标,同时也增强了Verilog程序的可读性。3.6.循环语句
在Verilog HDL中存在着四种类型的循环语句,用来控制执行语句的执行次数。1)forever
连续的执行语句。2)repeat
连续执行一条语句 n 次。
3)while
执行一条语句直到某个条件不满足。如果一开始条件即不满足(为假),则语句一次也不能被执行。
4)for通过以下三个步骤来决定语句的循环执行。a)
先给控制循环次数的变量赋初值。
b)
判定控制循环的表达式的值,如为假则跳出循环语句,如为真则执行指定的语句后,转到第三步。c)#1:当为时序逻辑建模,使用“非阻塞赋值”。#2:当为锁存器(latch)建模,使用“非阻塞赋值”。#3:当用always块为组合逻辑建模,使用“阻塞赋值”
#4:当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。
#5:不要在同一个always块里面混合使用“阻塞赋值”和“非阻塞赋值”。#6:不要在两个或两个以上always块里面对同一个变量进行赋值。#7:使用$strobe以显示已被“非阻塞赋值”的值。#8:不要使用#0延迟的赋值。
#9:在VERILOG语法中,if...else if...else 语句是有优先级的,一般说来第一个IF的优先级最高,最后一个ELSE的优先级最低。如果描述一个编码器,在XILINX的XST综合参数就有一个关于优先级编码器硬件原语句的选项Priority Encoder Extraction.而CASE语句是”平行“的结构,所有的CASE的条件和执行都没有“优先级”。而建立优先级结构会消耗大量的组合逻辑,所以如果能够使用CASE语句的地方,尽量使用CASE替换IF...ELSE结构。
#10:XILINX的底层可编程硬件资源叫SLICE,由2个FF和2个LUT组成。FF触发器 LUT查找表
ALTERA的底层可编程硬件资源叫LE, 由1个FF和1个LUT组成。#11:慎用锁存器(latch),同步时序设计要尽量避免使用锁存器,综合出非目的性latch的主要原因在于不完全的条件判断句。另外一种情况是设计中有组合逻辑的反馈环路(combinatorial feedback loops)。
#12:状态机的一般设计原则,Biary, gray-code 编码使用最少的触发器,较多的组合逻辑。而one-hot编码反之。所以CPLD多使用GRAY-CODE, 而FPGA多使用ONE-HOT编码。另一方面,小型设计使用GRAY-CODE和BINARY编码更有效,而大型状态机使用ONE-HOT更有效。
#13:业界主流CPLD产品是lattice的LC4000系列和ALTERA的MAX3000系列。#14:复位使初始状态可预测,防止出现禁用状态。FPGA 和CPLD 的复位信号采用异步低电平有效信号,连接到其全局复位输入端,使用专用路径通道,复位信号必须连接到FPGA 和CPLD 的全局复位管脚。
#15:不要用时钟或复位信号作数据或使能信号,也不能用数据信号作为时钟或复位信号,否则HDL 综合时会出现时序验证问题。信号穿过时钟的两半个周期时,要在前后分别取样;防止出现半稳定状态。
#16:fpga设计中不要使用门时钟(don't use gated clock)。时钟信号必须连接到全局时钟管脚上。
#17:不要使用内部三态信号,否则增加功耗。#18:只使用同步设计,不要使用延时单元。
#19:避免使用负延触发的双稳态多谐振荡器(flip flop)。
#20:不要使用信号和变量的默认值(或初始值),用复位脉冲初始化 信号和变量。
#21:不要在代码中使用buffer 类型的端口读取输出数据;要使用out 类型,再增加另外变量或信号,以获取输出值。
这是因为buffer 类型的端口不能连接到其他类型的端口上,因此buffer 类型就会在整个设计的端口中传播下去。
#22:对变量要先读后写;如果先写后读,就会产生长的组合逻辑和锁存器(或寄存器)。这是因为变量值是立即获取的。
#23:在组合逻辑进程中,其敏感向量标中要包含所有要读取得信号;这是为了防止出现不必要的锁存器。
近期,在stephen Brown的一本书数字逻辑基础与verilog设计一书中看到关于触发器电路的时序分析。以前一直没有搞明白这个问题,现在觉得豁然开朗。怕忘记了,特地摘抄与此与edacn网友分享。触发器电路的时序分析:
图7-84给出了一个使用D触发器的简单电路。我们想要计算该电路能正常工作的最大的时钟频率Fmax,并且想确定该电路的保持时间是否不够长。在技术文献中,这种类型的电路分析通常叫做时序分析。假设该触发器的时序参数为:tsu=0.6ns,th=0.4ns,0.8ns<=tcQ<=1.0ns。给tcq参数规定一个范围是因为延迟参数分布在一定范围内,这样处理是现成集成电路芯片常用的方法。为了计算最小的时钟信号周期Tmin=1/Fmax,我们必须考虑在触发器中从开始到结束的所有路径。在这个简单的电路中,只有一条这样的路径,这条路径开始于数据被时钟信号的正跳变沿加载进入触发器,经过tcQ的延迟后传播到Q的输出端,再传播通过非门,同时必须满足D输入端的建立时间要求。因此: Tmin=tcQ+tNOT+tsu 由于我们关注的只是计算出最长的延迟时间,所以应该用tcQ的最大值。为了计算出tNOT,我们将假设通过任何逻辑门的延迟都可以用1+0.1k进行计算,其中k是该门的输入信号的个数。对非门而言,k=1,因此得到如下Tmin和Fmax的值:Tmin=1.0+1.1+0.6=2.7ns Fmax=1/2.7ns=370.37MHz 当然,有必要检查电路中的保持时间是否违反规定。在这种场合,我们必须核查从时钟信号的正跳变沿到D输入值改变的最短延迟。该延迟由tcQ+tNOT=0.8+1.1=1.9ns给定。因为1.9ns>0.4ns,所以保持时间够长,没有违反规定。再举一个触发器电路时序分析的例子,请考虑图7-85所示的计数器电路。假设所用的触发器的时序参数与图7-84中用过的触发器相同,请计算该电路能正常运行的最高频率。再次假设通过逻辑门的传播延迟可以用1+0.1k来计算。在这个电路中,存在着四个触发器从开始到结束的许多路径。最长的路径从触发器Q0起到触发器Q3结束。在某个电路中最长的路径成为关键路径。关键路径的延迟包括触发器Q0的时钟信号到Q的延迟、通过三个与门的传播延迟和一个异或门的延迟。我们还必须考虑触发器Q3的建立时间。因此,得到 Tmin=tcQ+3(tAND)+tXOR+tsu 用tcQ的最大值,得到 Tmin=1.0+3(1.2)+1.2+0.6=6.4ns Fmax=1/6.4ns=156.25MHz 该电路的最短路径是从每个触发器通过异或门反馈到该触发器本身的输入端。沿每个这样路径的最小延迟为tcQ+tXOR=0.8+1.2=2.0ns。因为2.0ns>th=0.4ns,因此保持时间足够长,没有违反规定。
在上面的分析中,假设时钟信号同时到达所有四个触发器。我们现在将重复这个分析,假设时钟信号同时到达触发器Q0,Q1,Q2,但到达触发器Q3有一些延迟。始终到达不同的触发器之间的时间差称为时钟偏差(clock skew),记作tskew,时钟偏差可以由许多原因引起。
在图7-85中,电路的关键路径是从触发器Q0起到触发器Q3。然而,Q3的时钟偏差使得这个延迟减少,因为时钟偏差在数据被加载进该触发器前提供了附加的时间。如果考虑增加1.5ns的时钟偏差,则从触发器Q0到触发器Q3的路径延迟由tcQ+3(tAND)+tXOR+tsu-tskew=6.4-1.5ns=4.9ns给定。该电路现在还存在一个不同的关键路径,该路径从触发器Q0起到触发器Q2结束。这条路径的延迟为
Tmin=tcQ+2(tAND)+tXOR+tsu=1.0+2(1.2)+1.2+0.6ns=5.2ns Fmax=1/5.2ns=192.31MHz
在这种场合,时钟偏差导致电路的最高时钟频率提高。但是,如果时钟偏差是负的,即触发器Q3的时钟到达时间比其他触发器更早一些,则会造成该电路的最高时钟频率Fmax降低。
因为数据加载到触发器Q3被时钟偏差延迟了,所以对所有起始于Q0,Q1,Q2而以Q3为结束点的路径,都会产生使触发器Q3的保持时间需要增加到th+tskew的影响。在该电路中,这种最短的路径是从触发器Q2到Q3的路径,其延迟时间为TcQ+tAND+tXOR=0.8+1.2+1.2=3.2ns。因为3.2ns>th+tskew=1.9ns,所以保持时间足够长,没有违反规定。
如果对时钟偏差值tskew>=3.2-th=2.8ns,重复以上保持时间的分析,则会出现保持时间不够的情况。当tskew>=2.8ns时,该电路将不可能在任何频率下可靠地运行。由于时钟偏差的存在会引起电路时序问题,所以好的电路设计方法必须保证时钟信号到达所有触发器的偏差尽可能小。
最后是我的总结:确定最小周期是找关键路径即最长路径。确定Th是否违例是找最短路径。最短路径要大于Th。如果有Tskew的情况则要大于Th+Tskew(有skew的寄存器为最短路径的终点的时候)
还有就是我对有Tskew的情况的时候为什么防止违例要最短路径>Th+Tskew。因为Q0,Q1和Q2时钟比Q3早,以他们为起点的路径已经开始走了一段时间后Q3的时钟才到才开始打入数据。所以保持时间上要加上这段skew ISE 约束文件的基本操作 1.约束文件的概念
FPGA设计中的约束文件有3类:用户设计文件(.UCF文件)、网表约束文件(.NCF文件)以及物理约束文件(.PCF文件),可以完成时序约束、管脚约束以及区域约束。3类约束文件的关系为:用户在设计输入阶段编写UCF文件,然后UCF文件和设计综合后生成NCF文件,最后再经过实现后生成PCF 文件。本节主要介绍UCF文件的使用方法。
UCF文件是ASC 2码文件,描述了逻辑设计的约束,可以用文本编辑器和Xilinx约束文件编辑器进行编辑。NCF约束文件的语法和UCF文件相同,二者的区别在于: UCF文件由用户输入,NCF文件由综合工具自动生成,当二者发生冲突时,以UCF文件为准,这是因为UCF的优先级最高。PCF文件可以分为两个部分:一部分是映射产生的物理约束,另一部分是用户输入的约束,同样用户约束输入的优先级最高。一般情况下,用户约束都应在UCF文件中完成,不建议直接修改 NCF文件和PCF文件。2.创建约束文件
约束文件的后缀是.ucf,所以一般也被称为UCF文件。创建约束文件有两种方法,一种是通过新建方式,另一种则是利用过程管理器来完成。
第一种方法:新建一个源文件,在代码类型中选取“Implementation Constrains File”,在“File Name”中输入“one2two_ucf”。单击“Next”按键进入模块选择对话框,选择模块“one2two”,然后单击“Next”进入下一页,再单击“Finish”按键完成约束文件的创建。
第二种方法:在工程管理区中,将“Source for”设置为“Synthesis/Implementation”。“Constrains Editor”是一个专用的约束文件编辑器,双击过程管理区中“User Constrains”下的“Create Timing Constrains”就可以打开“Constrains Editor”,其界面如图所示:
图启动Constrains Editor引脚约束编辑
在“Ports”选项卡中可以看到,所有的端口都已经罗列出来了,如果要修改端口和FPGA管脚的对应关系,只需要在每个端口的“Location”列中填入管脚的编号即可。例如在UCF文件中描述管脚分配的语法为: NET “端口名称” LOC = 引脚编号;需要注意的是,UCF文件是大小敏感的,端口名称必须和源代码中的名字一致,且端口名字不能和关键字一样。但是关键字NET是不区分大小写的。3.编辑约束文件
在工程管理区中,将“Source for”设置为“Synthesis/Implementation”,然后双击过程管理区中“User Constrains”下的“Edit Constraints(Text)”就可以打开约束文件编辑器,如下图所示,就会新建当前工程的约束文件。图用户约束管理窗口 UCF文件的语法说明 1.语法
UCF文件的语法为:
{NET|INST|PIN} ”signal_name“ Attribute;其中,“signal_name”是指所约束对象的名字,包含了对象所在层次的描述;“Attribute”为约束的具体描述;语句必须以分号“;”结束。可以用“#”或“/* */”添加注释。需要注意的是:UCF文件是大小写敏感的,信号名必须和设计中保持大小写一致,但约束的关键字可以是大写、小写甚至大小写混合。例如: NET ”CLK“ LOC = P30;“CLK”就是所约束信号名,LOC = P30;是约束具体的含义,将CLK信号分配到FPGA的P30管脚上。
对于所有的约束文件,使用与约束关键字或设计环境保留字相同的信号名会产生错误信息,除非将其用” “括起来,因此在输入约束文件时,最好用” “将所有的信号名括起来。2.通配符
在UCF文件中,通配符指的是“*”和“?”。“*”可以代表任何字符串以及空,“?”则代表一个字符。在编辑约束文件时,使用通配符可以快速选择一组信号,当然这些信号都要包含部分共有的字符串。例如: NET ”*CLK?“ FAST;将包含“CLK”字符并以一个字符结尾的所有信号,并提高了其速率。在位置约束中,可以在行号和列号中使用通配符。例如: INST ”/CLK_logic/*“ LOC = CLB_r*c7;把CLK_logic层次中所有的实例放在第7列的CLB中。3.定义设计层次
在UCF文件中,通过通配符*可以指定信号的设计层次。其语法规则为: * 遍历所有层次
Level1/* 遍历level1及以下层次中的模块
Level1/*/ 遍历level1种的模块,但不遍历更低层的模块
例4-5 根据图4-75所示的结构,使用通配符遍历表4-3所要求的各个模块。图层次模块示意图 表要求遍历的符号列表 管脚和区域约束语法
LOC约束是FPGA设计中最基本的布局约束和综合约束,能够定义基本设计单元在FPGA芯片中的位置,可实现绝对定位、范围定位以及区域定位。此外,LOC还能将一组基本单元约束在特定区域之中。LOC语句既可以书写在约束文件中,也可以直接添加到设计文件中。换句话说,ISE中的FPGA底层工具编辑器(FPGA Editor)、布局规划器(Floorplanner)和引脚和区域约束编辑器的主要功能都可以通过LOC语句完成。•
LOC语句语法
INST ”instance_name “ LOC = location;
其中“location”可以是FPGA芯片中任一或多个合法位置。如果为多个定位,需要用逗号“,”隔开,如下所示: LOC = location1,location2,...,locationx;目前,还不支持将多个逻辑置于同一位置以及将多个逻辑至于多个位置上。需要说明的是,多位置约束并不是将设计定位到所有的位置上,而是在布局布线过程中,布局器任意挑选其中的一个作为最终的布局位置。范围定位的语法为:
INST “instance_name” LOC=location:location [SOFT];常用的LOC定位语句如表4-4所列。表常用的LOC定位语句 使用LOC完成端口定义时,其语法如下: NET ”Top_Module_PORT“ LOC = ”Chip_Port“;其中,“Top_Module_PORT”为用户设计中顶层模块的信号端口,“Chip_Port”为FPGA芯片的管脚名。
LOC语句中是存在优先级的,当同时指定LOC端口和其端口连线时,对其连线约束的优先级是最高的。例如,在图4-76中,LOC=11的优先级高于LOC=38。图 LOC优先级示意图 2.LOC属性说明
LOC语句通过加载不同的属性可以约束管脚位置、CLB、Slice、TBUF、块RAM、硬核乘法器、全局时钟、数字锁相环(DLL)以及DCM模块等资源,基本涵盖了FPGA芯片中所有类型的资源。由此可见,LOC语句功能十分强大,表4-5列出了LOC的常用属性。表 LOC语句常用属性列表
Verilog HDL代码描述对状态机综合的研究 2007-11-25 16:59 1 引言
Verilog HDL作为当今国际主流的HDL语言,在芯片的前端设计中有着广泛的应用。它的语法丰富,成功地应用于设计的各个阶段:建模、仿真、验证和综合等。可综合是指综合工具能将Verilog HDL代码转换成标准的门级结构网表,因此代码的描述必须符合一定的规则。大部分数字系统都可以分为控制单元和数据单元两个部分,控制单元的主体是一个状态机,它接收外部信号以及数据单元产生的状态信息,产生控制信号,因而状态机性能的好坏对系统性能有很大的影响。
有许多可综合状态机的Verilog代码描述风格,不同代码描述风格经综合后得到电路的物理实现在速度和面积上有很大差别。优秀的代码描述应当易于修改、易于编写和理解,有助于仿真和调试,并能生成高效的综合结果。2 有限状态机
有限状态机(Finite State Machine,FSM)在数字系统设计中应用十分广泛。根据状态机的输出是否与输入有关,可将状态机分为两大类:摩尔(Moore)型状态机和米莉(Mealy)型状态机。Moore型状态机的输出仅与现态有关;Mealy型状态机的输出不仅与现态有关,而且和输入也有关。图1是有限状态机的一般结构图,它主要包括三个部分,其中组合逻辑部分包括状态译码器和输出译码器,状态译码器确定状态机的下一个状态,输出译码器确定状态机的输出,状态寄存器属于时序逻辑部分,用来存储状态机的内部状态。图1 状态机的结构框图 2.1 好的状态机标准
好的状态机的标准很多,最重要的几个方面如下:
第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这里面有两层含义。其一要求该FSM的综合实现结果无_毛刺等异常扰动,其二要求FSM要完备,即使受到异常扰动进入非设计状态,也能很快恢复到正常状态。第二,状态机的设计要满足设计的面积和速度的要求。第三,状态机的设计要清晰易懂、易维护。
需要说明的是,以上各项标准,不是割裂的,它们有着直接紧密的内在联系。在芯片设计中,对综合结果评判的两个基本标准为:面积和速度。“面积”是指设计所占用的逻辑资源数量;“速度”指设计在芯片上稳定运行所能够达到的最高频率。两者是对立统一的矛盾体,要求一个设计同时具备设计面积最小,运行频率最高,这是不现实的。科学的设计目标应该是:在满足设计时序要求(包含对设计最高频率的要求)的前提下,占用最小的芯片面积,或者在所规定的面积下,使设计的时序余量更大,频率更高。另外,如果要求FSM安全,则很多时候需要使用“full case”的编码方式,即将状态转移变量的所有向量组合情况都在FSM 中有相应的处理,这经常势必意味着要多花更多的设计资源,有时也会影响FSM的频率所以,上述的标准要综合考虑,根据设计的要求进行权衡。2.2 状态机描述方法
状态机描述时关键是要描述清楚几个状态机的要素,即如何进行状态转移,每个状态的输出是什么,状态转移的条件等。具体描述时方法各种各样,最常见的有三种描述方式:
第一,整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出;第二,用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出;第三,在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态的输出(可以用组合电路输出,也可以时序电路输出)。
一般而言,推荐的FSM 描述方法是后两种。这是因为:FSM和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。
第二种描述方法同第一种描述方法相比,将同步时序和组合逻辑分别放到不同的always模块中实现,这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。在第二种方式的描述中,描述当前状态的输出用组合逻辑实现,组合逻辑很容易产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。第三种描述方式与第二种相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。
2.3 状态机的编码
二进制编码(Binary)、格雷码(Gray-code)编码使用最少的触发器,较多的组合逻辑,而独热码(One-hot)编码反之。独热码编码的最大优势在于状态比较时仅仅需要比较一个位,从而一定程度上简化了比较逻辑,减少了毛刺产生的概率。由于CPLD更多地提供组合逻辑资源,而FPGA更多地提供触发器资源,所以CPLD多使用二进制编码或格雷码,而FPGA多使用独热码编码。另一方面,对于小型设计使用二进制和格雷码编码更有效,而大型状态机使用独热码更高效。3 实例说明
下面通过实例来说明Verilog HDL代码描述对状态机综合结果的影响。
设计一个序列检测器,用于检测串行的二进制序列,每当连续输入三个或三个以上的1时,序列检测器的输出为1,其它情况下输出为0。
假设初始的状态为s0,输入一个1的状态记为s1,连续输入二个1后的状态记为s2,输入三个或以上1的状态记为s3,不论现态是何种状态一旦输入0的话,就返回到初始状态。根据题意,可画出状态图如图2所示。图2 状态图
根据状态图以及前面状态机的介绍,可以采用一个always模块来描述,状态编码采用二进制编码,程序如下: module fsm(clk,ina,out);input clk,ina;output out;reg out;parameter s0 = 3'bOO,s1 =3'b01,s2 =3'b10,s3=3'b11;reg[0:1]state;always @(posedge clk)begin state<=s0;out =0;case(state)s0:begin state<=(ina)?s1:s0;out=0;end s1:begin state<=(ina)?s2:s0;out=0;end s2:begin state<=(ina)?s3:s0;out=0;end s3:begin state<=(ina)?s3:s0;out=1;end endcase end endmodule
采用Synplify Pro工具在Altera EPF10K10系列器件上进行综合,其综合的结果如图3所示。
如果采用两个always来描述,程序的模块声明、端口定义和信号类型部分不变,只是改动逻辑功能描述部分,改动部分的程序如下: alwys @(posedge dk)state fsm <=next_state;always @(state_fsm or ina)begin state<=s0;out =0;case(state_fsm)s0:begin next_state=(ina)?s1:s0;out=0;end s1:begin next state=(ina)?s2:s0;out=0: end s2:begin next_state=(ina)?s3:s0;out=0;end s3:begin next_state=(ina)?s3:s0;out=1;end endcase end endmodule
在相同的器件上其综合的结果如图4所示,比较图3与图4的综合结果,可以看出。两种综合结果都是采用了两个触发器来存储状态。其不同的地方是输出部分,采用一个always模块的输出结果是寄存器输出。采用两个always模块描述的是组合逻辑直接输出,这是因为代码中的输出赋值也放在了时钟的上升沿(always @(posedge clk))。其综合的结果是寄存器,因此它比直接组合逻辑输出延迟一个时钟周期。图4
如果采用一位hot编码,仅改动参数设置的两行程序。采用一个always模块描述,改动部分的程序如下:
parameter s0 = 3'b0001,s1 =3'b0010,s2 =3'b0100,s3=3'b1000;reg[0:3] state;图5
综合的结果如图5所示。将图5与图3相比,可以看出:
图5中状态寄存器采用了4个触发器来存储状态,而图3采用了两个触发器来存储状态,这是由于它们的状态编码的不同而得到的不同的综合结果,采用二进制编码综合得到的触发器要比采用独热码综合得到的触发器少。它们的共同之处都是采用了寄存器来输出的。3 结束语
有多种可综合状态机的Verilog HDL代码描述风格。其综合的结果是不同的。其中广泛采用的是两个或三个always模块描述。组合逻辑输出型状态机不适合应用在高速复杂系统设计中,在高速系统中应当采用寄存器输出型状态机。寄存器类型信号不会产生毛刺,并且输出不含组合逻辑。会减少组合逻辑门延时。容易满足高速系统设计要求。总之,状态机的设计是数字系统设计中的关键部分,设计时做到心中有电路。充分考虑其综合的结果,才能编写出高质量的综合代码。进而提高设计水平。
模块划分非常重要,除了关系到是否最大程度上发挥项目成员的协同设计能力,而且直接决定着设计的综合、实现时间。下面是一些模块划分的原则。
a.对每个同步设计的子模块的输出使用寄存器(registering)。也即用寄存器分割同步时序模块的原则。)@(F3 f+ D” j
使用寄存器的好处有:综合工具在编译综合时会将所分割的子模块中的组合电路和同步时序电路整体考虑。而且这种模块结构符合时序约束的习惯,便于使用时序约束熟悉进行约束。)q9 t/ |# a 7 p0 C b.将相关的逻辑或者可以复用的逻辑划分在同一模块内。
这样做的好处有,一方面将相关的逻辑和可以复用的逻辑划分在同一模块,可以最大程度的复用资源,减少设计消耗的面积。同时也更利于综合工具优化一个具体功能(操作)在时序上的关键路径。其原因是,综合工具只能同时考虑一部分逻辑,而所同时优化的逻辑单元就是模块,所以将相关功能划分在同一模块更有利于综合器的优化。;l/ w" k5 r9 G4 X4 x c.将不同优化目标的逻辑分开。
好的设计,在规划阶段,设计者就已经思考了设计的大概规模和关键路径,并对设计的优化目标有一个整体上的把握。对于时序紧张的部分,应该独立划分为一个模块,其优化目标为“speed”,这种划分方法便于设计者进行时序约束,也便于综合和实现工具进行优化。比如时序优化的利器Amplify,使用模块进行区域优化更方便一些。另一类矛盾集中在面积的设计,也应该划分成独立的模块,这类模块的优化目标是“Area”,同样将他们规划到一起,更有利于区域布局与约束。这种根据优化目标进行优化的方法的最大好处是,对于某个模块综合器仅仅需要考虑一种优化目标和策略,从而比较容易达到较好的优化效果。相反的如果同时考虑两种优化目标,会使综合器陷入互相制约的困境。
d.将松约束的逻辑归到同一模块。
有些逻辑的时序非常宽松,不需要较高的时序约束,可以将这类逻辑归入同一模块,如多周期路径“multi-cycle”等。将这些模块归类,并指定松约束,则可以让综合器尽量的节省面积资源。
e.将RAM/ROM/FIFO等逻辑独立划分成模块。
这样做的好处是便于综合器将这类资源类推为器件的硬件原语,同时仿真时消耗的内存也会少些,便于提高仿真速度。(大多数仿真器对大面积的RAM都有独特的内存管理方式)0 o4 B!p5 Q-D)O)Y7 M/ ] f.合适的模块规模。
规模大,利于“Resource Sharing”。但是对综合器同时处理的逻辑量太大,不利于多模块和增量编译模式。关于约束,时序分析的问题汇总
很多人发贴,来信询问关于约束、时序分析的问题,比如:如何设置setup,hold时间?如何使用全局时钟和第二全局时钟(长线资源)?如何进行分组约束?如何约束某部分组合逻辑?如何通过约束保证异步时钟域之间的数据交换可靠?如何使用I/O逻辑单元内部的寄存器资源?如何进行物理区域约束,完成物理综合和物理实现?等等。。
为了解决大家的疑难,我们将逐一讨论这些问题。今天先讨论一下约束的作用?
有些人不知道何时该添加约束,何时不需要添加?有些人认为低速设计不需要时序约束?关于这些问题,希望下面关于约束作用的论述能够有所帮助!附加约束的基本作用有3:(1)提高设计的工作频率
对很多数字电路设计来说,提高工作频率非常重要,因为高工作频率意味着高处理能力。通过附加约束可以控制逻辑的综合、映射、布局和布线,以减小逻辑和布线延时,从而提高工作频率。(2)获得正确的时序分析报告
几乎所有的FPGA设计平台都包含静态时序分析工具,利用这类工具可以获得映射或布局布线后的时序分析报告,从而对设计的性能做出评估。静态时序分析工具以约束作为判断时序是否满足设计要求的标准,因此要求设计者正确输入约束,以便静态时序分析工具输出正确的时序分析报告。(3)指定FPGA/CPLD引脚位置与电气标准
FPGA/CPLD的可编程特性使电路板设计加工和FPGA/CPLD设计可以同时进行,而不必等FPGA/CPLD引脚位置完全确定,从而节省了系统开发时间。这样,电路板加工完成后,设计者要根据电路板的走线对FPGA/CPLD加上引脚位置约束,使FPGA/CPLD与电路板正确连接。另外通过约束还可以指定IO引脚所支持的接口标准和其他电气特性。为了满足日新月异的通信发展,Xilinx新型FPGA/CPLD可以通过IO引脚约束设置支持诸如AGP、BLVDS、CTT、GTL、GTLP、HSTL、LDT、LVCMOS、LVDCI、LVDS、LVPECL、LVDSEXT、LVTTL、PCI、PCIX、SSTL、ULVDS等丰富的IO接口标准。
另外通过区域约束还能在FPGA上规划各个模块的实现区域,通过物理布局布线约束,完成模块化设计等。贴2:时序约束的概念和基本策略!
时序约束主要包括周期约束(FFS到FFS,即触发器到触发器)和偏移约束(IPAD到FFS、FFS到OPAD)以及静态路径约束(IPAD到OPAD)等3种。通过附加
第二篇:如何学习电脑入门
如何学习电脑入门
在学习电脑之前,先消除对电脑的紧张感,其实学电脑是很轻松的事,电脑并不神秘(如果搞的那么复杂,估计也不会发展那么迅速了),电脑只是一种工具,电脑的内部工作原理虽然很复杂,但不需要了解那些深奥的原理,只要知道怎样使用就行了。
电脑的使用是比较简单的,和使用电视机,录像机没有什么区别,使用遥控器选择电视频道,该频道的节目就出现在电视屏幕上,同样,只要给电脑些指令,就会按照要求工作,其次,别被电脑那些”高深”的词汇吓倒,诸
如”Windows”,”鼠标”,”控制面板,.…”。它们只是一些部件文件的名字,不需要深入理解其意。在开始学习的时候,只需要知道常用的名字就可以了,等以后慢慢积累了,就知道很多关于电脑的东西了。
再次,应了解一点电脑知识的组成及发展,电脑知识分硬件部分的知识和软件部份的知识,硬件部分的知识,如计算机组成原理,硬件的组装,电工电子学等,软件部分的知识,如操作系统(访问windows)的使用,语言程序的使用,办公软件office的使用,一般非计算机专业用户先只要熟练掌握软件部分的知识就足够了,当熟知这些知识后,自然就能由此及彼,由表及里地掌握电脑的其它知识了。现在把流行的,常用的电脑知识分类,了解一下所学电脑知识的用途。今天就简单和大家说了电脑学习的入门,其实一开始入门,不需要理解复杂的东西,主要搞懂简单的东西就可以了!等你以后慢慢了解电脑,在由表及里地掌握电脑的其它知识了
第三篇:钢琴学习入门
钢琴学习入门
1.你用的键盘乐器
无论你是拥有一个真正的钢琴,还是一个电钢琴、电子琴或风琴,这里的教程都会教你认识键盘,弹奏五线谱曲子,并学习基本的五线谱知识。简单说来,钢琴的学习包括认识键盘,将手放到合适的位置,如何控制运用你的手指,如何用双手而不是单单右手来共同弹奏,当然还有如何看懂五线谱钢琴曲谱。
你是用哪种键盘乐器来学习的呢?一共有多少个键盘? 我建议你最好使用有61个键盘的那种。如果你的键盘有重力感觉(垂重感键盘)的就更好了,就更接近真实钢琴的机械装置和触感。一般来说简易低档的电子琴的键盘没有重力感设计,键盘的按下时没有什么阻力(比较真实的钢琴键盘就会知道)。
2.白键盘 黑键盘 从哪里开始呢?
看到键盘可能一开始会迷惑:这么多的键盘---88个键如何能记住呢?
不过你很快就可以总结出黑键的分布规律:即三个黑键和两个黑键规律性的排列,而且间隔是完全一样的。
你还会发现上图的白键上有规律的标出绿色的字母C,这个C是出现在两个黑键左面的白键上的。至于这个为何叫C以后会详细介绍。另一个你要注意记忆的是键盘中央的C位置,既所谓的中央C。这是一个需要牢记的位置,你以后会发现这个标志性的C的很多意义。而下面的中央C位置是真实钢琴的键盘位置。
3.钢琴键盘的分组 五线谱基本要素
上图最上面的就是你经常看到的钢琴的五线谱,中间那个空心圆在短横线的位置---线间就是中央C。这个中央C位置是你弹奏任何一个钢琴曲子都要参考的键盘。
五线谱是记录音乐的一种语言,就象英语、汉语一样,它同样有自己的规则,告诉你弹什么和如何弹奏。最明显的特征就是左端的谱号形式-----高音谱号和低音谱号一起成联合谱表,这是一个标准的钢琴五线谱形式。音符(后面还要讲)在线间或线上。
将中央C的一组白色键盘灰颜色填充,你会发现以C为一个组,七个白色琴键加上五个黑色键盘(两个黑色和三个黑色的)构成一12个键盘组,而且这个C组不断重复。随便用左手或右手弹奏这些不同的组会发现越往右侧的声音越高,越往左声音越低。4.C和八度
上面的图示显示出在中央C右面 和左面的其他的C在五线谱上面的位置。从中可以看出,在键盘上有规律的C的位置排列到了五线谱上面就没有什么规律可循。换句话说,不同C组的键盘位置在五线谱位置上没有什么联系,你只能通过大量的练习和不断的记忆来逐渐掌握。
5.线上音符
上面的五线谱从中央C上出现的线上的另外三个音符是E G B,下图是键盘上对应的E G B位置。6.线间音符
现在我们来看在线间位置出现的音符。上图中央C是作为参考位置,当然C不是在线间的音符。上图标出了线间上D F A的位置以及键盘对应的音符位置。
7.白键音符
现在你应该已经将白键的音符掌握了。上图就是C D E F G A B在白键盘上的7个音符的五线谱位置和键盘实际对应位置。这7个音符应该是你很熟悉的,对应的简谱就是1 2 3 4 5 6 7。
第四篇:英语语法入门学习
育星教育网 http://丰富的资源 最快的更新 优质的服务 诚信的运作 英语语法入门学习
首先要注意句子的结构:即句子的构成,主语+谓语+宾语+其它构成。在句子中,我们要注意谓语的变化,什么是谓语呢?谓语就是动词。在句子中宾语有时候是可以省略的,但是谓语(动词)是不可能省略的,那么动词有以下4+1类:
1、be动词:am is are was were2、使役动词:及物动词:(read, study, do play)
不及物动词:(listen to, look for, ask for)
3、情态动词:can-couldmay-might
will-wouldshall-should
must-have toneed-dare
ought tobe able tohad better4、感官动词:see look seem watch touch smell taste5、助动词:do does did have has had1、所有格:He is Fred's best friend.(-'s)
2、动词现在时的第三人称单数:Alfredo works.(-s)
3、动词过去式:Fred worked.(-ed),但亦有不规则变化。
4、现在分词/进行时态:Fred is working.(-ing)([注]如果动词的末音节为辅音结尾的闭音节,则须双写末辅音,如running)
5、过去分词:The car was stolen.(-en);Fred has talked to the police.(-ed),但亦有不规则变化。
6、动名词:Working is good for the soul.(-ing)
7、名词的复数:Fred has two blue eyes.(-s)([注]如果动词的尾字是s,sh,x,ch,则需加-es,如dishes)
8、形容词的比较级:Fred is smarter than Rick.(-er)形容词末尾加-er,多音节在前面”加more,如“more difficult”。
9、形容词的最高级:Fred has the fastest car.(-est)形容词末尾加-est,多音节词在前面加most,如“the most difficult”。/ 6
英语的基本语序为SVO,且基本上不能任意变换语序,除了在少数诗词以外;另一方面,有时英语会使用OSV的语序。(注:S:Subject[主语];V:Verbal phrase[];O:Object[宾语])
英语中所有的词可分成十大类,每一类词在句子中都有其特定的位置和作用。这十大词类是:
一、名 词:表示人或事物的名称的词。
二、形容词:表示人或事物的特征的词。
三、副 词:修饰动词、形容词和副词的词。
四、代 词:是代替名词、形容词和数词的词。
五、数 词:表示数量和顺序的词。
六、动 词:表示动作和状态的词。
七、冠 词:与名词连用,其说明人或事物的作用。
八、介 词:通常置于名词和代词之前,表示名词和代词与其他词的关系。
九、连 词:连接词与词、短语与短语、句子与句子的词。
十、感叹词:表示说话人感情或语气的词。
英语的时态
英语共有十六个时态、四个体。(注:四个体为——一般、进行、完成、完成进行。)
英语中的四个体相当于法语、西班牙语以及所有印欧语系罗曼语族中的式,如:直陈式,命令式等。
(1)一般现在时
基本形式(以do为例): 第三人称单数:does(主语为非第三人称单数); 肯定句:主语+动词原形+其他; 否定句:主语+don‘t+动词原形+其他; 一般疑问句:Do+主语+动词原形+其他。肯定回答:Yes,+ 主语+do. 否定回答:No,+主语+don't.特殊疑问句:疑问词+一般疑问句语序
(2)一般过去时
be动词+行为动词的过去式
was/were+not;在行为动词前加didn‘t,同时还原行为动词
was或were放于句首;用助动词do的过去式did提问,同时还原行为动词
(3)一般将来时
am/are/is+going to+do
will/shall+do
am/is/are/about to + do
am/is/are to + do 一般将来时的表达方法 be going to +动词原形 be +不定式,be to+动词原形,be about to +动词原形 be able to +不定式 be about to+动词原形
(4)过去将来时
be(was,were)going to+动词原形 be(was,were)about to+动词原形 be(was,were)to+动词原形 肯定句:主语+be(was,were)going to+动词原形~.否定句:主语+be(was,were)not going to+动词原形~.疑问句:Be(Was,Were)+主语+going to+动词原形~?肯定句:主语+would(should)+动词原形~.否定句:主语+would(should)not+动词原形~.疑问句:Would(Should)+主语+动词原形~?
(5)现在进行时
主语+be+动词ing〔现在分词〕形式 第一人称+am+doing+sth第二人称+are+doing +sth 第三人称+is+doing+sth
(6)过去进行时
肯定句:主语+was/were+doing+其它
否定句:主语+was/were+not+doing+其它
一般疑问句及答语:Was/Were+主语+doing+其它 答语:Yes,I was./No,I wasn't.特殊疑问句:特殊疑问词+was/were+主语+doing+其它
(7)将来进行时
动词be的将来时+现在分词
(8)过去将来进行时
should(would)+be+现在分词
(9)现在完成时
基本结构:主语+have/has+过去分词(done)
①肯定句:主语+have/has+过去分词+其他
②否定句:主语+have/has+not+过去分词+其他
③一般疑问句:Have/Has+主语+过去分词+其他
④特殊疑问句:特殊疑问词+一般疑问句(have/has+主语+过去分词+其他
(10)过去完成时
基本结构:主语+had+过去分词(done)①肯定句:主语+had+过去分词+其他 ②否定句:主语+had+not+过去分词+其他 ③一般疑问句:Had+主语+过去分词+其他 肯定回答:Yes,主语+had 否定回答:No,主语+hadn't④特殊疑问句:特殊疑问词+一般疑问句(had+主语+过去分词+其他)语法判定:
(1)by + 过去的时间点。如:
I had finished reading the novel by nine o'clock last night.(2)by the end of + 过去的时间点。如:
We had learnt over two thousand English words by the end of last term.(3)before + 过去的时间点。如:
They had planted six hundred trees before last Wednesday.(11)将来完成时
(shall)will+have+动词过去分词
before+将来时间或by+将来时间
before或by the time引导的现在时的从句
(12)过去将来完成时
should / would have done sth.(13)现在完成进行时
have/has been +-ing 分词
(14)过去完成进行时
had been +-ing 分词
(15)将来完成进行时
主语+ shall/will have been doing
(16)过去将来完成进行时
should+have been+现在分词用于第一人称
would have been+现在分词用于其他人称
苏教版:
1、感叹句:常用how 和what 这两个感叹词来引导表示强烈感情的句子。句式:whata/an +形容词+单数名词(+主语+谓语)!
What+形容词+复数名词(同上)
How+形容词(同上)
2、can I/mayI表示我可以吗?用来征求同意,如果同意就用sure回答
Shall I表示我们好吗?也是征求
3、I’dlike我想要/我宁愿
4、sorry/excuse me5、love/like6、It’s timefor+名词
to+ 动词或动词短语
7、what’s two and three? and= plus8、why don’t表达建议,为什么不ok /all right
9,what’s the boy with big eyes?With表示有的意思
10、these、those11、here isfor you给你
12、there be 表示有there is a book and a pencil on the desk(就近原则)
人称代词Be动词形容词性物主代词名词性物主代词宾格
Iammymineme
youareyouryoursyou heishishishim sheisherhersher itisitsitsit weareouroursus theyaretheirtheirsthem13、’s名词所有格
(1)有生命的名词,单数’s / 复数’(以s结尾)不以s结尾加’s
(2)没有生命的词,通常用“of+名词”如 the color of the coat
第五篇:学习易经如何入门
学习易经如何入门
易经是我国春秋以前解释“易”的经典书籍,是华夏智慧和文化的结晶。人们所知道的《易经》有三部《连山易》、《归藏易》、《周易》,前2部已经失 传,真正完整保存下来的只有周易。社会上不断有人声称已经发掘出了连山易和归藏易,并整理出版了相关书籍,但这些书籍被许多人认为是一种抄作,并没有得到 专家的认可和社会的承认。本文出自大成国学研究院张成。转载请说明出处。不过,人们通过古代易学文献的描述,已经确定了连山易是以“艮”卦为首,归藏易以“坤”卦为首,而周易是以“乾”卦为首。诸如南 怀瑾这样的专家认为,堪舆、医药等方面有关易的运用,这与连山易、归藏易是分不开的。几千年来,易经一直被人们誉为“群经之首”,这是因为易经包罗了宇宙万物产生、变化的的根本规律,其原理被无数的智者所证实并广泛得到应用,甚至所有的哲 学思想,在易经里面都能找到踪迹,然而人们却无法用所谓科学”的方法来全面地证明。这样,易经便被蒙上了一层神秘的色彩,吸引着无数的人来学习研究,也 无可避免地染上了迷信的内容。易经有如此的魅力,那么易经是如何产生的呢?因年代的久远,再加上远古的人们缺乏文字,今天的人们已经很难准确考证,但通过有限的资料,以及一些远古的传 说,我们大致理清了易经产生的脉络。孔子所写的《易传》告诉我们,远古人们仰则观象于天,俯则观法于地,取鸟兽之纹与地之宜,近取诸身,远取诸物,作八卦 以通神明之德、类万物之情。从这儿我们可以看出,什么是易经易经并非天外之物,它是人们效法天地而来,用一种简单易懂的符号来揭示自然的一些法则,从而指导人们更好地生活。什么是易经因此,易经是非常健 康的思想,其本源并不神秘,而是极其简单,所以称之为“易”。小雅甚至认为,八卦虽然是伏羲所作,但却并非他所创。这是由以往诸如有巢氏、燧人氏等长期观 察所总结传承而来,伏羲将这些思想进行分析,用通俗易懂的八卦符号,使许多人们看明白了其中的意思,从而得以传播,因此后人便有此误传。
易经的发展《左传》中记载,楚文王的左史倚相“能读《三坟》、《五典》、《八索》、《九丘》”。孔安国在《尚书?序》里说:“伏羲、神农、黄帝之书,谓之《三 坟》,言大道也。少昊、颛顼、高辛、唐、虞之书,谓之《五典》,言常道也。”三皇五帝之书”即三坟、五典,八索就是八卦,九丘就是九畴,是《河图》、《洛 书》的理数,由此可见,易经并非上天所赐,而是和万物一样逐渐发展而来.伏羲用八卦符号来演示易的原理,使易文化得到了飞跃发展,到了神农时代,什么是易经易的应用进一步得到了很大发展。当时人们不象现在一样交通发达,人们最大的麻烦是 困于大山甚至猛兽,因此,代表大山的“艮”便成了首卦。到了黄帝时代,物质生活得到了极大的补充,人们有了相对温暖的家,也开始有了积蓄,所以有了“归 藏”的思想雏形。以后各个朝代,都有相应的变更和补充,其中最有代表性的就是前面所说的《连山易》和《归藏易》,这本经典以及后来的周易被后人并称为“三 易”,至今仍以这三易为主导。由于古代没有印刷技术,春秋战国又是兵荒马乱,人们为生存而疲于奔命,再加上秦始皇焚书,诸多原因导致《连山易》和《归藏易》的正本已经失传,但其思想及 应用仍然被广泛流传。秦前的易经大多本着法天象地的原则,广泛用于祭祀、决策等国家大事。因此当时的儒者比较精通易经,这是理所当然的事。我们所下的围 棋,也是易经应用的工具之一。由于上述原因,《周易》便成了秦朝以后大多数人学习研究易经的唯一宝典。什么是易经周易是文王研究易经的应用体系,说所谓“文王演易、周公祖述”,也就是说,周易是由 周公记录整理并形成文字传承下来的。周易中的卦辞和爻辞便是文王和周公对“卦”和“爻”的解释。由于周易原文深奥难懂,孔子晚年作《十翼》系统地对周易作 了解释和说明,有人说《十翼》的一部分也可能是孔子的学生所作。
孔子所作《十翼》对后世学习研究易经起到了无可比拟的作用,至今仍是解释易经的最高权威,其内容已经被加到了周易原文中去,一起成为经文的一部分。《十 翼》便是:①上经的彖辞、②下经的彖辞、③上经的象辞、④下经的象辞、⑤《系辞上传》、⑥《系辞下传》、⑦《文言》、⑧《说卦传》、⑨《序卦传》、⑩《杂 卦传》。因此,孔子被后世称为继伏羲、文王之后的“易更三圣”之一。
孔子将《易》列为六艺之一并以此教育学生,而孔子的学生中,专门传授易经的主要有两人即卜子夏和商瞿(qú),他们的二人为易经的传承起到了很大作用,世上留传子夏水平没有商瞿高等传言概不可信。除了孔门弟子外,世上还有许多易经研究传播者,并非只有卜商两宗。《易》者,不外乎义理、象数两途,义理是《易》的内容,象数是《易》的形式。先民们有了太极的概念,然后产生了太极图;有了阴阳的概念,然后产生了两仪;有了四时的概念,然后产生四象;上观天象,下看地理,又观察大地万物,近取法于人体的解剖图形,远取法于万物的各种形象,然后造作了八卦,又交叉重迭衍生六十四卦;又造作河图、洛书。《易经·系辞上》说:“易有太极,是生两仪,两仪生四象,四象生八卦,八卦定吉凶,吉凶成大业。”所以说,以六十四卦为内容的卦象系统,以五行九宫为基础的河图洛书,都是易学文化的图象形式。卦画的最小单位是爻:“—”为阳爻,“--”为阴爻,阴阳爻、阴阳卦正是阴阳思想的符号化(线条符号)。太极图的黑白相间、首尾交合,正是阴阳对立统一、消长流行、互根互动的最佳图示(图形符号)。混沌之气——太极,于旋转中生出阴阳——两仪,阴阳于互动中生出四时——四象、八卦、六十四卦;五行于相生相克之中,演化出十分逼真的河图;九宫于循环往复之中衍生出洛书。易经八卦入门正是这种无穷变化,才启发了后人,不断地探索,不断地创造。我们的艺术家和设计师就是从这个让人无限遐想的太极图、无穷变化的阴阳爻、相生相克的河图、循环往复的洛书中,激发了灵感,产生了奇思妙想,于是就有了寓意深刻的中国书法和绘画艺术;有了美不胜收的中国古典建筑和园林艺术;有了精妙绝伦的中国民间艺术。看了汉代张衡设计制造的浑天仪和地动仪,有谁不认为这两件科学仪器是两件堪称世界之绝的艺术设计作品,又有谁不认为其中蕴涵了中国易学文化的精髓。所以古代的艺术家和科学家都说:太极图本身就是艺术和科学的秘籍。
太极图被称为“中华第一图”。从孔庙到道观的标识物;从道教的服饰到游方术士的招摇旗;从中医、气功、武术及中国古典书籍的书刊封面、会徽、会标,到韩国国旗图案、新加坡空军机徽、玻尔的爵士勋章等,太极图无不跃然其上。太极图除了阴阳鱼图形外,还有五层图形(即“周敦颐太极图”)、空心圆图形、黑白半圆图形等等。阴阳鱼太极图,早期称作先天图、河图、先天自然河图、先天自然之图、古太极图等;五层太极图又称无极图、太极顺逆图、太极顺生图、丹道逆生图等。
想学会易经八卦首先要从关于太极图的起源,学起那么历来说法不一,有原始时代说,有太古洪荒说,有生殖器崇拜说,不一而足。宋朝的朱震认为,太极图是由五代末宋初的道教鼻祖之一陈抟传下,他在《汉上易传·进易说表》中说:“以先天图传种放,放传穆修,穆修传李之才,之才传邵雍。”但是陈抟的太极图是谁传的,他没说,但恐怕也不会是陈抟自己创造的,因为有无数的出土文物证明。台湾的陈立夫在《关于太极图的一些问题》中认为:“大陆先后所出土之古太极图,较《周易》及《乾凿度》之成书,尚早三、四千年。易经八卦入门诸如陕西永靖所出土六千五百年前(伏羲时代)双耳彩陶壶上之双龙古太极图(藏瑞典远东博物馆),乃使用毛笔中锋所画,竟早于孔子四千年。又出土商代及西周之多件青铜器上,亦契有雌雄双龙相互缠绕之太极图。”陈立夫所称“双龙太极图”实际上就是华夏始祖“伏羲女娲交尾图”,陈立夫的说法比较科学,远古先民没有今天这样的科学手段,借助图象来推演天文地理、宇宙万物,那是十分自然的。至于陈抟,也许只是把太极图当成道教的标识物而已。
还有人认为太极图出于道教徒之手,是道教内丹学的产物。据说有人利用EF扫描技术,给进入气功功能态下的气功师作脑电图,并结合中医学和气功学有关记载,对气功师的脑电图进行了测试研究,发现大脑存在一个太极结构,以此证明太极图最早是人体气功功能态下内景感受(或内视)记录的丹象,也就是人体气功功能态下的脑电图。因此提出狭义与广义太极图之说,狭义的“太极图”(从它的原始起源的意义上说)是一张脑电图,广义的“太极图”(从它发现并描述了某种普遍的物质运动原理与结构的意义上说)是一种宇宙物质运动模型。也就是说,要想获得这种丹象——太极图,只有气功修炼达到出神入化的程度,否则就不可能获得。但是用什么来修炼呢,还得求助古人,丹家的经典《周易参同契》就说,修炼的理法依据仍然是《易经》的原理和《易经》的太极模式。也就是说,丹家内景感受(或内视)到的丹象,是在易理易法的指导下修炼出来的。无论是汉代的魏伯阳,还是以后的陈抟等道教徒,他们都得研习《易经》,不研究《易经》,就不能发现内景感受(或内视)到的丹象与伏羲八卦原理及图形相一致。
太极图产生以后,在流传的过程中,或配以八卦,或配以六十四卦,于是便陆续出现了“先天太极图”、“天地自然之图”、“河图太极图”、“洛书太极图”等各种不同名目的太极图。有人又据此得出结论:属于意义世界的太极图是以丹家内景感受(或内视)到的丹象为原形,以伏羲八卦方位为参照系,在《易经》原理的指导下画出来的。太极图产生以后,由于它具有与伏羲八卦方位图相同的宇宙意义,而其描述的简易性和生动性又容易为人们所接受,于是人们便用它来解说宇宙现象,从而使之具有普遍真理性和适用性。这种观点是否正确,留待专家去研究而后得出结论。但是有一点是可以肯定的,太极图的创造者,或者叫设计者,一定是根据大量的资料和研究,在大脑里产生了某种图形,然后逐步加以完善,也许这种完善,不是一个人、一个时间内完成的。
河图和洛书的创造,更带有一种神话的色彩。传说,在伏羲的时代,有龙马出于黄河,身上的花纹恰如八卦,于是,伏羲就取法于此,创造了八卦。又传说,在夏禹的时代,有神龟出于洛水,背上有文字,大禹取法于此,创造了洛书。这当然都是神话故事,不足为凭,但是,也有可取的地方,那就是,任何创造——包括一个伟大的艺术设计作品,都离不开客观实践。无论从哪一个学科、哪一个角度,用什么样的手段去研究易学象数的起源,这些象数自身都是一件伟大的艺术设计作品。它们给我们艺术家和设计师以深刻的启发,艺术创作的形象思维,离不开逻辑思维的指导;而理论创立的逻辑思维,在形象思维的表现下,将更加深刻。二者的结合,将是艺术创作的最高境界。