前言
在我年轻的时候,在例化了几个近百行接口的module,声明了还几百行的接口和wire后,精神就已经恍惚了,一直恍惚到今天。于是后来我尝试了各种办法来简化这个过程,包括生成简单的例化代码,通过VBA做例化文件等等,但是使用无法解决还是需要手动修改和连线的问题。
终于有一天我知道了verilogmode,所以我突然萌生一个想法,我也要做一个这样的工具来练一练手!
准备
做好的脚本我放在了固定路径下,之后在vimrc中补充这句话:
command! L :execute '%! /home/xiaotu/my_work/gen_link/gen_link -f %'
command! D :execute '%! /home/xiaotu/my_work/gen_link/gen_link -d -f %'
准备了几个需要在定层互连的模块:processing_unit、ctrl_unit、mem_unit,关于这几个模块的具体行为请参考:
在此只罗列下三个模块的接口:
module processing_unit #(
`include "C:/Users/gaoji/Desktop/RISC_SPM/src/para_def.v"
)(
output [WORD_WD -1:0] instruction ,//to ctl
output zero_flag ,//to ctl
output [ADDR_WD -1:0] addr ,//to mem, address
output [WORD_WD -1:0] bus1 ,//to mem, data_in
input [WORD_WD -1:0] mem_word ,//from mem, data_out
input load_R0, load_R1, load_R2, load_R3,
input load_PC,
input load_IR,
input load_reg_Y,
input load_reg_Z,
input load_add_R,
input inc_PC,
input [SEL1_WD -1:0] mux1_sel_to_bus1,
input [SEL2_WD -1:0] mux2_sel_to_bus2,
input clk, rst_n
);
module ctrl_unit #(
`include "C:/Users/gaoji/Desktop/RISC_SPM/src/para_def.v"
)(
output reg load_R0, load_R1, load_R2, load_R3,
output reg load_PC,
output reg load_IR,
output reg load_reg_Y,
output reg load_reg_Z,
output reg load_add_R,
output reg inc_PC,
output reg [SEL1_WD -1:0] mux1_sel_to_bus1,
output reg [SEL2_WD -1:0] mux2_sel_to_bus2,
output reg write,
input [WORD_WD -1:0] instruction,
input zero_flag,
input clk, rst_n
);
module mem_unit #(
`include "C:/Users/gaoji/Desktop/RISC_SPM/src/para_def.v"
)(
output [WORD_WD -1:0] data_out,
input [WORD_WD -1:0] data_in,
input [ADDR_WD -1:0] addr_in,
input write_en,
input clk, rst_n
);
现在我要做的就是将这三个模块按照 如下的结构进行互连:
实际操作
在实际操作中,定层文件全部代码量如下:
module link_test(/*GEN_PORT*/);
parameter SEL1_WD = 3;
parameter SEL2_WD = 5;
parameter WORD_WD = 1024;
parameter ADDR_WD = 128;
//GEN_INPUT
//GEN_OUTPUT
//GEN_WIRE
/*ctrl_unit u_ctrl LINK_MODULE
.write(ctrl2mem_write),
.load_(.*)(LINK_load_#1#),
*/
ctrl_unit #(/*GEN_PARA*/) u_ctrl(/*GEN_LINK*/);
/*processing_unit u_proc LINK_MODULE
.load_(.*)(LINK_load_#1#)
.mem_word(mem_word)
.bus1(proc2mem_data)
.addr(proc2mem_addr)
*/
processing_unit u_proc(/*GEN_LINK*/);
/*mem_unit u_mem LINK_MODULE
.write_en(ctrl2mem_write)
.data_out(mem_word)
.data_in(proc2mem_data)
.addr_in(proc2mem_addr)
*/
mem_unit u_mem(/*GEN_LINK*/);
endmodule
//SUB MODULE LIST START
//"./"
//"./RISC_SPM/src","/home/xiaotu/my_work"
//SUB MODULE LIST END
在文件中键入:L键后,文件的内容转变为:
module link_test(/*GEN_PORT*/
//output port /*GEN_LINK START*/
//input port
rst_n,clk
/*GEN_LINK END*/
);
parameter SEL1_WD = 3;
parameter SEL2_WD = 5;
parameter WORD_WD = 1024;
parameter ADDR_WD = 128;
//GEN_INPUT
/*GEN_LINK START*/
input rst_n;
input clk;
/*GEN_LINK END*/
//GEN_OUTPUT
/*GEN_LINK START*/
/*GEN_LINK END*/
//GEN_WIRE
/*GEN_LINK START*/
wire [SEL2_WD-1:0]mux2_sel_to_bus2;
wire LINK_load_R0;
wire LINK_load_R2;
wire [SEL1_WD-1:0]mux1_sel_to_bus1;
wire LINK_load_IR;
wire ctrl2mem_write;
wire [WORD_WD-1:0]instruction;
wire LINK_load_PC;
wire [WORD_WD-1:0]mem_word;
wire LINK_load_R3;
wire [WORD_WD-1:0]proc2mem_data;
wire inc_PC;
wire LINK_load_add_R;
wire [ADDR_WD-1:0]proc2mem_addr;
wire zero_flag;
wire LINK_load_reg_Y;
wire LINK_load_reg_Z;
wire LINK_load_R1;
/*GEN_LINK END*/
/*ctrl_unit u_ctrl LINK_MODULE
.write(ctrl2mem_write),
.load_(.*)(LINK_load_#1#),
*/
//ctrl_unit #(/*GEN_PARA*/) u_ctrl(/*GEN_LINK*/); GEN_LINK_ADD
/*GEN_LINK START*/
ctrl_unit u_ctrl(
//output port inst
.mux2_sel_to_bus2(mux2_sel_to_bus2),
.load_IR(LINK_load_IR),//FROM .load_(.*)(LINK_load_#1#)
.mux1_sel_to_bus1(mux1_sel_to_bus1),
.load_reg_Y(LINK_load_reg_Y),//FROM .load_(.*)(LINK_load_#1#)
.load_reg_Z(LINK_load_reg_Z),//FROM .load_(.*)(LINK_load_#1#)
.load_R0(LINK_load_R0),//FROM .load_(.*)(LINK_load_#1#)
.write(ctrl2mem_write),//FROM .write(ctrl2mem_write)
.load_R2(LINK_load_R2),//FROM .load_(.*)(LINK_load_#1#)
.load_R3(LINK_load_R3),//FROM .load_(.*)(LINK_load_#1#)
.inc_PC(inc_PC),
.load_R1(LINK_load_R1),//FROM .load_(.*)(LINK_load_#1#)
.load_PC(LINK_load_PC),//FROM .load_(.*)(LINK_load_#1#)
.load_add_R(LINK_load_add_R),//FROM .load_(.*)(LINK_load_#1#)
//input port inst
.rst_n(rst_n),
.zero_flag(zero_flag),
.instruction(instruction),
.clk(clk)
);
/*GEN_LINK END*/
/*processing_unit u_proc LINK_MODULE
.load_(.*)(LINK_load_#1#)
.mem_word(mem_word)
.bus1(proc2mem_data)
.addr(proc2mem_addr)
*/
//processing_unit u_proc(/*GEN_LINK*/); GEN_LINK_ADD
/*GEN_LINK START*/
processing_unit u_proc(
//output port inst
.zero_flag(zero_flag),
.bus1(proc2mem_data),//FROM .bus1(proc2mem_data)
.instruction(instruction),
.addr(proc2mem_addr),//FROM .addr(proc2mem_addr)
//input port inst
.rst_n(rst_n),
.mux2_sel_to_bus2(mux2_sel_to_bus2),
.load_IR(LINK_load_IR),//FROM .load_(.*)(LINK_load_#1#)
.mux1_sel_to_bus1(mux1_sel_to_bus1),
.clk(clk),
.load_reg_Y(LINK_load_reg_Y),//FROM .load_(.*)(LINK_load_#1#)
.load_reg_Z(LINK_load_reg_Z),//FROM .load_(.*)(LINK_load_#1#)
.load_add_R(LINK_load_add_R),//FROM .load_(.*)(LINK_load_#1#)
.mem_word(mem_word),
.load_R2(LINK_load_R2),//FROM .load_(.*)(LINK_load_#1#)
.load_R3(LINK_load_R3),//FROM .load_(.*)(LINK_load_#1#)
.inc_PC(inc_PC),
.load_R1(LINK_load_R1),//FROM .load_(.*)(LINK_load_#1#)
.load_PC(LINK_load_PC),//FROM .load_(.*)(LINK_load_#1#)
.load_R0(LINK_load_R0)//FROM .load_(.*)(LINK_load_#1#)
);
/*GEN_LINK END*/
/*mem_unit u_mem LINK_MODULE
.write_en(ctrl2mem_write)
.data_out(mem_word)
.data_in(proc2mem_data)
.addr_in(proc2mem_addr)
*/
//mem_unit u_mem(/*GEN_LINK*/); GEN_LINK_ADD
/*GEN_LINK START*/
mem_unit u_mem(
//output port inst
.data_out(mem_word),//FROM .data_out(mem_word)
//input port inst
.rst_n(rst_n),
.write_en(ctrl2mem_write),//FROM .write_en(ctrl2mem_write)
.data_in(proc2mem_data),//FROM .data_in(proc2mem_data)
.addr_in(proc2mem_addr),//FROM .addr_in(proc2mem_addr)
.clk(clk)
);
/*GEN_LINK END*/
endmodule
//SUB MODULE LIST START
//"./"
//"./RISC_SPM/src","/home/xiaotu/my_work"
//SUB MODULE LIST END
如果我看的没有问题的话,应该是按照要求完成了全部互连工作!
再次键入:D,生成的代码消失,文件恢复到原始状态。
顶层文件格式
endmodule
//SUB MODULE LIST START
//"./"
//"./RISC_SPM/src","/home/xiaotu/my_work"
//SUB MODULE LIST END
endmodule之后的代码,SUB MODULE LIST START .. SUB MODULE LIST END之间的路径,用来查找定层内所需module的文件,支持绝对路径和相对路径,不支持环境变量;
/*ctrl_unit u_ctrl LINK_MODULE
.write(ctrl2mem_write),
.load_(.*)(LINK_load_#1#),
*/
这一段代码表示例化模块的信息,module inst LINK_MODULE关键字,下面到*/之前的行可以支持以下形式的写法:
1.关于某信号什么也不写,那么直接按moudle内接口名例化:
ctrl_unit u_ctrl(
//output port inst
.mux2_sel_to_bus2(mux2_sel_to_bus2),
2.关于某信号,支持改名,例化时会标记怎么改的名字:
.addr(proc2mem_addr),//FROM .addr(proc2mem_addr)
3.改名时支持通配符,比如
.load_(.*)(LINK_load_#1#),
代表把load_xxx信号连接为LINK_load_xxx信号,连接效果就是:
.load_reg_Y(LINK_load_reg_Y),//FROM .load_(.*)(LINK_load_#1#)
.load_reg_Z(LINK_load_reg_Z),//FROM .load_(.*)(LINK_load_#1#)
.load_R0(LINK_load_R0),//FROM .load_(.*)(LINK_load_#1#)
.write(ctrl2mem_write),//FROM .write(ctrl2mem_write)
.load_R2(LINK_load_R2),//FROM .load_(.*)(LINK_load_#1#)
.load_R3(LINK_load_R3),//FROM .load_(.*)(LINK_load_#1#)
4.支持输出信号空接,输入信号接定值:
.mux2_sel_to_bus2(),
.zero_flag(1'b1),
对应生成信号:
.mux2_sel_to_bus2(),//FROM .mux2_sel_to_bus2()
.zero_flag(1'b1),//FROM .zero_flag(1'b1)
5.支持parameter传递,但是参数传递不支持通配符:
/*ctrl_unit u_ctrl LINK_MODULE
.SEL1_WD (5)
...
ctrl_unit #(
.SEL1_WD(5)
) u_ctrl(
此时生成的信号,位宽对应自动修改:
wire [5-1:0]mux1_sel_to_bus1;
OK,关于接口的格式说明 就这么多;
ctrl_unit #(/*GEN_PARA*/) u_ctrl(/*GEN_LINK*/);
processing_unit u_proc(/*GEN_LINK*/);
mem_unit u_mem(/*GEN_LINK*/);
这个用来标记模块例化在哪,同时,有GEN_LINK的会生成接口连接,有GEN_PARA的会生成parameter连接,生成后这行会被注释掉:
//mem_unit u_mem(/*GEN_LINK*/); GEN_LINK_ADD
/*GEN_LINK START*/
mem_unit u_mem(
//output port inst
.data_out(mem_word),//FROM .data_out(mem_word)
//input port inst
.rst_n(rst_n),
.write_en(ctrl2mem_write),//FROM .write_en(ctrl2mem_write)
.data_in(proc2mem_data),//FROM .data_in(proc2mem_data)
.addr_in(proc2mem_addr),//FROM .addr_in(proc2mem_addr)
.clk(clk)
);
/*GEN_LINK END*/
在:D时,GEN_LINK_ADD这行会被取消注释,恢复原样;
//GEN_INPUT
//GEN_OUTPUT
//GEN_WIRE
这三个注释用来标记生成内部和接口信号,如果没有GEN_INPUT或GEN_OUTPUT的话,会把信号声明在wire里:
//GEN_INPUT
/*GEN_LINK START*/
input rst_n;
input [SEL2_WD-1:0]mux2_sel_to_bus2;
input clk;
/*GEN_LINK END*/
//GEN_OUTPUT
/*GEN_LINK START*/
output zero_flag;
/*GEN_LINK END*/
//GEN_WIRE
/*GEN_LINK START*/
wire LINK_load_R0;
wire LINK_load_R2;
wire [5-1:0]mux1_sel_to_bus1;
wire LINK_load_IR;
wire ctrl2mem_write;
wire [WORD_WD-1:0]instruction;
wire LINK_load_PC;
wire [WORD_WD-1:0]mem_word;
wire LINK_load_R3;
wire [WORD_WD-1:0]proc2mem_data;
wire inc_PC;
wire LINK_load_add_R;
wire [ADDR_WD-1:0]proc2mem_addr;
wire LINK_load_reg_Y;
wire LINK_load_reg_Z;
wire LINK_load_R1;
/*GEN_LINK END*/
没有output、input:
//GEN_WIRE
/*GEN_LINK START*/
wire LINK_load_R0;
wire LINK_load_R2;
wire [5-1:0]mux1_sel_to_bus1;
wire LINK_load_IR;
wire ctrl2mem_write;
wire [WORD_WD-1:0]instruction;
wire LINK_load_PC;
wire [WORD_WD-1:0]mem_word;
wire LINK_load_R3;
wire [WORD_WD-1:0]proc2mem_data;
wire inc_PC;
wire LINK_load_add_R;
wire [ADDR_WD-1:0]proc2mem_addr;
wire LINK_load_reg_Y;
wire LINK_load_reg_Z;
wire LINK_load_R1;
wire rst_n; //org = input
wire [SEL2_WD-1:0]mux2_sel_to_bus2; //org = input
wire clk; //org = input
wire zero_flag; //org = output
/*GEN_LINK END*/
如果在生成信号时发现已经 有某个信号在rtl中手动声明了,那么就不会重复声明:
input clk;
//GEN_INPUT
/*GEN_LINK START*/
input rst_n;
input [SEL2_WD-1:0]mux2_sel_to_bus2;
/*GEN_LINK END*/
module link_test(/*GEN_PORT*/);
这里用来生成定层对外接口以95代码标准形式生成:
module link_test(/*GEN_PORT*/
//output port /*GEN_LINK START*/
zero_flag,
//input port
clk,rst_n,mux2_sel_to_bus2
/*GEN_LINK END*/
);
OK主体功能就是这样的,如果在生成后不满意,可直接修改一些信号连接,继续按:L就可以重新生成,此时之前生成的带啊会被清除,直接跟新为新的代码;或者通过:D来恢复为原始代码,进行修改后重新生成;
工具路径