前言
不知道先写什么,先写写代码规范吧。找资料的时候找到了一个专门讲Verilog代码规划的,转载复述一下,好像CSDN没用verilog的关键词高亮,我就统一用python的了。链接如下:Verilog编码风格
从哲学的角度出发(我猜的),任何语言都要求追“信达雅”,信指译文内容准确,达指的结构清晰,雅指富有文采。所以编写代码也要追求功能准确实现,结构清晰,可读性好。
编码风格
1、关于命名(信)
本铲屎官目前写的代码体量都不是很大,所以还没遇到很长的命名。
据悉信号变量模块一定要使用有意义的名字,不然
reg [7:0]a;
reg [7:0]b; //a和b当时写的时候还记得,过了几天,a是啥??!
链接推荐了两种书写方法,不过我更喜欢我自动的第三种,好像首字母大写更好看一点
reg DataToDestinationClock ;
reg data_to_destination_clock ; //推荐
reg Data_to_Destination_Clock; //首字母大写
一些十分常用的信号线采用独特的命名方法,还有很多就不一一举例了
wire clk; //clk代替clock
wire rst; //rst代替reset
reg clk4test; //4代替for,原为clk_for_test
wire clk_en; //clock_enable
wire wdata; //write_data
建议一般功能模块的名称、端口、信号变量等全部使用小写(感觉我第三种写法也行)
parameter DW = 8;
reg [DW-1:0] wdata;
寄存器变量一般加后缀 _r ,延时打拍的变量加后缀 _r1、_r2
reg indata_r;
reg indata_r1,indata_r2;
always@(posedge clk or negedge rst_n)begin
indata_r1 <= indata_r;
indata_r2 <= indata_r1; //打两拍实现同步并且减少冒险出现的概率
end
还有的就是 _d 可以表示延迟后的信号,_t 可以表示暂时存储的信号,_n 可以表示低有效的信号,_s 可以表示 slave 信号,_m 可以表示 master 信号等
2、关于注释
注释可好用了,我第一次知道注释居然可以用来画波形,而且还可以画综合后的电路,把相关的时序描述写在注释里面就不用去查找功能文档了
// clk ________/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄\_/ ̄\____________ //时钟信号
// rst_n _____/ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ //复位信号
设计模块开头,应该包含文件说明信息,包括版权、模块名字、作者、日期、梗概、修改记录等信息。(下面的代码从链接直接抄过来了)
/**********************************************************
// Copyright 1891.06.02-2017.07.14
// Contact with willrious@sina.com
================ runoob.v ======================
>> Author : willrious
>> Date : 1995.09.07
>> Description : Welcome
>> note : (1)To
>> : (2)My
>> V180121 : World.
************************************************************/
对于信号线和寄存器需要注明其用途,注释很短直接写在代码后面,若注释过长则写在前面
//输出位宽小于输入位宽,求取缩小的倍数及对应的位数
parameter SHRINK = DWI/DWO ;
reg [AWI-1:0] ADDR_WR ; //写地址
3、关于优化(达)
这里的优化所指的不是在算法层面对功能模块进行优化,而是通过添加括号的形式使模块更有结构感,更具有可读性。
assign F = A + B + C + D; //这种写法会被综合成三个加法器
//这种写法也会被综合成三个加法器,但是A与B相加的和与C与D相加的和进行相加
assign F = (A + B) + (C + D);
//不推荐,结构不够清晰
assign flag = cnt == 4'd2 && mode == 2'b01;
//推荐
assign flag = (cnt == 4'd2) && (mode == 2'b01);
(下面内容直接复制了,已经说的很好了)
条件语句尽量使用 case 语句代替 if 语句。当同级别的条件判断语句过多时,使用 case 语句综合后的硬件结构,往往比 if 语句消耗更少的资源,拥有更好的时序。
状态机编写时,尽量使用 3 段式,以保证代码具有良好的整洁性和安全性。
系统设计时,尽量采用模块按功能分割、然后进行模块例化的方法。相比成千上万行代码都集成在一个文件中,模块分割有利于团队设计,便于更新维护。
4、关于美观(雅)
美观是在功能正确实现的基础上怎么写的有层次感,让人赏心悦目,这个和写作文一样,哪怕是同样的内容,写字好看的总会比写字不好看的多一点分
端口信号保证每行一个信号,逗号紧跟在端口声明之后
module rs_code(input clk,input rst_n,input data_in,output data_out); //写法不推荐
//推荐写法
module rs_code(
input clk,
input rst_n,
input data_in,
output data_out
);
尽量使用 begin + end 的方式保证执行语句间的层叠关系。begin 与关键字同行,end 另起一行。
例如,always 语句块使用时,或条件语句只有一条执行语句时,都可以省略 begin + end 关键字。但为保证结构的完整性,以及后续代码的调试与修改,还是建议加入此类关键字。
always @(posedge dout_clk or negedge rstn) begin
if (!rstn) begin
dout_en_r <= 1'b0 ;
end
else begin
dout_en_r <= rd_en_wir ;
end
end
模块例化时,端口信号尽量与连接信号隔开,并各自对齐。连接信号为向量时指明其位宽,方便阅读、调试。
ram u_ram(
.CLK_WR (clk),
.WR_EN (wren), //写满时禁止写
.ADDR_WR (addr),
.D (wdata[9:0]),
.Q (rdata[31:0])
);