是否有可综合的任务或端口接口方式来更好地将 AXI 信号分配给本地模块?
Is there a synthesizeable task or port interface way to better assign AXI signals to local modules?
目前我的设计中有一个横杆,我正在以不同的偏移量连接几个不同的模块(xbarAWADDR
和其他模块根据总线名称增加 32 或 40 或 4 或 1)。我将交叉开关信号传递给各个模块,如下所示。不过,这让我开始思考,是否有更易读或更有效的方式来多次编写此代码?
我 运行 关注的问题是,由于其 AXI,总线长度随输入和输出而变化。我想也许有两个结构会起作用,但我认为偏移地址和数据行之类的东西会更难,而且最终可能会产生更多代码。但我平均这样做 5 到 10 次。它很大,可能会很痛苦。也许一个虚拟任务需要四个结构输入、一个迭代次数并输出两个新结构?
也许有一些我不知道的结构可以更好地做到这一点?
为了进一步说明,我想做的是
localBusAssign( crossbarAxiBus, regBus, 0 );
localBusAssign( crossbarAxiBus, bramBus, 1);
而不是这个
// Map CTRL REGS
wire [ 39: 0 ] ctrlRegAWADDR ;
wire [2 : 0 ] ctrlRegAWPROT ;
wire ctrlRegAWVALID ;
wire ctrlRegAWREADY ;
wire [31 : 0 ] ctrlRegWDATA ;
wire [3 : 0 ] ctrlRegWSTRB ;
wire ctrlRegWVALID ;
wire ctrlRegWREADY ;
wire [ 1 : 0 ] ctrlRegBRESP ;
wire ctrlRegBVALID ;
wire ctrlRegBREADY ;
wire [ 39: 0 ] ctrlRegARADDR ;
wire [ 2 : 0 ] ctrlRegARPROT ;
wire ctrlRegARVALID ;
wire ctrlRegARREADY ;
wire [31 : 0 ] ctrlRegRDATA ;
wire [1 : 0 ] ctrlRegRRESP ;
wire ctrlRegRVALID ;
wire ctrlRegRREADY ;
//ctrl reg mappings
assign ctrlRegAWADDR = xbarAWADDR[39 : 0];
assign ctrlRegAWPROT = xbarAWPROT[ 2 : 0];
assign ctrlRegAWVALID = xbarAWVALID[0];
assign xbarAWREADY[0] = ctrlRegAWREADY;
assign ctrlRegWDATA = xbarWDATA[31 : 0];
assign ctrlRegWSTRB = xbarWSTRB[3 : 0];
assign ctrlRegWVALID = xbarWVALID[0];
assign xbarWREADY[0] = ctrlRegWREADY;
assign xbarBRESP[1 : 0] = ctrlRegBRESP;
assign xbarBVALID[0] = ctrlRegBVALID;
assign ctrlRegBREADY = xbarBREADY[0];
assign ctrlRegARADDR = xbarARADDR[39 : 0];
assign ctrlRegARPROT = xbarARPROT[2 : 0];
assign ctrlRegARVALID = xbarARVALID[0];
assign xbarARREADY[0] = ctrlRegARREADY;
assign xbarRDATA[31 : 0] = ctrlRegRDATA;
assign xbarRRESP[1 : 0] = ctrlRegRRESP;
assign xbarRVALID[0] = ctrlRegRVALID;
assign ctrlRegRREADY = xbarRREADY[0];
wire [39 : 0] bramCtrlAWADDR ;
wire [2 : 0] bramCtrlAWPROT ;
wire bramCtrlAWVALID ;
wire bramCtrlAWREADY ;
wire [31 : 0] bramCtrlWDATA ;
wire [3 : 0] bramCtrlWSTRB ;
wire bramCtrlWVALID ;
wire bramCtrlWREADY ;
wire [1 : 0] bramCtrlBRESP ;
wire bramCtrlBVALID ;
wire bramCtrlBREADY ;
wire [39 : 0] bramCtrlARADDR ;
wire [2 : 0] bramCtrlARPROT ;
wire bramCtrlARVALID ;
wire bramCtrlARREADY ;
wire [31 : 0] bramCtrlRDATA ;
wire [1 : 0] bramCtrlRRESP ;
wire bramCtrlRVALID ;
wire bramCtrlRREADY ;
assign bramCtrlAWADDR = xbarAWADDR[79 :40];
assign bramCtrlAWPROT = xbarAWPROT[ 5 : 3];
assign bramCtrlAWVALID = xbarAWVALID[0];
assign xbarAWREADY[1] = bramCtrlAWREADY;
assign bramCtrlWDATA = xbarWDATA[63 :32];
assign bramCtrlWSTRB = xbarWSTRB[7 : 4];
assign bramCtrlWVALID = xbarWVALID[1];
assign xbarWREADY[1] = bramCtrlWREADY;
assign xbarBRESP[3 : 2] = bramCtrlBRESP;
assign xbarBVALID[1] = bramCtrlBVALID;
assign bramCtrlBREADY = xbarBREADY[1];
assign bramCtrlARADDR = xbarARADDR[79 :40];
assign bramCtrlARPROT = xbarARPROT[5 : 3];
assign bramCtrlARVALID = xbarARVALID[1];
assign xbarARREADY[1] = bramCtrlARREADY;
assign xbarRDATA[63 :32] = bramCtrlRDATA;
assign xbarRRESP[3 : 2] = bramCtrlRRESP;
assign xbarRVALID[1] = bramCtrlRVALID;
assign bramCtrlRREADY = xbarRREADY[1];
对于任何需要它的人,这就是我想出的解决方案。
package axiutils;
import sysdefs_lib::*;
typedef struct {
reg [ A_AXIF_WIDTH*NUMIFACE-1 : 0 ] AWADDR ;
reg [ NUMIFACE*3-1 : 0 ] AWPROT ;
reg [ NUMIFACE-1 : 0 ] AWVALID ;
reg [ NUMIFACE-1 : 0 ] AWREADY ;
reg [ A_DATA_WIDTH*NUMIFACE-1 : 0 ] WDATA ;
reg [ NUMIFACE*4-1 : 0 ] WSTRB ;
reg [ NUMIFACE-1 : 0 ] WVALID ;
reg [ NUMIFACE-1 : 0 ] WREADY ;
reg [ NUMIFACE*2-1 : 0 ] BRESP ;
reg [ NUMIFACE-1 : 0 ] BVALID ;
reg [ NUMIFACE-1 : 0 ] BREADY ;
reg [ A_AXIF_WIDTH*NUMIFACE-1 : 0 ] ARADDR ;
reg [ NUMIFACE*3-1 : 0 ] ARPROT ;
reg [ NUMIFACE-1 : 0 ] ARVALID ;
reg [ NUMIFACE-1 : 0 ] ARREADY ;
reg [ A_DATA_WIDTH*NUMIFACE-1 : 0 ] RDATA ;
reg [ NUMIFACE*2-1 : 0 ] RRESP ;
reg [ NUMIFACE-1 : 0 ] RVALID ;
reg [ NUMIFACE-1 : 0 ] RREADY ;
} xbarRegIface;
typedef struct {
logic [A_AXIF_WIDTH-1 : 0 ] AWADDR ;
logic [2 : 0 ] AWPROT ;
logic AWVALID ;
logic AWREADY ;
logic [A_DATA_WIDTH-1 : 0 ] WDATA ;
logic [3 : 0 ] WSTRB ;
logic WVALID ;
logic WREADY ;
logic [1 : 0 ] BRESP ;
logic BVALID ;
logic BREADY ;
logic [A_AXIF_WIDTH-1 : 0 ] ARADDR ;
logic [2 : 0 ] ARPROT ;
logic ARVALID ;
logic ARREADY ;
logic [A_DATA_WIDTH-1 : 0 ] RDATA ;
logic [1 : 0 ] RRESP ;
logic RVALID ;
logic RREADY ;
} axiLiteIface;
`define xbarData(liteIface, xbarIface, i) \
begin \
assign liteIface.AWADDR = xbarIface.AWADDR[(i+1)*(A_AXIF_WIDTH-1) : A_AXIF_WIDTH*i] ; \
assign liteIface.AWPROT = xbarIface.AWPROT[ 3*i+1 : 3*i] ; \
assign liteIface.AWVALID = xbarIface.AWVALID[i] ; \
assign xbarIface.AWREADY[i] = liteIface.AWREADY ; \
assign liteIface.WDATA = xbarIface.WDATA[(i+1)*(A_DATA_WIDTH-1) : A_DATA_WIDTH*i] ; \
assign liteIface.WSTRB = xbarIface.WSTRB[4*i+3 : 4*i] ; \
assign liteIface.WVALID = xbarIface.WVALID[i] ; \
assign xbarIface.WREADY[i] = liteIface.WREADY ; \
assign xbarIface.BRESP[2*i+1 : 2*i] = liteIface.BRESP ; \
assign xbarIface.BVALID[i] = liteIface.BVALID ; \
assign liteIface.BREADY = xbarIface.BREADY[i] ; \
assign liteIface.ARADDR = xbarIface.ARADDR[(i+1)*(A_AXIF_WIDTH-1) : A_AXIF_WIDTH*i] ; \
assign liteIface.ARPROT = xbarIface.ARPROT[3*i+1 : 3*i] ; \
assign liteIface.ARVALID = xbarIface.ARVALID[i] ; \
assign xbarIface.ARREADY[i] = liteIface.ARREADY ; \
assign xbarIface.RDATA[(i+1)*(A_DATA_WIDTH-1) : A_DATA_WIDTH*i] = liteIface.RDATA ; \
assign xbarIface.RRESP[2*i+1 : 2*i] = liteIface.RRESP ; \
assign xbarIface.RVALID[i] = liteIface.RVALID ; \
assign liteIface.RREADY = xbarIface.RREADY[i] ; \
end
endpackage : axiutils
然后包含包并像这样使用
import axiutils::*;
xbarRegIface xbarReg;
axiLiteIface bus1, bus2, bus3;
`xbarData(bus1, xbarReg, 0);
`xbarData(bus2, xbarReg, 1);
`xbarData(bus3, xbarReg, 2);
目前我的设计中有一个横杆,我正在以不同的偏移量连接几个不同的模块(xbarAWADDR
和其他模块根据总线名称增加 32 或 40 或 4 或 1)。我将交叉开关信号传递给各个模块,如下所示。不过,这让我开始思考,是否有更易读或更有效的方式来多次编写此代码?
我 运行 关注的问题是,由于其 AXI,总线长度随输入和输出而变化。我想也许有两个结构会起作用,但我认为偏移地址和数据行之类的东西会更难,而且最终可能会产生更多代码。但我平均这样做 5 到 10 次。它很大,可能会很痛苦。也许一个虚拟任务需要四个结构输入、一个迭代次数并输出两个新结构?
也许有一些我不知道的结构可以更好地做到这一点?
为了进一步说明,我想做的是
localBusAssign( crossbarAxiBus, regBus, 0 );
localBusAssign( crossbarAxiBus, bramBus, 1);
而不是这个
// Map CTRL REGS
wire [ 39: 0 ] ctrlRegAWADDR ;
wire [2 : 0 ] ctrlRegAWPROT ;
wire ctrlRegAWVALID ;
wire ctrlRegAWREADY ;
wire [31 : 0 ] ctrlRegWDATA ;
wire [3 : 0 ] ctrlRegWSTRB ;
wire ctrlRegWVALID ;
wire ctrlRegWREADY ;
wire [ 1 : 0 ] ctrlRegBRESP ;
wire ctrlRegBVALID ;
wire ctrlRegBREADY ;
wire [ 39: 0 ] ctrlRegARADDR ;
wire [ 2 : 0 ] ctrlRegARPROT ;
wire ctrlRegARVALID ;
wire ctrlRegARREADY ;
wire [31 : 0 ] ctrlRegRDATA ;
wire [1 : 0 ] ctrlRegRRESP ;
wire ctrlRegRVALID ;
wire ctrlRegRREADY ;
//ctrl reg mappings
assign ctrlRegAWADDR = xbarAWADDR[39 : 0];
assign ctrlRegAWPROT = xbarAWPROT[ 2 : 0];
assign ctrlRegAWVALID = xbarAWVALID[0];
assign xbarAWREADY[0] = ctrlRegAWREADY;
assign ctrlRegWDATA = xbarWDATA[31 : 0];
assign ctrlRegWSTRB = xbarWSTRB[3 : 0];
assign ctrlRegWVALID = xbarWVALID[0];
assign xbarWREADY[0] = ctrlRegWREADY;
assign xbarBRESP[1 : 0] = ctrlRegBRESP;
assign xbarBVALID[0] = ctrlRegBVALID;
assign ctrlRegBREADY = xbarBREADY[0];
assign ctrlRegARADDR = xbarARADDR[39 : 0];
assign ctrlRegARPROT = xbarARPROT[2 : 0];
assign ctrlRegARVALID = xbarARVALID[0];
assign xbarARREADY[0] = ctrlRegARREADY;
assign xbarRDATA[31 : 0] = ctrlRegRDATA;
assign xbarRRESP[1 : 0] = ctrlRegRRESP;
assign xbarRVALID[0] = ctrlRegRVALID;
assign ctrlRegRREADY = xbarRREADY[0];
wire [39 : 0] bramCtrlAWADDR ;
wire [2 : 0] bramCtrlAWPROT ;
wire bramCtrlAWVALID ;
wire bramCtrlAWREADY ;
wire [31 : 0] bramCtrlWDATA ;
wire [3 : 0] bramCtrlWSTRB ;
wire bramCtrlWVALID ;
wire bramCtrlWREADY ;
wire [1 : 0] bramCtrlBRESP ;
wire bramCtrlBVALID ;
wire bramCtrlBREADY ;
wire [39 : 0] bramCtrlARADDR ;
wire [2 : 0] bramCtrlARPROT ;
wire bramCtrlARVALID ;
wire bramCtrlARREADY ;
wire [31 : 0] bramCtrlRDATA ;
wire [1 : 0] bramCtrlRRESP ;
wire bramCtrlRVALID ;
wire bramCtrlRREADY ;
assign bramCtrlAWADDR = xbarAWADDR[79 :40];
assign bramCtrlAWPROT = xbarAWPROT[ 5 : 3];
assign bramCtrlAWVALID = xbarAWVALID[0];
assign xbarAWREADY[1] = bramCtrlAWREADY;
assign bramCtrlWDATA = xbarWDATA[63 :32];
assign bramCtrlWSTRB = xbarWSTRB[7 : 4];
assign bramCtrlWVALID = xbarWVALID[1];
assign xbarWREADY[1] = bramCtrlWREADY;
assign xbarBRESP[3 : 2] = bramCtrlBRESP;
assign xbarBVALID[1] = bramCtrlBVALID;
assign bramCtrlBREADY = xbarBREADY[1];
assign bramCtrlARADDR = xbarARADDR[79 :40];
assign bramCtrlARPROT = xbarARPROT[5 : 3];
assign bramCtrlARVALID = xbarARVALID[1];
assign xbarARREADY[1] = bramCtrlARREADY;
assign xbarRDATA[63 :32] = bramCtrlRDATA;
assign xbarRRESP[3 : 2] = bramCtrlRRESP;
assign xbarRVALID[1] = bramCtrlRVALID;
assign bramCtrlRREADY = xbarRREADY[1];
对于任何需要它的人,这就是我想出的解决方案。
package axiutils;
import sysdefs_lib::*;
typedef struct {
reg [ A_AXIF_WIDTH*NUMIFACE-1 : 0 ] AWADDR ;
reg [ NUMIFACE*3-1 : 0 ] AWPROT ;
reg [ NUMIFACE-1 : 0 ] AWVALID ;
reg [ NUMIFACE-1 : 0 ] AWREADY ;
reg [ A_DATA_WIDTH*NUMIFACE-1 : 0 ] WDATA ;
reg [ NUMIFACE*4-1 : 0 ] WSTRB ;
reg [ NUMIFACE-1 : 0 ] WVALID ;
reg [ NUMIFACE-1 : 0 ] WREADY ;
reg [ NUMIFACE*2-1 : 0 ] BRESP ;
reg [ NUMIFACE-1 : 0 ] BVALID ;
reg [ NUMIFACE-1 : 0 ] BREADY ;
reg [ A_AXIF_WIDTH*NUMIFACE-1 : 0 ] ARADDR ;
reg [ NUMIFACE*3-1 : 0 ] ARPROT ;
reg [ NUMIFACE-1 : 0 ] ARVALID ;
reg [ NUMIFACE-1 : 0 ] ARREADY ;
reg [ A_DATA_WIDTH*NUMIFACE-1 : 0 ] RDATA ;
reg [ NUMIFACE*2-1 : 0 ] RRESP ;
reg [ NUMIFACE-1 : 0 ] RVALID ;
reg [ NUMIFACE-1 : 0 ] RREADY ;
} xbarRegIface;
typedef struct {
logic [A_AXIF_WIDTH-1 : 0 ] AWADDR ;
logic [2 : 0 ] AWPROT ;
logic AWVALID ;
logic AWREADY ;
logic [A_DATA_WIDTH-1 : 0 ] WDATA ;
logic [3 : 0 ] WSTRB ;
logic WVALID ;
logic WREADY ;
logic [1 : 0 ] BRESP ;
logic BVALID ;
logic BREADY ;
logic [A_AXIF_WIDTH-1 : 0 ] ARADDR ;
logic [2 : 0 ] ARPROT ;
logic ARVALID ;
logic ARREADY ;
logic [A_DATA_WIDTH-1 : 0 ] RDATA ;
logic [1 : 0 ] RRESP ;
logic RVALID ;
logic RREADY ;
} axiLiteIface;
`define xbarData(liteIface, xbarIface, i) \
begin \
assign liteIface.AWADDR = xbarIface.AWADDR[(i+1)*(A_AXIF_WIDTH-1) : A_AXIF_WIDTH*i] ; \
assign liteIface.AWPROT = xbarIface.AWPROT[ 3*i+1 : 3*i] ; \
assign liteIface.AWVALID = xbarIface.AWVALID[i] ; \
assign xbarIface.AWREADY[i] = liteIface.AWREADY ; \
assign liteIface.WDATA = xbarIface.WDATA[(i+1)*(A_DATA_WIDTH-1) : A_DATA_WIDTH*i] ; \
assign liteIface.WSTRB = xbarIface.WSTRB[4*i+3 : 4*i] ; \
assign liteIface.WVALID = xbarIface.WVALID[i] ; \
assign xbarIface.WREADY[i] = liteIface.WREADY ; \
assign xbarIface.BRESP[2*i+1 : 2*i] = liteIface.BRESP ; \
assign xbarIface.BVALID[i] = liteIface.BVALID ; \
assign liteIface.BREADY = xbarIface.BREADY[i] ; \
assign liteIface.ARADDR = xbarIface.ARADDR[(i+1)*(A_AXIF_WIDTH-1) : A_AXIF_WIDTH*i] ; \
assign liteIface.ARPROT = xbarIface.ARPROT[3*i+1 : 3*i] ; \
assign liteIface.ARVALID = xbarIface.ARVALID[i] ; \
assign xbarIface.ARREADY[i] = liteIface.ARREADY ; \
assign xbarIface.RDATA[(i+1)*(A_DATA_WIDTH-1) : A_DATA_WIDTH*i] = liteIface.RDATA ; \
assign xbarIface.RRESP[2*i+1 : 2*i] = liteIface.RRESP ; \
assign xbarIface.RVALID[i] = liteIface.RVALID ; \
assign liteIface.RREADY = xbarIface.RREADY[i] ; \
end
endpackage : axiutils
然后包含包并像这样使用
import axiutils::*;
xbarRegIface xbarReg;
axiLiteIface bus1, bus2, bus3;
`xbarData(bus1, xbarReg, 0);
`xbarData(bus2, xbarReg, 1);
`xbarData(bus3, xbarReg, 2);