Lishengxie
  • Posts
  • About
  • Contact
  1. Home
  2. Posts
  3. Verilog Note

Verilog Note

Apr 30, 2023 verilog Lishengxie

参考书籍:

《手把手教你学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_cnt且add_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. 加一条件必须与计数器严格对齐,其他信号一律向计数器对齐;例如,现在需要输出两个信号dout0和dout1,dout0在计数到6时拉高,dout1在计数到7时拉高,因此dout0变1的条件为add_cnt && cnt==6-1,dout1变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
  1. 插入代码段 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;

Table of Contents

    • 参考书籍:
    • 计数器
    • 状态机
    • FIFO
    • VScode verilog使用笔记
    • 数字电路相关

Recent Posts

  • 分布式ID生成方案全解析:从数据库到雪花算法 Jun 25, 2026
  • Let's Encrypt 免费申请 SSL 证书,并实现自动续期 Sep 14, 2025
  • Redis ziplist、quicklist 和 listpack Mar 3, 2025
  • Nginx禁止使用IP直接访问服务器上相应端口 May 11, 2024
  • LeetCode刷题 - KMP算法 Feb 4, 2024

Categories

  • Linux7
  • 算法学习7
  • 论文笔记6
  • C++4
  • 未分类3
  • Go学习2
  • Redis1
  • SystemC1
  • Verilog1

Tags

← Gin框架学习 Snn & NoC 仿真器收集 →
皖ICP备2023003716号-1 | 公安备案皖公网安备34012202341113 | 违法和不良信息举报邮箱:1141751053@qq.com
Powered by Hugo & Explore Theme.