From f03fe4246f55adf0acf148989c5e3d1fc97ed9da Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 16 Jul 2024 17:56:51 +0200 Subject: [PATCH] axi_sim_mem: Increase number of ports --- src/axi_sim_mem.sv | 468 +++++++++++++++++++++++---------------------- 1 file changed, 238 insertions(+), 230 deletions(-) diff --git a/src/axi_sim_mem.sv b/src/axi_sim_mem.sv index 564cfc9da..bdc74715c 100644 --- a/src/axi_sim_mem.sv +++ b/src/axi_sim_mem.sv @@ -33,6 +33,8 @@ module axi_sim_mem #( parameter int unsigned IdWidth = 32'd0, /// AXI User Width. parameter int unsigned UserWidth = 32'd0, + /// Number of request ports + parameter int unsigned NumPorts = 32'd1, /// AXI4 request struct definition parameter type axi_req_t = logic, /// AXI4 response struct definition @@ -53,41 +55,41 @@ module axi_sim_mem #( /// Active-low reset input logic rst_ni, /// AXI4 request struct - input axi_req_t axi_req_i, + input axi_req_t [NumPorts-1:0] axi_req_i, /// AXI4 response struct - output axi_rsp_t axi_rsp_o, + output axi_rsp_t [NumPorts-1:0] axi_rsp_o, /// Memory monitor write valid. All `mon_w_*` outputs are only valid if this signal is high. /// A write to the memory is visible on the `mon_w_*` outputs in the clock cycle after it has /// happened. - output logic mon_w_valid_o, + output logic [NumPorts-1:0] mon_w_valid_o, /// Memory monitor write address - output logic [AddrWidth-1:0] mon_w_addr_o, + output logic [NumPorts-1:0][AddrWidth-1:0] mon_w_addr_o, /// Memory monitor write data - output logic [DataWidth-1:0] mon_w_data_o, + output logic [NumPorts-1:0][DataWidth-1:0] mon_w_data_o, /// Memory monitor write ID - output logic [IdWidth-1:0] mon_w_id_o, + output logic [NumPorts-1:0][IdWidth-1:0] mon_w_id_o, /// Memory monitor write user - output logic [UserWidth-1:0] mon_w_user_o, + output logic [NumPorts-1:0][UserWidth-1:0] mon_w_user_o, /// Memory monitor write beat count - output axi_pkg::len_t mon_w_beat_count_o, + output axi_pkg::len_t [NumPorts-1:0] mon_w_beat_count_o, /// Memory monitor write last - output logic mon_w_last_o, + output logic [NumPorts-1:0] mon_w_last_o, /// Memory monitor read valid. All `mon_r_*` outputs are only valid if this signal is high. /// A read from the memory is visible on the `mon_w_*` outputs in the clock cycle after it has /// happened. - output logic mon_r_valid_o, + output logic [NumPorts-1:0] mon_r_valid_o, /// Memory monitor read address - output logic [AddrWidth-1:0] mon_r_addr_o, + output logic [NumPorts-1:0][AddrWidth-1:0] mon_r_addr_o, /// Memory monitor read data - output logic [DataWidth-1:0] mon_r_data_o, + output logic [NumPorts-1:0][DataWidth-1:0] mon_r_data_o, /// Memory monitor read ID - output logic [IdWidth-1:0] mon_r_id_o, + output logic [NumPorts-1:0][IdWidth-1:0] mon_r_id_o, /// Memory monitor read user - output logic [UserWidth-1:0] mon_r_user_o, + output logic [NumPorts-1:0][UserWidth-1:0] mon_r_user_o, /// Memory monitor read beat count - output axi_pkg::len_t mon_r_beat_count_o, + output axi_pkg::len_t [NumPorts-1:0] mon_r_beat_count_o, /// Memory monitor read last - output logic mon_r_last_o + output logic [NumPorts-1:0] mon_r_last_o ); localparam int unsigned StrbWidth = DataWidth / 8; @@ -112,222 +114,224 @@ module axi_sim_mem #( logic last; } monitor_t; - monitor_t mon_w, mon_r; + monitor_t [NumPorts-1:0] mon_w, mon_r; logic [7:0] mem[addr_t]; axi_pkg::resp_t rerr[addr_t] = '{default: axi_pkg::RESP_OKAY}; axi_pkg::resp_t werr[addr_t] = '{default: axi_pkg::RESP_OKAY}; // error happened in write burst - axi_pkg::resp_t error_happened = axi_pkg::RESP_OKAY; + axi_pkg::resp_t [NumPorts-1:0] error_happened = axi_pkg::RESP_OKAY; - initial begin - automatic ar_t ar_queue[$]; - automatic aw_t aw_queue[$]; - automatic b_t b_queue[$]; - automatic shortint unsigned r_cnt = 0, w_cnt = 0; - axi_rsp_o = '0; - // Monitor interface - mon_w = '0; - mon_r = '0; - wait (rst_ni); - fork - // AW - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.aw_ready = 1'b1; - #(AcqDelay - ApplDelay); - if (axi_req_i.aw_valid) begin - automatic aw_t aw = axi_req_i.aw; - aw_queue.push_back(aw); - end - end - // W - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.w_ready = 1'b0; - mon_w = '0; - if (aw_queue.size() != 0) begin - axi_rsp_o.w_ready = 1'b1; + for (genvar i = 0; i < NumPorts; i++) begin + initial begin + automatic ar_t ar_queue[$]; + automatic aw_t aw_queue[$]; + automatic b_t b_queue[$]; + automatic shortint unsigned r_cnt = 0, w_cnt = 0; + axi_rsp_o[i] = '0; + // Monitor interface + mon_w[i] = '0; + mon_r[i] = '0; + wait (rst_ni); + fork + // AW + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].aw_ready = 1'b1; #(AcqDelay - ApplDelay); - if (axi_req_i.w_valid) begin - automatic axi_pkg::burst_t burst = aw_queue[0].burst; - automatic axi_pkg::len_t len = aw_queue[0].len; - automatic axi_pkg::size_t size = aw_queue[0].size; - automatic addr_t addr = axi_pkg::beat_addr(aw_queue[0].addr, size, len, burst, - w_cnt); - mon_w.valid = 1'b1; - mon_w.addr = addr; - mon_w.data = axi_req_i.w.data; - mon_w.id = aw_queue[0].id; - mon_w.user = aw_queue[0].user; - mon_w.beat_count = w_cnt; - for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); - i_byte <= axi_pkg::beat_upper_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); - i_byte++) begin - if (axi_req_i.w.strb[i_byte]) begin - automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; - mem[byte_addr] = axi_req_i.w.data[i_byte*8+:8]; - error_happened = axi_pkg::resp_precedence(werr[byte_addr], error_happened); - if (ClearErrOnAccess) - werr[byte_addr] = axi_pkg::RESP_OKAY; + if (axi_req_i[i].aw_valid) begin + automatic aw_t aw = axi_req_i[i].aw; + aw_queue.push_back(aw); + end + end + // W + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].w_ready = 1'b0; + mon_w[i] = '0; + if (aw_queue.size() != 0) begin + axi_rsp_o[i].w_ready = 1'b1; + #(AcqDelay - ApplDelay); + if (axi_req_i[i].w_valid) begin + automatic axi_pkg::burst_t burst = aw_queue[0].burst; + automatic axi_pkg::len_t len = aw_queue[0].len; + automatic axi_pkg::size_t size = aw_queue[0].size; + automatic addr_t addr = axi_pkg::beat_addr(aw_queue[0].addr, size, len, burst, + w_cnt); + mon_w[i].valid = 1'b1; + mon_w[i].addr = addr; + mon_w[i].data = axi_req_i[i].w.data; + mon_w[i].id = aw_queue[0].id; + mon_w[i].user = aw_queue[0].user; + mon_w[i].beat_count = w_cnt; + for (shortint unsigned + i_byte = axi_pkg::beat_lower_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); + i_byte <= axi_pkg::beat_upper_byte(aw_queue[0].addr, size, len, burst, StrbWidth, w_cnt); + i_byte++) begin + if (axi_req_i[i].w.strb[i_byte]) begin + automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; + mem[byte_addr] = axi_req_i[i].w.data[i_byte*8+:8]; + error_happened[i] = axi_pkg::resp_precedence(werr[byte_addr], error_happened[i]); + if (ClearErrOnAccess) + werr[byte_addr] = axi_pkg::RESP_OKAY; + end + end + if (w_cnt == aw_queue[0].len) begin + automatic b_t b_beat = '0; + assert (axi_req_i[i].w.last) else $error("Expected last beat of W burst!"); + b_beat.id = aw_queue[0].id; + b_beat.resp = error_happened[i]; + b_queue.push_back(b_beat); + w_cnt = 0; + mon_w[i].last = 1'b1; + error_happened[i] = axi_pkg::RESP_OKAY; + void'(aw_queue.pop_front()); + end else begin + assert (!axi_req_i[i].w.last) else $error("Did not expect last beat of W burst!"); + w_cnt++; end end - if (w_cnt == aw_queue[0].len) begin - automatic b_t b_beat = '0; - assert (axi_req_i.w.last) else $error("Expected last beat of W burst!"); - b_beat.id = aw_queue[0].id; - b_beat.resp = error_happened; - b_queue.push_back(b_beat); - w_cnt = 0; - mon_w.last = 1'b1; - error_happened = axi_pkg::RESP_OKAY; - void'(aw_queue.pop_front()); - end else begin - assert (!axi_req_i.w.last) else $error("Did not expect last beat of W burst!"); - w_cnt++; + end + end + // B + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].b_valid = 1'b0; + if (b_queue.size() != 0) begin + axi_rsp_o[i].b = b_queue[0]; + axi_rsp_o[i].b_valid = 1'b1; + #(AcqDelay - ApplDelay); + if (axi_req_i[i].b_ready) begin + void'(b_queue.pop_front()); end end end - end - // B - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.b_valid = 1'b0; - if (b_queue.size() != 0) begin - axi_rsp_o.b = b_queue[0]; - axi_rsp_o.b_valid = 1'b1; + // AR + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].ar_ready = 1'b1; #(AcqDelay - ApplDelay); - if (axi_req_i.b_ready) begin - void'(b_queue.pop_front()); + if (axi_req_i[i].ar_valid) begin + automatic ar_t ar = axi_req_i[i].ar; + ar_queue.push_back(ar); end end - end - // AR - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.ar_ready = 1'b1; - #(AcqDelay - ApplDelay); - if (axi_req_i.ar_valid) begin - automatic ar_t ar = axi_req_i.ar; - ar_queue.push_back(ar); - end - end - // R - forever begin - @(posedge clk_i); - #(ApplDelay); - axi_rsp_o.r_valid = 1'b0; - mon_r = '0; - if (ar_queue.size() != 0) begin - automatic axi_pkg::burst_t burst = ar_queue[0].burst; - automatic axi_pkg::len_t len = ar_queue[0].len; - automatic axi_pkg::size_t size = ar_queue[0].size; - automatic addr_t addr = axi_pkg::beat_addr(ar_queue[0].addr, size, len, burst, r_cnt); - automatic r_t r_beat = '0; - automatic data_t r_data = 'x; // compatibility reasons - r_beat.data = 'x; - r_beat.id = ar_queue[0].id; - r_beat.resp = axi_pkg::RESP_OKAY; - for (shortint unsigned - i_byte = axi_pkg::beat_lower_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); - i_byte <= axi_pkg::beat_upper_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); - i_byte++) begin - automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; - if (!mem.exists(byte_addr)) begin - if (WarnUninitialized) begin - $warning("Access to non-initialized byte at address 0x%016x by ID 0x%x.", byte_addr, - r_beat.id); + // R + forever begin + @(posedge clk_i); + #(ApplDelay); + axi_rsp_o[i].r_valid = 1'b0; + mon_r[i] = '0; + if (ar_queue.size() != 0) begin + automatic axi_pkg::burst_t burst = ar_queue[0].burst; + automatic axi_pkg::len_t len = ar_queue[0].len; + automatic axi_pkg::size_t size = ar_queue[0].size; + automatic addr_t addr = axi_pkg::beat_addr(ar_queue[0].addr, size, len, burst, r_cnt); + automatic r_t r_beat = '0; + automatic data_t r_data = 'x; // compatibility reasons + r_beat.data = 'x; + r_beat.id = ar_queue[0].id; + r_beat.resp = axi_pkg::RESP_OKAY; + for (shortint unsigned + i_byte = axi_pkg::beat_lower_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); + i_byte <= axi_pkg::beat_upper_byte(ar_queue[0].addr, size, len, burst, StrbWidth, r_cnt); + i_byte++) begin + automatic addr_t byte_addr = (addr / StrbWidth) * StrbWidth + i_byte; + if (!mem.exists(byte_addr)) begin + if (WarnUninitialized) begin + $warning("Access to non-initialized byte at address 0x%016x by ID 0x%x.", byte_addr, + r_beat.id); + end + case (UninitializedData) + "random": + r_data[i_byte*8+:8] = $urandom; + "ones": + r_data[i_byte*8+:8] = '1; + "zeros": + r_data[i_byte*8+:8] = '0; + default: + r_data[i_byte*8+:8] = 'x; + endcase + end else begin + r_data[i_byte*8+:8] = mem[byte_addr]; + end + r_beat.resp = axi_pkg::resp_precedence(rerr[byte_addr], r_beat.resp); + if (ClearErrOnAccess & axi_req_i[i].r_ready) begin + rerr[byte_addr] = axi_pkg::RESP_OKAY; end - case (UninitializedData) - "random": - r_data[i_byte*8+:8] = $urandom; - "ones": - r_data[i_byte*8+:8] = '1; - "zeros": - r_data[i_byte*8+:8] = '0; - default: - r_data[i_byte*8+:8] = 'x; - endcase - end else begin - r_data[i_byte*8+:8] = mem[byte_addr]; end - r_beat.resp = axi_pkg::resp_precedence(rerr[byte_addr], r_beat.resp); - if (ClearErrOnAccess & axi_req_i.r_ready) begin - rerr[byte_addr] = axi_pkg::RESP_OKAY; + r_beat.data = r_data; + if (r_cnt == ar_queue[0].len) begin + r_beat.last = 1'b1; + mon_r[i].last = 1'b1; + end + axi_rsp_o[i].r = r_beat; + axi_rsp_o[i].r_valid = 1'b1; + mon_r[i].valid = 1'b1; + mon_r[i].addr = addr; + mon_r[i].data = r_beat.data; + mon_r[i].id = r_beat.id; + mon_r[i].user = ar_queue[0].user; + mon_r[i].beat_count = r_cnt; + #(AcqDelay - ApplDelay); + while (!axi_req_i[i].r_ready) begin + @(posedge clk_i); + #(AcqDelay); + mon_r[i] = '0; + end + if (r_beat.last) begin + r_cnt = 0; + void'(ar_queue.pop_front()); + end else begin + r_cnt++; end - end - r_beat.data = r_data; - if (r_cnt == ar_queue[0].len) begin - r_beat.last = 1'b1; - mon_r.last = 1'b1; - end - axi_rsp_o.r = r_beat; - axi_rsp_o.r_valid = 1'b1; - mon_r.valid = 1'b1; - mon_r.addr = addr; - mon_r.data = r_beat.data; - mon_r.id = r_beat.id; - mon_r.user = ar_queue[0].user; - mon_r.beat_count = r_cnt; - #(AcqDelay - ApplDelay); - while (!axi_req_i.r_ready) begin - @(posedge clk_i); - #(AcqDelay); - mon_r = '0; - end - if (r_beat.last) begin - r_cnt = 0; - void'(ar_queue.pop_front()); - end else begin - r_cnt++; end end - end - join - end + join + end - // Assign the monitor output in the next clock cycle. Rationale: We only know whether we are - // writing until after `AcqDelay`. This means we could only provide the monitoring output for - // writes after `AcqDelay` in the same cycle, which is incompatible with ATI timing. Thus, we - // provide the monitoring output for writes (and for uniformity also for reads) in the next clock - // cycle. - initial begin - mon_w_valid_o = '0; - mon_w_addr_o = '0; - mon_w_data_o = '0; - mon_w_id_o = '0; - mon_w_user_o = '0; - mon_w_beat_count_o = '0; - mon_w_last_o = '0; - mon_r_valid_o = '0; - mon_r_addr_o = '0; - mon_r_data_o = '0; - mon_r_id_o = '0; - mon_r_user_o = '0; - mon_r_beat_count_o = '0; - mon_r_last_o = '0; - wait (rst_ni); - forever begin - @(posedge clk_i); - mon_w_valid_o <= #(ApplDelay) mon_w.valid; - mon_w_addr_o <= #(ApplDelay) mon_w.addr; - mon_w_data_o <= #(ApplDelay) mon_w.data; - mon_w_id_o <= #(ApplDelay) mon_w.id; - mon_w_user_o <= #(ApplDelay) mon_w.user; - mon_w_beat_count_o <= #(ApplDelay) mon_w.beat_count; - mon_w_last_o <= #(ApplDelay) mon_w.last; - mon_r_valid_o <= #(ApplDelay) mon_r.valid; - mon_r_addr_o <= #(ApplDelay) mon_r.addr; - mon_r_data_o <= #(ApplDelay) mon_r.data; - mon_r_id_o <= #(ApplDelay) mon_r.id; - mon_r_user_o <= #(ApplDelay) mon_r.user; - mon_r_beat_count_o <= #(ApplDelay) mon_r.beat_count; - mon_r_last_o <= #(ApplDelay) mon_r.last; + // Assign the monitor output in the next clock cycle. Rationale: We only know whether we are + // writing until after `AcqDelay`. This means we could only provide the monitoring output for + // writes after `AcqDelay` in the same cycle, which is incompatible with ATI timing. Thus, we + // provide the monitoring output for writes (and for uniformity also for reads) in the next clock + // cycle. + initial begin + mon_w_valid_o[i] = '0; + mon_w_addr_o[i] = '0; + mon_w_data_o[i] = '0; + mon_w_id_o[i] = '0; + mon_w_user_o[i] = '0; + mon_w_beat_count_o[i] = '0; + mon_w_last_o[i] = '0; + mon_r_valid_o[i] = '0; + mon_r_addr_o[i] = '0; + mon_r_data_o[i] = '0; + mon_r_id_o[i] = '0; + mon_r_user_o[i] = '0; + mon_r_beat_count_o[i] = '0; + mon_r_last_o[i] = '0; + wait (rst_ni); + forever begin + @(posedge clk_i); + mon_w_valid_o[i] <= #(ApplDelay) mon_w[i].valid; + mon_w_addr_o[i] <= #(ApplDelay) mon_w[i].addr; + mon_w_data_o[i] <= #(ApplDelay) mon_w[i].data; + mon_w_id_o[i] <= #(ApplDelay) mon_w[i].id; + mon_w_user_o[i] <= #(ApplDelay) mon_w[i].user; + mon_w_beat_count_o[i] <= #(ApplDelay) mon_w[i].beat_count; + mon_w_last_o[i] <= #(ApplDelay) mon_w[i].last; + mon_r_valid_o[i] <= #(ApplDelay) mon_r[i].valid; + mon_r_addr_o[i] <= #(ApplDelay) mon_r[i].addr; + mon_r_data_o[i] <= #(ApplDelay) mon_r[i].data; + mon_r_id_o[i] <= #(ApplDelay) mon_r[i].id; + mon_r_user_o[i] <= #(ApplDelay) mon_r[i].user; + mon_r_beat_count_o[i] <= #(ApplDelay) mon_r[i].beat_count; + mon_r_last_o[i] <= #(ApplDelay) mon_r[i].last; + end end end @@ -352,6 +356,7 @@ module axi_sim_mem_intf #( parameter int unsigned AXI_DATA_WIDTH = 32'd0, parameter int unsigned AXI_ID_WIDTH = 32'd0, parameter int unsigned AXI_USER_WIDTH = 32'd0, + parameter int unsigned NUM_PORTS = 32'd1, parameter bit WARN_UNINITIALIZED = 1'b0, parameter UNINITIALIZED_DATA = "undefined", parameter bit ClearErrOnAccess = 1'b0, @@ -360,21 +365,21 @@ module axi_sim_mem_intf #( ) ( input logic clk_i, input logic rst_ni, - AXI_BUS.Slave axi_slv, - output logic mon_w_valid_o, - output logic [AXI_ADDR_WIDTH-1:0] mon_w_addr_o, - output logic [AXI_DATA_WIDTH-1:0] mon_w_data_o, - output logic [AXI_ID_WIDTH-1:0] mon_w_id_o, - output logic [AXI_USER_WIDTH-1:0] mon_w_user_o, - output axi_pkg::len_t mon_w_beat_count_o, - output logic mon_w_last_o, - output logic mon_r_valid_o, - output logic [AXI_ADDR_WIDTH-1:0] mon_r_addr_o, - output logic [AXI_DATA_WIDTH-1:0] mon_r_data_o, - output logic [AXI_ID_WIDTH-1:0] mon_r_id_o, - output logic [AXI_USER_WIDTH-1:0] mon_r_user_o, - output axi_pkg::len_t mon_r_beat_count_o, - output logic mon_r_last_o + AXI_BUS.Slave axi_slv[NUM_PORTS], + output logic [NUM_PORTS-1:0] mon_w_valid_o, + output logic [NUM_PORTS-1:0][AXI_ADDR_WIDTH-1:0] mon_w_addr_o, + output logic [NUM_PORTS-1:0][AXI_DATA_WIDTH-1:0] mon_w_data_o, + output logic [NUM_PORTS-1:0][AXI_ID_WIDTH-1:0] mon_w_id_o, + output logic [NUM_PORTS-1:0][AXI_USER_WIDTH-1:0] mon_w_user_o, + output axi_pkg::len_t [NUM_PORTS-1:0] mon_w_beat_count_o, + output logic [NUM_PORTS-1:0] mon_w_last_o, + output logic [NUM_PORTS-1:0] mon_r_valid_o, + output logic [NUM_PORTS-1:0][AXI_ADDR_WIDTH-1:0] mon_r_addr_o, + output logic [NUM_PORTS-1:0][AXI_DATA_WIDTH-1:0] mon_r_data_o, + output logic [NUM_PORTS-1:0][AXI_ID_WIDTH-1:0] mon_r_id_o, + output logic [NUM_PORTS-1:0][AXI_USER_WIDTH-1:0] mon_r_user_o, + output axi_pkg::len_t [NUM_PORTS-1:0] mon_r_beat_count_o, + output logic [NUM_PORTS-1:0] mon_r_last_o ); typedef logic [AXI_ADDR_WIDTH-1:0] axi_addr_t; @@ -384,17 +389,20 @@ module axi_sim_mem_intf #( typedef logic [AXI_USER_WIDTH-1:0] axi_user_t; `AXI_TYPEDEF_ALL(axi, axi_addr_t, axi_id_t, axi_data_t, axi_strb_t, axi_user_t) - axi_req_t axi_req; - axi_resp_t axi_rsp; + axi_req_t [NUM_PORTS-1:0] axi_req; + axi_resp_t [NUM_PORTS-1:0] axi_rsp; - `AXI_ASSIGN_TO_REQ(axi_req, axi_slv) - `AXI_ASSIGN_FROM_RESP(axi_slv, axi_rsp) + for (genvar i = 0; i < NUM_PORTS; i++) begin + `AXI_ASSIGN_TO_REQ(axi_req[i], axi_slv[i]) + `AXI_ASSIGN_FROM_RESP(axi_slv[i], axi_rsp[i]) + end axi_sim_mem #( .AddrWidth (AXI_ADDR_WIDTH), .DataWidth (AXI_DATA_WIDTH), .IdWidth (AXI_ID_WIDTH), .UserWidth (AXI_USER_WIDTH), + .NumPorts (NUM_PORTS), .axi_req_t (axi_req_t), .axi_rsp_t (axi_resp_t), .WarnUninitialized (WARN_UNINITIALIZED),