FPGA学习笔记

个人学习笔记 侵权联删

任何数与1   与是本身
与0   与是0
、
任何数与1  或是1
与0或   是本身

组合逻辑定义  wire 
时序逻辑定义   reg     有个信号特例也用reg  没听清是什么

if判断,如果if后面只有一条语句,可以不加begin  end  ,如果有多条语句,要加begin  end

如果是在always里面赋值,那么需要写reg   如果是在assign里面赋值,,就可以不写reg
例如  outout  reg  [3:0]led;   在always里面赋值

DFF是D触发器,为边沿敏感,latch是锁存器,为电平敏感。

变量的赋值都是在时钟上升沿进行的  ,复位一般是高电平,所以在下降沿复位,复位之后是低电平,例如
不指定端口数据类型的话默认是wire型的
输入可以是reg或者wire型,输出必是wire型


//抓取上升沿代码固定写法
reg        uart_en_d0; 
reg        uart_en_d1;  
wire      en_flag;
//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;

//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_d0 <= 1'b0;                                  
        uart_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_d0 <= uart_en;                               
        uart_en_d1 <= uart_en_d0;                            
    end
end


//抓取下降沿固定写法,只是把取反符号换了下位置
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
wire       start_flag;
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end


//并行转串行
//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end

//串行转并行
//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)                            //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end


MODISM仿真
输入信号一般是reg型    输出信号一般是wire型
复位是低电平有效 
停止位是高电平
锁相环默认高电平复位,低电平正常工作

ip核
1.ROM
输出端口寄存器存在的话,输出数据比地址数据晚两个时钟即第0个时钟输入地址,在第二个时钟周期输出数据,不存在的话晚一个时钟,即第0个时钟输入地址,第1个时钟输出数据
2.FIFO
同步FIFO输入与输出数据位宽相等
异步FIFO输入与输出数据位宽不等


//wr_full是在wr_clk时钟下产生的,需要时钟同步下到rd_clk
always@(posedge rd_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
begin
wr_full_reg0<=1'b0;
wr_full_reg1<=1'b0;
end
else begin
wr_full_reg0<=wr_full;
wr_full_reg1<=wr_full_reg0;
end
end


always@(posedge rd_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rd_req<=1'b0;
else if(wr_full_reg1==1'b1)
rd_req<=1'b1;
else if(rd_empty==1'b1)
re_req<=1'b0;
end

好的博客:
1.=是用在always@(*)块和assign语句中写组合逻辑电路的。<=只用在always@(posedge clk)块中用来写寄存器。always@(*)和assign之间没啥区别,都生成组合逻辑电路。只是有时组合逻辑比较复杂,用assign语句一句话写不完时会用always@(*)。区别就是always@(*)块中被赋值的信号要被定义成reg,而assign中被赋值的信号则必须是wire,但它们却都是生成组合逻辑电路。这就是Verilog一点不严谨的地方。不过这也没啥大问题,就是容易把初学者搞糊涂。有人喜欢把组合电路和时序电路在代码中分开来写,比如在always@(*)中写NextState = 一堆组合逻辑,然后再在always@(posedge clk)中只写 State <=NextState。不过我嫌这样写罗索,所以在我写的代码中就只会出现always@(posedge clk) 和assign。 作者:無限次元 https://www.bilibili.com/read/cv13109706 出处:bilibili
2.右移两位相当于处以4
去掉一位相当于处以2
移位两次相当于延迟三个时钟周期,如下面代码所示 
//------------------------------------------
//lag 3 clocks signal sync  
reg	[2:0]	per_frame_vsync_r;
reg	[2:0]	per_frame_href_r;	
reg	[2:0]	per_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		per_frame_vsync_r <= 0;
		per_frame_href_r <= 0;
		per_frame_clken_r <= 0;
		end
	else
		begin
		per_frame_vsync_r 	<= 	{per_frame_vsync_r[1:0], 	per_frame_vsync};
		per_frame_href_r 	<= 	{per_frame_href_r[1:0], 	per_frame_href};
		per_frame_clken_r 	<= 	{per_frame_clken_r[1:0], 	per_frame_clken};
		end
end
assign	post_frame_vsync 	= 	per_frame_vsync_r[2];
assign	post_frame_href 	= 	per_frame_href_r[2];
assign	post_frame_clken 	= 	per_frame_clken_r[2];
偶数分频的分频系数N,通过时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,以此循环下去,此处使用50分频,于是反转条件为50/2-1=24 得到1MHZ时钟
3.多条assign语句并行执行
阻塞赋值与非阻塞赋值
非阻塞赋值
a=1,b=2,c=3
 
begin
 
    a<=b+1;
 
    b<=a+1;
 
    c<=a-1;
 
    end
 
计算结果为:a=3,b=2,c=0

阻塞赋值
begin
 
        a=b+1;
 
        b=a+1;
 
        c=a+1;
 
end
在上述代码中先执行b+1赋值给a后再执行a+1赋值给b以此类推


4.输入信号不用赋初值,包括有位宽的信号,输出信号需要在复位处赋初值

脉冲同步器的基本原理:

将src_clk时钟域的输入脉冲转换为src_clk时钟域的电平信号src_state;
对src_state电平信号进行打拍(打两拍)同步到dst_clk时钟域;
对dst_clk时钟域的电平信号进行检测,产生dst_clk时钟域脉冲;
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值