本帖最后由 lc_shanshui 于 2014-11-9 18:51 编辑
【篇外】
持续关注电子发烧友技术论坛已有一年多的时间了,之前一直是在看别人的帖子,没有自己去发过帖。俗话说得好,吃水不忘挖井人。现在自己也该为论坛做点事情了,记录下自己学习FPGA中的点滴,也算是对自己学习的一种激励和监督吧。好了,不多说了,下面就借着桂林的雨声开始我的脚印之旅~在这之前熟悉了Quartus II软件的使用,看过华为的Verilog HDL入门教程和夏宇闻的Verilog HDL数字设计与综合(第二版),对照着开发板进行了简单的代码调试,因此,现在对于开发环境和Verilog HDL语言有了一个简单的认识。进行上面的学习一共花了我将近两个月的时间,当然中间我还看过数据结构与算法分析,以及对自己课题相关论文进行了查阅和分析,最终确定了设计方案和阶段学习任务。总的来说,这个暑假还是有点收获的。
2014-09-13 早 桂林 阵雨
【回顾】
昨天,我开始看潘松编著的EDA技术与Verilog HDL,想把之前看的Verilog HDL在温习一遍,差缺不漏,目的是为了能设计基于FPGA的AD和DA转换程序。
【收获】
(一)组合逻辑电路的Verilog HDL描述
(1)case语句
- 一般用case语句表示顺序语句,进行仿顺序操作;
- 对真值表的描述一般也用case语句;
- 注意一般都要加上default语句;
- 表达式中的值必须在case下面列出的取值范围内,且数据类型必须匹配。
(2)always语句块和assign语句
- always语句为过程语句,assign语句为连续赋值语句;
- always语句块是顺序执行语句块,assign语句为并行语句;
- 一般有两个固定搭配:always块中使用reg型变量,assign语句中使用wire型变量;
- reg定义的寄存器型变量并非一定会在Verilog程序中映射出时序电路,定义reg型只是always块的需要,且input和inout信号不能定义成reg型,即reg只能定义always块中的output信号;
- assign语句中,同一目标变量名下不允许有多个不同赋值表达式,即不允许有不同的数据赋给同一个变量;
- assign语句后面一般只能接一条阻塞式赋值语句“=”;
- 等价写法:wire Y = a1 ^ a2;等价于wire a1, a2; assign Y = a1 ^ a2;
(3)阻塞式语句与非阻塞式语句
- 阻塞式赋值语句“=” —— 当执行某一语句时,其他语句不可能被同时执行。但对于assign语句,其综合表现却是并行特性。
- 非阻塞式赋值语句“<=” —— 必须在块语句执行结束时才整体完成赋值操作。但在begin_end顺序块中,所有非阻塞语句却可以并行执行。
- 提醒 —— 在同一过程中对于同一变量的赋值,阻塞式赋值和非阻塞式赋值不允许混合使用。
(4)Verilog程序的层次结构设计
- 值得借鉴的一种写法,assign {co, so} = a + b; // 两位二进制数直接相加,进位给并位操作后的co
- 例化就是引入一种连接关系,常采用端口名关联法(与位置顺序无关)和位置关联法。
【附件】
华为的Verilog HDL入门教程
夏宇闻的Verilog HDL数字设计与综合(第二版)
2014-09-14 午 桂林 多云
【回顾】
昨天接着看了时序电路的Verilog HDL描述、计数器的Verilog HDL设计以及Quartus II应用初步(包括:基本设计流程、引脚设置与硬件验证、嵌入式逻辑分析仪使用方法、编辑SignalTap II的触发信号和原理图输入设计方法),并且做了十六进制7段数码显示译码器设计的实验。
【收获】
(二)时序电路的Verilog HDL描述
(1)Verilog的敏感信号- Verilog的敏感信号分为两类,即边沿敏感型(使用关键词posedge下降沿和negedge上升沿)和电平敏感型。
- 特别注意,每一个过程语句中只能放置一种类型的敏感信号,不能混放。如,always @(posedge CLK or RST)就是一个错误写法。
- 敏感操作还要与敏感信号的定义相匹配。如,always @(posedge CLK or negedge RST) begin if(RST) ··· 中的if条件RST就是一种错误的表示,应该为:if(!RST)
(2)时序图的重要性
- 对于边沿触发型D触发器、电平触发型锁存器、含异步清0和时钟使能结构的D触发器、含同步清0结构的D触发器和含异步清0的锁存器的Verilog描述的理解,重点是对时序图的分析。
- 异步时序电路很少用到,因为其容易产生有害的冒险竞争,优化算法复杂,无法形成高速工作模块。
(3)在Quartus II中观察综合后得到的RTL图的方法
Tool --> Netlist Viewers --> RTL Viewer
(三)Quartus II应用初步(1)嵌入式逻辑分析仪的使用
- Quartus II中嵌入式逻辑分析仪SignalTap II Logic Analyzer,在Tool主菜单下。
- 特别注意,当利用SignalTap II将芯片中的信号全部测试结束后,完成产品开发前,不要忘了将SignalTap II的部件从芯片中除去。方法是Setting --> SignalTap II Logic Analyzer中取消选中Enable SignalTap II Logic Analyzer复选框,再编译、编程一次即可。
(2)十六进制7段数码显示译码器设计
- module decoder_7s(output reg [6:0] OUT,
- input [3:0] IN);
- always @(IN)
- begin
- case(IN)
- 4'b0000: OUT <= 7'b0111_111; // 0
- 4'b0001: OUT <= 7'b0000_110; // 1
- 4'b0010: OUT <= 7'b1011_011; // 2
- 4'b0011: OUT <= 7'b1001_111; // 3
- 4'b0100: OUT <= 7'b1100_110; // 4
- 4'b0101: OUT <= 7'b1101_101; // 5
- 4'b0110: OUT <= 7'b1111_101; // 6
- 4'b0111: OUT <= 7'b0000_111; // 7
- 4'b1000: OUT <= 7'b1111_111; // 8
- 4'b1001: OUT <= 7'b1101_111; // 9
- 4'b1010: OUT <= 7'b1110_111; // A
- 4'b1011: OUT <= 7'b1111_100; // B
- 4'b1100: OUT <= 7'b0111_001; // C
- 4'b1101: OUT <= 7'b1011_110; // D
- 4'b1110: OUT <= 7'b1111_001; // E
- 4'b1111: OUT <= 7'b1110_001; // F
- default: OUT <= 7'b0111_111; // 0
- endcase
- end
- endmodule
复制代码
- set_location_assignment PIN_69 -to IN[3]
- set_location_assignment PIN_68 -to IN[2]
- set_location_assignment PIN_67 -to IN[1]
- set_location_assignment PIN_66 -to IN[0]
- set_location_assignment PIN_50 -to OUT[6]
- set_location_assignment PIN_51 -to OUT[5]
- set_location_assignment PIN_52 -to OUT[4]
- set_location_assignment PIN_53 -to OUT[3]
- set_location_assignment PIN_54 -to OUT[2]
- set_location_assignment PIN_55 -to OUT[1]
- set_location_assignment PIN_58 -to OUT[0]
复制代码
- 对于已配置好引脚的Quartus II工程文件,提取TCL文件的方法
进入主菜单Project --> Generate Tcl File for Project··· ,保存TCL文件。注意,其中的 “ set_location_assignment PIN_69 -to IN[3] ” 形式的语句就是引脚的配置情况,且只保留这些形式的语句,其他配置语句全部删除,不然配置引脚会不成功。自己编写TCL文件时也可参考这种格式书写,便于导入到未配置引脚的Quartus II工程。
2014-11-9 下午 桂林 雨
【回顾】
说起来已有将近两月没有来电子发烧友论坛来续写自己的这个学习贴了,但是这期间我一直都没有放弃FPGA 的学习,因为太忙了,没有想起当初自己在这里的一点心愿(如题)。那么,下面我就来总结下,这两个月来我的收获和遇到的问题。
【收获】
自从上次看完潘松老师写的那本书之后,自己把里面的实验代码都烧写到自己的开发板中实验了验证之后,发现有如下几个地方需要注意:
(1)阻塞式赋值语句“=”和非阻塞式赋值语句“<=”在always语句块中的应用
之前看到一些参考书上说always语句块中只能使用非阻塞式赋值语句“<=”,其实这个说法并不是绝对的。阻塞式赋值语句“=”同样可以在always语句块中使用,并且二者使用要根据具体的环境来使用。可以参考潘松老师的《EDA技术与Verilog HDL》6.1节
其实,就我的理解,“=”语句和“<=”语句的区别是:前者是立即更新左边的值,而后者是依据时钟沿延时更新左边的值。
(2)不完整的条件语句(if...else)在综合时,往往会配置一个锁存器来保存原值,可能会造成逻辑资源的浪费、降低电路的工作速度、影响电路的可靠性,甚至导致系统根本无法工作。因此,我们在设计的时候应尽量避免不完整条件语句的出现。
(3)双向端口inout设计
首先,注意双向端口在完成输入功能时,必须使原来呈输出模式的端口呈高组态,否则,外部输入的数据会与端口原有电平发生“线与”,导致无法从外部正确读入数据。
- module bi4b (TRI_PORT, DOUT, DIN, ENA, CTRL);
- inout TRI_PORT;
- input DIN, ENA, CTRL;
- output DOUT;
- assign TRI_PORT = ENA ? DIN : 1'bz;
- assign DOUT = TRI_PORT | CTRL;
- endmodule
复制代码
(4)分频电路设计
—— 同步加载分频电路设计
- module fdiv0 (clk, pm, d, dout, rst_n);
- (* chip_pin = "11" *) output pm;
- (* chip_pin = "43, 44, 46, 32" *) output [3:0]dout;
- (* chip_pin = "91" *) input clk;
- (* chip_pin = "69" *) input rst_n;
- (* chip_pin = "105, 104, 103, 101" *) input [3:0]d;
- reg [3:0] q1;
- reg full;
- (* synthesis, probe_port, keep *) wire ld;
- always @(posedge clk, negedge rst_n) begin
- if(!rst_n) begin q1 <= 0; full <= 0; end
- else if(ld) begin q1 <= d; full <= 1; end
- else begin q1 <= q1 + 1; full <= 0; end
- end
- assign ld = (q1 == 4'b0000);
- assign pm = full;
- assign dout = q1;
- endmodule
复制代码
——异步加载分频电路设计
- module fdiv1 (clk, pm, d, dout, rst_n );
- (* chip_pin = "11" *) output pm;
- (* chip_pin = "43, 44, 46, 32" *) output [3:0]dout;
- (* chip_pin = "91" *) input clk;
- (* chip_pin = "69" *) input rst_n;
- (* chip_pin = "105, 104, 103, 101" *) input [3:0]d;
- reg [3:0] q1;
- reg full;
- (* synthesis, probe_port, keep *) wire ld;
- always @(posedge clk, negedge rst_n, posedge ld ) begin
- if(!rst_n) begin q1 <= 0; full <= 0; end
- else if(ld) begin q1 <= d; full <= 1; end
- else begin q1 <= q1 + 1; full <= 0; end
- end
- assign ld = (q1 == 4'b0000);
- assign pm = full;
- assign dout = q1;
- endmodule
复制代码
——异步清0分频电路设计
- module fdiv2 (pm, clk, d);
- (* chip_pin = "11" *) output pm;
- (* chip_pin = "91" *) input clk;
- (* chip_pin = "105, 104, 103, 101" *) input [3:0] d;
- (* synthesis, probe_port, keep *) reg [3:0] q1;
- reg full;
- (* synthesis, probe_port, keep *) wire rst_n;
- always @(posedge clk, posedge rst_n ) begin
- if(rst_n) begin q1 <= 0; full <= 1; end
- else begin q1 <= q1 + 1; full <= 0; end
- end
- assign rst_n = (q1 == d);
- assign pm = full;
- endmodule
复制代码
——同步清0分频电路设计
- module fdiv3 (pm, clk, d);
- (* chip_pin = "11" *) output pm;
-
- (* chip_pin = "91" *) input clk;
- (* chip_pin = "105, 104, 103, 101" *) input [3:0] d;
- (* synthesis, probe_port, keep *) reg [3:0] q1;
- reg full;
- (* synthesis, probe_port, keep *) wire rst_n;
- always @(posedge clk) begin
- if(rst_n) begin q1 <= 0; full <= 1; end
- else begin q1 <= q1 + 1; full <= 0; end
- end
- assign rst_n = (q1 == d);
- assign pm = full;
- endmodule
复制代码
——半整数与奇数分频器电路设计
- // 占空比为50%的任意奇数次5分频电路
- module fdiv4 (clk, k_or, k1, k2);
- input clk;
- output k_or, k1, k2;
- reg [2:0] c1, c2;
- reg m1, m2;
- always @(posedge clk) begin
- if(c1==4) c1 <= 0;
- else c1 <= c1 + 1;
- if(c1==1) m1 <= ~m1;
- else if(c1==3) m1 = ~m1;
- end
- always @(posedge clk) begin
- if(c2==4) c2 <= 0;
- else c2 <= c2 + 1;
- if(c2==1) m2 <= ~m2;
- else if(c2==3) m2 = ~m2;
- end
- assign k1 = m1;
- assign k2 = m2;
- assign k_or = m1 | m2;
- endmodule
复制代码
【附件】
《SOPC技术实用教程》 - 潘松.pdf
《深入浅出玩转FPGA》 - 吴厚航【网名:特权同学】.pdf
未完待续......
8
|
|
|
|
正打算学FPGA,不知道从何下手,没有信心啊。我看看先
|
|
|
|
|
谢谢分享了。
|
|
|
|
|