work/Scripts/blog/verilog_mode_UG/verilog_mode_UG.md

8.6 KiB
Raw Blame History

@TOC

1 what is verilog-mode

verilog-mode原本是Emacs的一种编辑模式面向Verilog的开发环境主要是提供自动缩进机制和AUTO机制。其中AUTO机制是verilog-mode最重要的核心。AUTO机制主要提供自动模块参数列表、自动完成模块例化和自动声明连线等 我们在写rtl时候尤其是在top顶层集成的时候经常会不可避免的来进行例化模块连接信号这非常繁琐和容易出错。这也是veirlog-mode产生的背景

1.1 收益

  • 自动缩进,代码整洁,便于阅读等;
  • 提高编码效率和准确性,尤其是在顶层实例化;
  • 便于维护,比如修改、增加和删除端口,无需修改参数列表,比如修改、增加和删除子模块端口,无需修改顶层实例化;

2 How to use--AUTO机制

所有的都是添加/AUTOxxx/,最后使用\m来自动化生成

2.1 AUTOSENSE来自动生成敏感列表

编写时:

always @ (/*AUTOSENSE*/) begin
    dout_a = {din_a,din_b};
end

\a生成后

always @(/*AUTOSENSE*/din_a or din_b) begin
    dout_a = {din_a,din_b};
end

2.2 AUTOARG来自动生成模块输入输出参数列表

编写时:

module sub_md(/*AUTOARG*/);
input din_a;
input din_b;
output reg[1:0] dout_a;

endmodule:sub_md

\a生成后

module sub_md(/*AUTOARG*/
    // Outputs
    dout_a,
    // Inputs
    din_a,din_b
);
input din_a;
input din_b;
output reg[1:0] dout_a;

always @ (/*AUTOSENSE*/) begin
    dout_a = {din_a,din_b};
end
endmodule:sub_md

2.3 AUTOINST来自动实现例化

编写时:

# sub_md.v

module sub_md(/*AUTOARG*/
    // Outputs
    dout_a,
    // Inputs
    din_a,din_b
);
input din_a;
input din_b;
output reg[1:0] dout_a;

always @ (/*AUTOSENSE*/) begin
    dout_a = {din_a,din_b};
end
endmodule:sub_md

# top_md.v
module top_md(/*AUTOARG*/);
input               din1;
input wire[1:0]     din2;

output              dout1;
output [1:0]        dout2;

/*AUTOREG*/
/*AUTOWIRE*/

wire    din_a;
wire    din_b;

always @(/*AUTOSENSE*/) beign
    dout1 = din1 | din2[1];
end

assign din_a = din2[0];
assign din_b = din2[1];

sub_md u_sub_md(/*AUTOINST*/);

assign dout2[1:0] = dout_a[1:0]; 

endmodule: top_md

\a生成后

module top_md(/*AUTOARG*/
// Outputs
dout1, dout2,
// Inputs
din1, din2
);
input           din1;
input [1:0]     din2;

output          dout1;
output [1:0]    dout2;

/*AUTOREG*/
// Beginning of automatic regs (for this module's undeclared outputs)
reg                     dout1;
// End of automatics
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [1:0]              dout_a;                 // From i_sub_md of sub_md.v
// End of automatics

wire            din_a;
wire            din_b;

always@(/*AUTOSENSE*/din1 or din2)
    dout1 = din1 | din2[1];

assign din_a = din2[0];
assign din_b = din2[1];

sub_md i_sub_md(/*AUTOINST*/
                // Outputs
                .dout_a                 (dout_a[1:0]),
                // Inputs
                .din_a                  (din_a),
                .din_b                  (din_b));

assign dout2[1:0] = dout_a[1:0];

endmodule: top_md

这样上述做的需要的约束或者前提是: 1.子模块与顶层例化模块需保存在同一文件目录;否则会索引不到子模块; 2.实例化的端口名与子模块的端口名默认是一致的;一般来讲,是提倡实例化的端口名与子模块的端口名保持一致; 3.但是经常连线是必须涉及到实例化端口名和被实例化端口名不一致的情况; ---1.在/AUTOINST/之前进行直接指定该端口名,放心/AUTOINST/之前的端口名不会再次生成但是最后加上Inputs/Outputs注释否则AUTOWIRE不知道信号方向 比如如下:

fanout fanout (
                //.i端口事先声明
               // Inputs
               .i          (my_i_dont_mess_with_it),
               /*AUTOINST*/
               // Outputs
               .o          (o[31:0]));

2.4 AUTOWIRE来自动实现连线

顶层实例化时需要将线进行声明AUTOWIRE特别适合两个子模块之间互连且没在顶部模块中使用到的信号 约束前提:子模块间互联的信号不是已经在顶层上使用过的信号; 编写时:

# src.v
module src(/*AUTOARG*/);
input   des2src_a;
input   des2src_b;
output [1:0] src2des;

always @(/*AUTOSENSE*/) begin
    src2des = {des2src_b,des2src_a};
end
endmodule:src

# des.v
module des(/*AUTOARG*/);
output  des2src_a;
output  des2src_b;
input [1:0] src2des;

always @(/*AUTOSENSE*/) begin
    {des2src_b,des2src_a} = src2des;
end

endmodule:des

# top.v
module top(/*AUTOARG*/);
input a;
output b;

/*AUTOWIRE*/

/*AUTOREG*/

src u_src(/*AUTOINST*/);

des u_des(/*AUTOINST*/);

endmodule:top

\a生成因为代码比较多在这里就不展示了

2.5 AUTOREG

若是模块的输出来自寄存器会自动为该输出信号名声明为寄存器AUTOREG将完成输出信号的寄存器声明若是输出来自非寄存器则不会添加reg声明 编辑时:

module src(/*AUTOARG*/);
input   des2src_a;
input   des2src_b;
output [1:0] src2des;
output test_auto_reg;
output test_auto_wire;

/*AUTOREG*/

/*AUTOWIRE*/

always @(/*AUTOSENSE*/) begin
    src2des = {des2src_b,des2src_a};
end

always @(*) begin
    test_auto_reg = 1'b0;
end

assign test_auto_wire = 1'b1;

endmodule:src

\a生成后: alt text

2.6 AUTOINSTPARAM来自动实现例化时填充参数

这个一般使用场景比较少因为parameter较少 编辑时:

# autoinstparam.v
module autoinstparam #(
    parameter   para_1,
    parameter   para_2
)(
    /*AUTOARG*/ 
);

input   a;
input   b;
output  c;

assign c = a ^ b;
endmodule: autoinstparam

# topparam.v
module topparam(/*AUTOARG*/);

input test_in;
output test_out;

parameter   para_1 = 0,
            para_2 = 1;

wire a = 0;
wire b = 1;

autoinstparam #(/*AUTOINSTPARAM*/

) u_autoinstparam(/*AUTOINST*/);

endmodule: topparam

\a生成后 alt text

2.7 AUTOINPUT、AUTOOUTPUT来自动实现top层的输入输出

如果在top层一般只有子模块的例化没有任何其他粘合逻辑当然这也是某种最理想的情况 这时top层通过AUTOWIRE声明子模块的例化连线,AUTOREG来声明未声明的输出信号寄存器AUTOINST来实现子模块的例化其余未声明的信号就是top模块的输入输出信号可以通过AUTOINPUT,AUTOOUTPUT完成输入输出信号的声明

编辑时:

# sub_md.v
module sub_md(
    /*AUTOARG*/
);
input   din_a;
input   din_b;

output [1:0] dout;

assign dout = {din_b,din_a};

endmodule: sub_md

# top_md.v
module top_md(
    /*AUTOARG*/
);
/*AUTOINPUT*/

/*AUTOOUTPUT*/

sub_md u_sub_md(/*AUTOINST*/);

endmodule: top_md

\a生成后 alt text

AUTORESET来自动实现时序逻辑的初始化

寄存器声明的变量往往需要赋初值。描述时序逻辑的always时最好对复位条件下进行寄存器变量的初始化描述组合逻辑的always时最好对寄存器变量赋缺省值这样不会产生latch。 AUTORESET模式初始化赋值是0若是其他值需手动添加到AUTORESET之前这样就不会重复添加

编辑时:

module autoreset(
    /*AUTOARG*/
); 

reg        dout_a;
reg  [1:0] dout_b;
reg  [2:0] dout_c;
reg        dout_x;
reg  [1:0] dout_y;
reg  [2:0] dout_z;

always@(*)
    /*AUTORESET*/
if (sig1==1'b1)begin
    dout_a      = din0;
    dout_b[1:0] = {2{din1}};
    dout_c[2:0] = {3{din2}};
end

always@(posedge clk or negedge rst_n)
if (!rst_n)begin
    /*AUTORESET*/
end
else begin
    dout_x      <= din0;
    dout_y[1:0] <= {2{din1}};
    dout_z[2:0] <= {3{din2}};
end

endmodule: autoreset

特别注意要事先声明reg变量,AUTORESET才会自动加上位宽。 \a生成后 alt text

AUTOREGINPUT来自动实现打激励

尤其适用于搭建testbench时将设计模块(dut)作为一个子模块在TB中进行例化因此需要一些reg类型的信号作为dut的输入激励。

编辑时:

module dut(
    /*AUTOARG*/
);
input din1;
input din2;
output dout;

assign dout = din1 & din2;

endmodule: dut

module testbench;
/*AUTOREGINPUT*/

initial begin
    #0  begin din1 = 1'b0; din2 =1'b0; end
    #10 begin din1 = 1'b0; din2 =1'b1; end
    #10 begin din1 = 1'b1; din2 =1'b0; end
    #10 begin din1 = 1'b1; din2 =1'b1; end
end

dut i_dut(/*AUTOINST*/);

endmodule: testbench

\a生成后 alt text

3 AUTO_TEMPLATE创建模板

3.1 AUTOTEMPLATE

在模板中使用Lisp