今天在看正点原子的ZYNQ PL端控制EEPROM读写时,找到之前写的i2c读写控制模块想对比着来学习,结果那个代码风格惨不忍睹,一度怀疑真的是自己写的吗?痛定思痛决定规范自己的代码风格,不管是后续的团队合作和代码复用都有很多好处。
这是规格化之前的,只是一部分,在这里插入代码片
因为最开始惨不忍睹的代码已经被我修改过了,这里只是还原。
module i2c_ctrl
#(
parameter FPGA_clk = 26'd50_000_000,
parameter I2C_clk = 18'd250_000
)(
input sys_clk,//系统时钟,会分频
input rst_n,
input [7:0]slave_addr,//器件地址,不设为常量是考虑多从机情况
input [7:0]write_data,//写数据
input [15:0]word_addr,//字地址 高8位可以无效
input w_en,//写使能
input r_en,//读使能
output reg [7:0]read_data,//读入数据
output done,//一次i2c操作完成
output scl,
inout sda
);
规格化后的。Markdown里看着差别不大,但是我在Vscode里感觉完全不一样。
module i2c_ctrl
#(
parameter FPGA_clk = 26'd50_000_000 ,
parameter I2C_clk = 18'd250_000
)(
input sys_clk , //系统时钟,会分频
input rst_n ,
input [7:0] slave_addr , //器件地址,不设为常量是考虑多从机情况
input [7:0] write_data , //写数据
input [15:0] word_addr , //字地址 高8位可以无效
input w_en , //写使能
input r_en , //读使能
output reg [7:0] read_data , //读入数据
output done , //一次i2c操作完成
output scl ,
inout sda
);
下面是总结的几条规范化建议:
1 端口信号定义时位宽,变量名,逗号,注释上下对齐
看verilog代码第一眼就是端口信号,一个整齐的信号美观度Max,而且,例化时非常方便,直接alt+shift/ctrl赋值若干列,效率高。
端口信号名,若有时钟,说明频率,如clk_50M,统一使用pll生成频率时会很方便。若有输出时钟,命名为对应外设时钟,如i2c_clk,spi_clk。
2 定义常量(parameter)用大写字母,定义变量用小写字母
parameter [12:0] IDLE = 13'd1 ;
reg [9:0] clk_cnt;
3 变量名做到见名知义,用连贯的写法,分割用下划线,某些介词用数字代替
连贯的写法指clock->clk, address->addr。节省阅读成本。下划线连接两个不同的名词构成一个专有名词,比如bit_cnt。一些介词有同音的数字,比如to->2,for->4,我不太习惯,但看到过很多人用。
4 变量定义时不要赋初值
定义时赋初值的作用是仿真会用到和仿真开始没有红色的X信号,美观一点,其余都是坏处。reg sda_in = 1'b0
若一个信号被定义了但没有在后续赋值,而这个信号也要赋值给其他信号,那么若有初始值时在仿真阶段不能明显的被检查到,增加纠错成本。
verilog描述的是硬件电路,硬件电路最开始很多地方也是没有初始值的,上电复位后等一段时间才有稳定的输出,那么就不该赋初值。这也是我非常讨厌把模块例化比作C语言函数调用行为的地方。
也不是没有例外,不过看成特殊的常量就行。
reg [8:0] clk_div = FPGA_clk / I2C_clk;
5 clk用posedge,rst_n用negetdge,统一时钟
竞争和冒险,在状态机出现异常状态跳变查不出具体问题在哪时很崩溃。PLL的输出范围在6.25M-800M,不在范围内的要手动分频,多时钟电路注意。
6 一个always语句对一个信号赋值(三段式状态机)
复用,后续修改和阅读很方便,也是很多公司会用到的标准。有时候关联性强的信号,比如scl和sda,clk_cnt和scl_clk可以一起。(不确定)
7 begin和关键字同行,end另起一行,一条语句也要begin-end
Verilog和C很像,begin-end从{…}来的,不过C的代码写法也一直在变,有左右括号单独列一行,有左括号跟关键字右括号单独列一行,因为是先学的C,所以总会不习惯,就定一个最多人用的风格。
补充:状态机begin-end单独列一行,因为状态后面可能会写注释。always语句begin和always并列,因为可以在always前单独开一行写注释。
8不要小瞧注释,可以在注释里画时序图甚至FSM
最好是英文写注释,不会因为编码格式不同而乱码。看到过用- / | \ _几个符号画信号时序图的注释,惊呆我一整年。
verilog编码风格
9 例化名用u_模块名_<0~9>命名
以前用的格式u0,u1,u2…。导出原理图时都不认识哪个模块是什么了。
10 顶层模块只提供连线和例化模块,不写任何逻辑
想到接着补充