FPGA入门到实战-学习笔记

ref:腾讯教育
FPGA入门到实战-录播课-上海V3学院
https://ke.qq.com/course/66019
老师:尤恺元
第1课 掌握Verilog HDL的高级编码知识
授课日期:
老师以DQ触发器实例:

//声明模块时,输入模块一定是wire变量
clr 没有同步到 sclk,所以是异步复位,以后老师再举一个同步复位的例子。
1'b0 含义: 1是1bit b代表二进制,如果是d表示十进制,h表示十六进制
再例如:
2'b01 2bit的二进制01
8'b0000_0101 8bit的二进制,可以用下划线分割


ex_module.v
module ex_module(
input wire sclk, //系统时钟常见名字sys_clk system_clock
input wire rst_n, //n表示低复位,异步D触发器
input wire [7:0] d,//模块声明的时候,输入必须是wire变量
output reg [7:0] q// 模块声明的时候,输出可以是wire变量也可以是reg
);

always @(posedge sclk or negedge rst_n)//敏感列表,可以包括电平触发,也可以是沿触发
if(rst_n == 1'b0)//双等号声明一个比较器,条件表,这里是组合逻辑
q <= 8'h00;// 沿触发的逻辑一定要用 <= 分阻塞赋值
else
q <= d;

/*
//如果是同步清零的,always块应写为下面的格式
always @(posedge sclk)
if(rst_n == 1'b0)
q<= 8'h00;
else
q<=d;
*/
endmodule
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
数据选择器,wire操作例子
//刚才的always 赋值 用来对 reg 赋值
//assign 连续赋值,对wire赋值
ex_wire.v
module(
input wire sel;
input wire a,
input wire b,
output wire c
);
//wire变量一定要用assign 连续赋值语句赋值,
//而且必须用阻塞赋值
//assign c=(条件) ? a:b;
assign c=(sel == 1'b1 ) ? a:b;

/*
上面语句同等于
if(sel == 1)
c = a;
else
c=b;
*/
endmodule

本课程不讲时序约束

FPGA百分之四十 用来做IC验证
其它的都是直接工程设计

ARM做全局控制
DSP处理纳秒级别的工作,有些吃力
FPGA接口相对也多一些,例如PCIE

alter的MAX10,内部集成了FLASH,配置模式分为AS和JTAG
消费类电子,一般不适合FPGA,百万级以上,考虑成本

EPCS就是16M的FLASH,支持了alter的一些标准。
FLASH,推荐了一些,例如华邦的。
除了赛灵思和alter,还有国内的京维雅格

GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
计数器

ex_cnt.v
module ex_cnt(
input wire sclk,
input wire rst_n,
output wire [9:0] cnt
);
reg [7:0] cnt_r;
always@(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
cnt_r <= 10'b0;//1023 + 1 = 1024 = 0x400
else
cnt_r <= cnt_r + 1'b1;
endmodule

verilog可以用仿真工具进行验证
//仿真工具用modelsim
下载链接 http://pan.baidu.com/s/1qW5IhhM 密码:n28z
建立sim模块(tb),描述测试激励如何产生,不能综合为电路
design 要例化到tb里
ggggggggggg

tb_ex_cnt.v
//esc 按键下面的那个键
//100ps 表示的是延时时间的精度
`timescale 1ns/100ps//单位时标声明
//#代表延时的开始,例如 #10.1 代表延时1ns
//#如果是#10.11由于延时精度是100ps,所以被忽略成了 #10.1

module tb_ex_cnt;//声明激励模块不需要端口列表
reg tb_sclk,tb_rst_n;//激励信号的声明
wire [9:0] tb_cnt;//原始模块输出信号连接线线的声明
initial//initial模块只执行1次
begin//initial 块只能对寄存器变量赋值
//这里是顺序执行的
//这里写阻塞赋值或者非阻塞赋值都是可以的
tb_sclk <= 0;
tb_rst_n <= 0;
//上面两句话是有先后执行顺序的,但是延时是0
#200.1
tb_rst_n <= 1;
//以上语句产生的复位信号的波形




end
//产生时钟
always #10 tb_sclk <= ~tb_sclk;//循环震荡周期为20ns
//把激励信号与被测试模块连接起来
//例化的方法,原始模块的名字 空格例化的名字(可以自定义的)
//ex_cnt_inst是例化的名字
//点后面的名字是原始模块的名字,括号里面是激励信号
ex_cnt ex_cnt_inst(
.sclk (tb_sclk),//模拟晶振产生时钟震荡信号
.rst_n (tb_rst_n),//模拟外部复位电平testbench
.cnt (tb_cnt)//例化模块的时候,如果原始模块是输出信号,那么括号内必须是wire类型
);
endmodule

gggggggggggggggggggggg
下面讲用modelsim软件进行仿真
File->Project..
新建工程,工程名为ex_cnt
放到工程目录sim文件夹下。
把上面的两个.v文件加入到工程。
点compile all
启动仿真
如果不想显示路径
Tools---> Display --->Display Signal Path 由0改成1

可能是版本的原因,我的和老师的菜单不一样
运行100ns

发现有一些问题,cnt一直是高阻态
第3课 FPGA入门到实战 Verilog 2
授课日期:2015年4月25日
task与 case 可综合的语句
左边是多级选择器,是if else的电路
而右边是case 译码器电路,实现的原理是LUT(look out table)即查找表
case比if else 效率高很多
查找表的电路

module ex_case(
input wire rst_n,
input wire sclk,
output reg o_dv,
output reg [7:0] o_data
);
reg[2:0] cnt_7;
//不同功能的寄存器分开always块来写,这样代码可维护性强
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b 0)
cnt_7 <= 3'd0;
else
cnt_7 <= cnt_7 + 1;


//case 语句也是并行的语句
//case 在电路里面对应的是译码器,比if else 要快很多
//if else 对应的是多级数据选择器,选择器一级1ns,两级就会乘以2
//case 语句必须要写default
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
o_data <= 8'd0;
o_dv <= 1'b0;//输出使能
else begin
case(cnt_7)
3'd0:begin
o_data <= 3'd7;//当cnt_7 等于3’d0时,执行此语句
o_dv <= 1'b1;
end
3'd1:begin
o_data <= 3'd0;
o_dv <= 1'b0;//这时候输出又是无效的了
end
3'd2:begin
o_data <= 3'd5;
o_dv <= 1'b1;
end
default:begin
o_data <= 3'b0;
o_dv <= 1'b0;
end
endcase
end
endmodule

如果要即可发生的组合逻辑,那怎么写呢?


//如果是组合逻辑,则用下面的
//敏感列表一定要完整,否则会生成锁存器
//锁存器对我们的危害是相当大的。
//因为锁存器的时间是不固定的。
//这在整个产品里面就是个潜藏的炸弹。
//消除锁存器的方法
//1.要把敏感列表写完整,case 条件,赋值语句右端的变量
//2.把所有条件分支写全。
//用Quarters13.1综合一下,产生个锁存器看看
always @(cnt_7)
case(cnt_7)
3'd0:begin
o_data <= 3'd7;//当cnt_7 等于3’d0时,执行此语句
o_dv <= 1'b1;
end
3'd1:begin
o_data <= 3'd0;
o_dv <= 1'b0;//这时候输出又是无效的了
end
3'd2:begin
o_data <= 3'd5;
o_dv <= 1'b1;
end
default:begin
o_data <= 3'b0;
o_dv <= 1'b0;
end
endcase
55分钟
wire 和reg 的具体区别
wire就是连线。
FPGA:应用领域
做接口
1.PCIE,spi
2.数据采集、存储,摄像头
3.10G,百G的以太网
4.路边大屏

算法方面:
中兴,海思
集成
工控,电机,车床
FPGA
也用于做芯片验证。主要是功能验证,但是不是时序验证。

posedge negedge 一般只用于时钟,时钟线是金线,成本高,性能好,延时小,
数据线,是铜线,如果用posedge可能出现时序违例

ggggggggggggggggggggggggggggg

下面编写激励
在sim文件夹里
建立文件, tb_ex_case.v

`timescale 1ns/1ns

module tb_ex_case;
reg sclk,rst_n;
//例化的时候输出只能接wire变量
wire[7:0] data;
wire dv;
reg [7:0] i_addr;
reg [9:0] i_data;

initial begin
sclk =0;
rst_n = 0;
#200
rst_n =1;
end

initial begin
#500
send_data(255);
end


always #10 sclk <= ~sclk;
ex_case ex_case_inst(
.rst_n(rst_n),
.sclk(sclk),
.o_dv(dv),
.o_data(data),
.i_data(i_data),
.i_addr(i_addr)
);

task send_data(len);//任务的名称,过程描述
integer len,i;//变量声明区
begin
for(i = 0;i<=len;i=i+1)begin
@(posedge sclk);
i_addr <= i[7:0];
i_data <= i[7:0];
end
i_addr <= 0;
i_data <= 0;
end
endtask
endmodule


//用case语句产生一个协议, 当地址为0是,i_data = 0xff;
//当地址为1时,i_data = 0x55;
//2时, i_data = 0;
//其它地址全部赋值为 0xff
//采用这种写法, 总是被下个周期赋值
always @(posedge sclk)
case(i_addr)
8'd0:begin
i_data <= 8'hff;
end
8'd1:begin
i_data <= 8'h55;
end
8'd2:begin
i_data <= 8'h0;
end
default:begin
i_data <= 8'hff;
end
endcase



for循环一定要加一个posedge按节拍来做

在RAM中,不要用case,用reg
什么时候用case
例如单片机和ARM通信,过来了地址,可以用CASE

门级描述,基本用不到
数据流级,基本不用,也可能用到
行为级描述,刚才用到的就是。常用

乘法除法必须要用ip核,不能直接写。
老师:尤恺元

数字电路很重要,给任意数字电路,能用Verilog描述,写出来的代码质量就非常高。
模电对开发FPGA前期基本不用。

在编解码和调制解调的时候, 数学知识才最重要。

FPGA分为逻辑工程师和硬件工程师(指的是做PCB)。
DSP 主要用于数字信号处理。
本科毕业,平均薪资6000(授课日期是)
研究生,女,南京 9.7K ,某某,深圳,8.9K
研究生也就多个一两千。迎接毕业生

至芯也还是可以的。

第4课 FPGA入门到实战 Verilog 3
授课日期 :2015.4.26 19点
同步有限状态机的设计
FSM







ex_fsm.v
module ex_fsm(
input wire sclk,
input wire rst_n,
output reg k1,
output reg k2,
input wire A
);
parameter IDLE = 4'b0001;
parameter START = 4'b0010;
parameter STOP = 4'b0100;
parameter CLEAR = 4'b1000;
// parameter

//第一段描述状态机
always @(posedge sclk or negedge rst_n)
if(rst_n==1'b0)
state<=IDLE;
else
//case语句描述状态机再合适不过了
case(state)
IDLE:if(A==1'b1)//这里是个选择器
state <= START;
else
state <= state;
START:if(A==1'b0)
state <= STOP;
STOP:if(A == 1'b1)
state <= IDLE;
default: state <= IDLE;
endcase


reg[3:0] state;//表示四种状态
//2'b00 2'b01 2'b10 2'b11
//二进制编码用的寄存器数量少,但是用的组合逻辑资源较多
//所以不能泛泛的说用的位资源少,整体资源就少

//4'b0001 4'b0010 4'b0100 4'b1000
//独热码,占用寄存器数量多,但是组合逻辑资源较少
//所以我们用独热码。

//由于布线原因,多个为变量不同步的到达比较器,就会产生不同步状态,会有中间状态
//所以独热码,能跑高速,建立时间保持时间都不需要,只是这一根线而已。
//还有以一中码是格雷码,异步fifo用。
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
k1 <= 1'b0;
else if(state == IDLE && A=1'b1)
K1<= 1'b0;
else if(state == CLEAR && A==1'b1)
k1<=1'b1
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
k2 <= 1'b0;
else if(state == STOP && A ===1'b1)
K2 <= 1'b1;
else if(state == CLEAR && A== 1'b0)
K2 <= 1'b0;
endmodule

tb_ex_fsm.v
`timescale 1ns/1ns
module tb_ex_fsm;
reg sclk,rst_n;
wire k1,k2;
reg in_A;
initial begin
sclk <= 0;
rst_n <= 0;
#100;
rst_n <= 1;
end
initial begin
#200;
in_data();
end

always #10 sclk <= ~sclk;
ex_fsm ex_fsm_inst(
.sclk(sclk),
.rst_n(rst_n),
.k1(k1),
.k2(k2),
.A(in_A)
);
task in_data();
integer i;
begin
for(i=0;i<1024;i=i+1)
begin
@(posedge sclk);
if(i<50)
in_A <= 0;
else if(i<200)
in_A <= 1;
else if(i<700)
in_A <= 0;
else if(i<800)
in_A <= 1;
else if(i<800)
in_A <= 0;
end
end
endtask
endmodule
//初期学习可以不用开发板。
ggggggggggggggggggggggggggggggg
之后老师用Modsim进行了仿真测试,后来用QuartusII进行了综合
观查状态机对应的硬件电路




你可能感兴趣的:(FPGA入门到实战-学习笔记)