【python脚本】应用于verilog RTL的顶层模块互连集成工具

前言

在我年轻的时候,在例化了几个近百行接口的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,关于这几个模块的具体行为请参考:

【读书笔记】RISC存储程序机的电路设计

在此只罗列下三个模块的接口:

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来恢复为原始代码,进行修改后重新生成;

工具路径

gen_link

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尼德兰的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值