标签搜索

verilog学习笔记

lishengxie
2023-01-27 / 0 评论 / 43 阅读 / 正在检测是否收录...

参考书籍:

《手把手教你学FPGA设计:基于大道至简的至简设计法》

百度网盘链接:https://pan.baidu.com/s/12knuxzb4Z6z_8gR-By-l-A
提取码:mwzd

自己实现的书中的模块和相应的testbench测试:https://github.com/lishengxie/verilog-learning.git

计数器

设计规则

  1. 计数器需要考虑三要素:初值、加一条件和结束值(通常依次考虑);
  2. 计数初值必须为0;
  3. 使用某个计数值时必须同时满足加1条件;例如加1条件为add_cntadd_cnt && cnt==4时表示计数到第五个,而add_cnt==0 && cnt==4不表示计数到第五个;
  4. 计数条件必须同时满足加一条件,且结束值必须是x-1的形式;
  5. 当从计数器取某个数时,assign形式必须为:(加一条件) && (cnt==计数值-1)
  6. 结束后计数值需要回到0;
  7. 需要限定范围时,推荐使用>=<两种符号,尽量不要使用大于或者小于等于两种符号;
  8. 计数器设计时,先写计数器的always段,条件用名字代替,随后使用assign语句依次写出加一条件和结束条件;由此可以得出计数器的模板写法如下所示
// 中文词语方便理解,实际使用需要更改为相应的变量名
always @(posedge clk or negedge rst_n) begin
    if(rst_n==1'b0)begin
        cnt <= 0;
    end 
    else if(加一条件)begin
        if(结束条件)
            cnt <= 0;
        else
            cnt <= cnt + 1;
    end
end
assign 加一条件 = xxxxxx;
assign 结束条件 = (加一条件) && (cnt==计数值-1);
  1. 加一条件必须与计数器严格对齐,其他信号一律向计数器对齐;例如,现在需要输出两个信号dout0dout1dout0在计数到6时拉高,dout1在计数到7时拉高,因此dout0变1的条件为add_cnt && cnt==6-1dout1变1的条件有两种写法

    • dout0 == 1
    • add_cnt && cnt==7-1


    第一种写法是间接向计数器对齐,是非常不好的方法,建议使用第二种直接向计数器对齐;

  2. 加一条件统一前缀为add_,结束条件统一前缀为end_
  3. 暂不使用减1计数器。

状态机

设计规则

  1. 使用四段式写法
    第一段为同步时序的always模块,用于格式化描述次态迁移到现态寄存器;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end

第二段为组合逻辑的always块,用于描述状态转移条件判断,以三个状态的状态机IDLE->S1->S2->IDLE为例;

always @(*) begin
    case(state_c)
        IDLE: begin
            if(idle2s1_start) begin
                state_n = S1;
            end
            else begin
                state_n = state_c;
            end
        end
        S1: begin
            if(s12s2_start) begin
                state_n = S2;
            end
            else begin
                state_n = state_c;
            end
        end
        S2: begin
            if(s22_idle_start) begin
                state_n = S2;
            end
            else begin
                state_n = state_c;
            end
        end
        default: begin
            state_n = IDLE;
        end
    endcase
end

第三段定义转移条件,注意条件一定要加上现态。

assign idle2s1_start = state_c == IDLE && xxxx;
assign s12s2_start = state_c == S1 && xxxx;
assign s22idle_start = state_c == S2 && xxxx;

第四段设计输出信号,每一个输出信号使用一个always块

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        out1 <= 1'b0
    end
    else if(state_c==S1)begin
        out <= 1'b1;
    end
    else begin
        out <= 1'b0;
    end
end
  1. 四段式状态机第一段写法可以保持不变;
  2. 第二段中的状态转移条件用信号名表示,无需写出具体的转移条件;
  3. 用assign形式将状态转移条件写成xx2xx_start的形式;
  4. 状态转移条件,用assign产生变化条件时必须加上当前状态;
  5. 状态保持不变使用state_n = state_c,因为如果在组合逻辑中使用state_n = state_n,只有锁存器才能有保持电路,而锁存器在数字电路中通常是不希望出现的。

FIFO

设计规则

  1. 使用Show-ahead模式。FIFO有两种使用模式,分别是Normal和Show-ahead模式,其中Normal模式指先有读使能,之后FIFO才输出这个数据;而Show-ahead模式指FIFO先输出数据,遇到读使能后FIFO更新输出数据。两种模式只有读数据时存在区别,使用Show-ahead模式的好处在于读请求信号读数据同时有效,可以当做有效数据使用
  2. 读、写隔离,读控制和写控制是相互独立的,相互之间除了用FIFO交流信息外,不能有任何信息传递。
  3. 读使能必须判断空状态,并且用组合逻辑产生。原因在于使用Show-ahead模式当FIFO为空时,如果使用时序逻辑产生读使能,会出现在FIFO为空的情况下读数据的操作,读操作会出错。
  4. 处理报文时将指示信号和数据一起存入FIFO,这样做的好处是可以将报文数据、报文头、报文尾的指示信号和数据一起原封不动地送入下游模块。
  5. 读写时钟不同时,必须使用异步FIFO。

VScode verilog使用笔记

编写&添加Verilog代码段

  1. 编写代码段

* 顶部菜单栏 文件(File) -> 首选项(Preference) -> 用户代码段(User Snippets)
* 选择verilog.json打开,添加代码段模板,以编写的计数器模板为例,如下所示
counter snippet
2. 插入代码段
Ctrl+Shift+P进入命令输入,输入Insert Snippet命令选择对应的代码段插入。

数字电路相关

三态门电路/inout端口

三态门电路
- 当sio_out_en=0 时,此时sio_d作为输出口,sio_d输出sio_out的值;
- 当sio_out_en=1 时,此时sio_d作为输入口,sio_din输出sio_d的输入值;

inout_sio_d;
assign sio_d = sio_out_en ? Sio_out : 1'bz;
assign sio_din = sio_d;
0

评论 (0)

取消