我有一个用Verilog(很重要的不是SystemVerilog)编写的项目,由于在设计的不同部分之间传递信号的数量,它已经变得有点难以管理。由于我有几个模块都需要相同的信号,我正在考虑将它们合并为少量的命名对象。问题是如何做到这一点。
让我们说这是我做作的例子:
module mymodule(sig_a_in, sig_b_in, sig_c_in, sig_d_in, sig_e_in,
sig_a_out, sig_b_out, sig_c_out, sig_d_out, sig_e_out);
input wire sig_a_in, sig_b_in, sig_c_in;
input wire [5 : 0] sig_d_in;
input wire [31 : 0] sig_e_in;
output reg sig_a_out, sig_b_out, sig_c_out;
output reg [5 : 0] sig_d_out;
output reg [31 : 0] sig_e_out;
endmodule
在我看来,重要的是,为了便于阅读,我可以通过名字来引用信号。但是,我不想将它们全部单独传递给每个模块。同样,我只在这个项目中使用Verilog,因此不可能使用SystemVerilog构造。
我的第一个想法是,我只是将它们组合成一个总线,然后使用定义的名称来引用各个线路。然而,这有点笨重,特别是当您添加其他公共汽车时。在我设计的例子中,这是非常微不足道的,因为信号有明显的隐含顺序,但在现实生活中它们并没有。
`define SIGNAL_BUS_WIDTH 41
`define A 0
`define B 1
`define C 2
`define D 3
`define E 9
module mymodule(signal_bus_in, signal_bus_out);
input wire [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_in;
output reg [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_out;
// reference a
signal_bus_in[`A]
// reference d? Not good when names don't have an obvious order
signal_bus_in[`E-1 : `D]
endmodule
最后,除了所有这些之外,工具链还必须能够区分模块中哪些导线被模块使用,并且只能合成这些导线。并非所有模块都使用所有线路,因此我希望避免使用额外的未使用路径。我认为工具应该足够智能,即使在上面的总线示例中也是如此,但我并不完全确定。
有没有一种方法可以在Verilog中得到我想要的东西?
答案 0 :(得分:1)
您可以通过使用宏来定义每个信号的范围而不是端点,从而进一步扩展您的想法:
`define WIDTH 41
`define sigA 0:0
`define sigB 1:1
`define sigC 2:2
`define sigD 8:3
`define sigE 40:9
module mymodule(signal_bus_in, signal_bus_out);
input wire [`WIDTH-1 : 0] signal_bus_in;
output reg [`WIDTH-1 : 0] signal_bus_out;
...
// signal a
signal_bus_in[`sigA];
// signal d
signal_bus_in[`sigD];
...
当然,这并不像SystemVerilog打包的结构那么容易(这就是它们存在的原因!),但它可以满足您的需求。此外,这也增加了你的线条的顺序,但我看到没有结构不会这样做;偶数结构将为您的信号添加顺序。但是,只要您使用宏,除了定义marcos之外,订单并不重要。
任何好的综合工具都应该能够丢弃任何不驱动任何东西或者没有驱动任何东西的端口或电线,所以除非你必须明确地告诉它由于某种原因忽略哪些线路,你不应该担心它为未使用的模块引脚合成额外的空间。
答案 1 :(得分:1)
Verilog没有结构。 IMO将长矢量(或称为总线)中的所有信号组合在一起是您最好的选择。但是,您可以略微改进您的宏:
`define SIGNAL_BUS_WIDTH 41
`define A 0:0
`define B 1:1
`define C 2:2
`define D 8:3
`define E 40:9
// reference a
signal_bus_in[`A]
// reference d
signal_bus_in[`D]
// reference e
signal_bus_in[`E]
大多数综合工具都没有为未连接的电线创建额外的逻辑,并将它们视为不关心。
答案 2 :(得分:1)
为避免过多依赖预处理器,您可以尝试使用localparam
和function
声明来模拟结构。下面是一个“mybus”结构的模型,其中有四个字段,名为A到D,各种大小,以说明这个想法。
您可以将这些支持参数和函数放入一个文件中include
仅在需要构建和解构这种总线的各种模块中。这可能允许您使用较短的名称而不必担心冲突。
module test ;
// Boilerplate structure size definitions -- you could automatically generate these
// with a simple script and put them into an include file.
localparam mybus_a_size = 4;
localparam mybus_a_offset = 0;
localparam mybus_b_size = 8;
localparam mybus_b_offset = mybus_a_offset + mybus_a_size;
localparam mybus_c_size = 4;
localparam mybus_c_offset = mybus_b_offset + mybus_b_size;
localparam mybus_d_size = 6;
localparam mybus_d_offset = mybus_c_offset + mybus_c_size;
localparam mybus_size = mybus_a_size + mybus_b_size + mybus_c_size + mybus_d_size;
// accessor functions, i.e., instead of bus.a you write mybus_a(bus)
function [mybus_a_size-1:0] mybus_a (input [mybus_size-1:0] in);
mybus_a = in[mybus_a_size + mybus_a_offset - 1 : mybus_a_offset];
endfunction
function [mybus_b_size-1:0] mybus_b (input [mybus_size-1:0] in);
mybus_b = in[mybus_b_size + mybus_b_offset - 1 : mybus_b_offset];
endfunction
function [mybus_c_size-1:0] mybus_c (input [mybus_size-1:0] in);
mybus_c = in[mybus_c_size + mybus_c_offset - 1 : mybus_c_offset];
endfunction
function [mybus_d_size-1:0] mybus_d (input [mybus_size-1:0] in);
mybus_d = in[mybus_d_size + mybus_d_offset - 1 : mybus_d_offset];
endfunction
// constructor function -- build a mybus out of its components
function [mybus_size-1:0] make_mybus(input [mybus_a_size-1:0] a,
input [mybus_b_size-1:0] b,
input [mybus_c_size-1:0] c,
input [mybus_d_size-1:0] d);
make_mybus = {d,c,b,a};
endfunction
// example of using this stuff
reg [mybus_size - 1 : 0] bus;
initial begin
bus = make_mybus(1,2,3,4);
$display("Hello, my bus is { a=%b, b=%b, c=%b, d=%b }", mybus_a(bus), mybus_b(bus), mybus_c(bus), mybus_d(bus));
end
endmodule
这个模拟可能会成为一个很好的起点。一些明显的改进是从一个简单的脚本自动生成所有这个样板,并在C ++中添加其他构造函数,如“setter”,即
set_mybus_a(mybus, 5) // set mybus.a = 5