413 lines
13 KiB
Systemverilog
413 lines
13 KiB
Systemverilog
// Copyright © 2019-2023
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
`include "vortex_afu.vh"
|
|
|
|
module VX_afu_wrap #(
|
|
parameter C_S_AXI_CTRL_ADDR_WIDTH = 8,
|
|
parameter C_S_AXI_CTRL_DATA_WIDTH = 32,
|
|
parameter C_M_AXI_MEM_ID_WIDTH = 16,
|
|
parameter C_M_AXI_MEM_ADDR_WIDTH = 32,
|
|
parameter C_M_AXI_MEM_DATA_WIDTH = 512
|
|
) (
|
|
// System signals
|
|
input wire ap_clk,
|
|
input wire ap_rst_n,
|
|
|
|
// AXI4 master interface
|
|
`REPEAT (`M_AXI_MEM_NUM_BANKS, GEN_AXI_MEM, REPEAT_COMMA),
|
|
|
|
// AXI4-Lite slave interface
|
|
input wire s_axi_ctrl_awvalid,
|
|
output wire s_axi_ctrl_awready,
|
|
input wire [C_S_AXI_CTRL_ADDR_WIDTH-1:0] s_axi_ctrl_awaddr,
|
|
input wire s_axi_ctrl_wvalid,
|
|
output wire s_axi_ctrl_wready,
|
|
input wire [C_S_AXI_CTRL_DATA_WIDTH-1:0] s_axi_ctrl_wdata,
|
|
input wire [C_S_AXI_CTRL_DATA_WIDTH/8-1:0] s_axi_ctrl_wstrb,
|
|
input wire s_axi_ctrl_arvalid,
|
|
output wire s_axi_ctrl_arready,
|
|
input wire [C_S_AXI_CTRL_ADDR_WIDTH-1:0] s_axi_ctrl_araddr,
|
|
output wire s_axi_ctrl_rvalid,
|
|
input wire s_axi_ctrl_rready,
|
|
output wire [C_S_AXI_CTRL_DATA_WIDTH-1:0] s_axi_ctrl_rdata,
|
|
output wire [1:0] s_axi_ctrl_rresp,
|
|
output wire s_axi_ctrl_bvalid,
|
|
input wire s_axi_ctrl_bready,
|
|
output wire [1:0] s_axi_ctrl_bresp,
|
|
|
|
output wire interrupt
|
|
);
|
|
localparam C_M_AXI_MEM_NUM_BANKS = `M_AXI_MEM_NUM_BANKS;
|
|
|
|
localparam STATE_IDLE = 0;
|
|
localparam STATE_RUN = 1;
|
|
|
|
wire m_axi_mem_awvalid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_awready_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ADDR_WIDTH-1:0] m_axi_mem_awaddr_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ID_WIDTH-1:0] m_axi_mem_awid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [7:0] m_axi_mem_awlen_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_wvalid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_wready_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_DATA_WIDTH-1:0] m_axi_mem_wdata_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_DATA_WIDTH/8-1:0] m_axi_mem_wstrb_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_wlast_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_bvalid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_bready_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ID_WIDTH-1:0] m_axi_mem_bid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [1:0] m_axi_mem_bresp_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_arvalid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_arready_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ADDR_WIDTH-1:0] m_axi_mem_araddr_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ID_WIDTH-1:0] m_axi_mem_arid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [7:0] m_axi_mem_arlen_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_rvalid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_rready_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_DATA_WIDTH-1:0] m_axi_mem_rdata_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire m_axi_mem_rlast_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [C_M_AXI_MEM_ID_WIDTH-1:0] m_axi_mem_rid_a [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [1:0] m_axi_mem_rresp_a [C_M_AXI_MEM_NUM_BANKS];
|
|
|
|
// convert memory interface to array
|
|
`REPEAT (`M_AXI_MEM_NUM_BANKS, AXI_MEM_TO_ARRAY, REPEAT_SEMICOLON);
|
|
|
|
wire clk = ap_clk;
|
|
wire reset = ~ap_rst_n;
|
|
|
|
reg [`CLOG2(`RESET_DELAY+1)-1:0] vx_reset_ctr;
|
|
reg [15:0] vx_pending_writes;
|
|
reg vx_busy_wait;
|
|
reg vx_running;
|
|
|
|
wire vx_busy;
|
|
|
|
wire [63:0] mem_base [C_M_AXI_MEM_NUM_BANKS];
|
|
|
|
wire dcr_wr_valid;
|
|
wire [`VX_DCR_ADDR_WIDTH-1:0] dcr_wr_addr;
|
|
wire [`VX_DCR_DATA_WIDTH-1:0] dcr_wr_data;
|
|
|
|
reg state;
|
|
|
|
wire ap_reset;
|
|
wire ap_start;
|
|
wire ap_idle = ~vx_running;
|
|
wire ap_done = ~(state == STATE_RUN || vx_pending_writes != 0);
|
|
wire ap_ready = 1'b1;
|
|
|
|
`ifdef SCOPE
|
|
wire scope_bus_in;
|
|
wire scope_bus_out;
|
|
wire scope_reset = reset;
|
|
`endif
|
|
|
|
always @(posedge ap_clk) begin
|
|
if (reset || ap_reset) begin
|
|
state <= STATE_IDLE;
|
|
vx_busy_wait <= 0;
|
|
vx_running <= 0;
|
|
end else begin
|
|
case (state)
|
|
STATE_IDLE: begin
|
|
if (ap_start) begin
|
|
`ifdef DBG_TRACE_AFU
|
|
`TRACE(2, ("%d: STATE RUN\n", $time));
|
|
`endif
|
|
state <= STATE_RUN;
|
|
vx_running <= 0;
|
|
end
|
|
end
|
|
STATE_RUN: begin
|
|
if (vx_running) begin
|
|
if (vx_busy_wait) begin
|
|
// wait until processor goes busy
|
|
if (vx_busy) begin
|
|
vx_busy_wait <= 0;
|
|
end
|
|
end else begin
|
|
// wait until the processor is not busy
|
|
if (~vx_busy) begin
|
|
state <= STATE_IDLE;
|
|
`ifdef DBG_TRACE_AFU
|
|
`TRACE(2, ("%d: AFU: End execution\n", $time));
|
|
`TRACE(2, ("%d: STATE IDLE\n", $time));
|
|
`endif
|
|
end
|
|
end
|
|
end else begin
|
|
// wait until the reset sequence is complete
|
|
if (vx_reset_ctr == (`RESET_DELAY-1)) begin
|
|
`ifdef DBG_TRACE_AFU
|
|
`TRACE(2, ("%d: AFU: Begin execution\n", $time));
|
|
`endif
|
|
vx_running <= 1;
|
|
vx_busy_wait <= 1;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
reg m_axi_mem_wfire;
|
|
reg m_axi_mem_bfire;
|
|
|
|
always @(*) begin
|
|
m_axi_mem_wfire = 0;
|
|
m_axi_mem_bfire = 0;
|
|
for (integer i = 0; i < C_M_AXI_MEM_NUM_BANKS; ++i) begin
|
|
m_axi_mem_wfire |= m_axi_mem_wvalid_a[i] && m_axi_mem_wready_a[i];
|
|
m_axi_mem_bfire |= m_axi_mem_bvalid_a[i] && m_axi_mem_bready_a[i];
|
|
end
|
|
end
|
|
|
|
always @(posedge ap_clk) begin
|
|
if (reset || ap_reset) begin
|
|
vx_pending_writes <= '0;
|
|
end else begin
|
|
if (m_axi_mem_wfire && ~m_axi_mem_bfire)
|
|
vx_pending_writes <= vx_pending_writes + 1;
|
|
if (~m_axi_mem_wfire && m_axi_mem_bfire)
|
|
vx_pending_writes <= vx_pending_writes - 1;
|
|
end
|
|
end
|
|
|
|
always @(posedge ap_clk) begin
|
|
if (state == STATE_RUN) begin
|
|
vx_reset_ctr <= vx_reset_ctr + 1;
|
|
end else begin
|
|
vx_reset_ctr <= '0;
|
|
end
|
|
end
|
|
|
|
VX_afu_ctrl #(
|
|
.AXI_ADDR_WIDTH (C_S_AXI_CTRL_ADDR_WIDTH),
|
|
.AXI_DATA_WIDTH (C_S_AXI_CTRL_DATA_WIDTH),
|
|
.AXI_NUM_BANKS (C_M_AXI_MEM_NUM_BANKS)
|
|
) afu_ctrl (
|
|
.clk (ap_clk),
|
|
.reset (reset || ap_reset),
|
|
.clk_en (1'b1),
|
|
|
|
.s_axi_awvalid (s_axi_ctrl_awvalid),
|
|
.s_axi_awready (s_axi_ctrl_awready),
|
|
.s_axi_awaddr (s_axi_ctrl_awaddr),
|
|
.s_axi_wvalid (s_axi_ctrl_wvalid),
|
|
.s_axi_wready (s_axi_ctrl_wready),
|
|
.s_axi_wdata (s_axi_ctrl_wdata),
|
|
.s_axi_wstrb (s_axi_ctrl_wstrb),
|
|
.s_axi_arvalid (s_axi_ctrl_arvalid),
|
|
.s_axi_arready (s_axi_ctrl_arready),
|
|
.s_axi_araddr (s_axi_ctrl_araddr),
|
|
.s_axi_rvalid (s_axi_ctrl_rvalid),
|
|
.s_axi_rready (s_axi_ctrl_rready),
|
|
.s_axi_rdata (s_axi_ctrl_rdata),
|
|
.s_axi_rresp (s_axi_ctrl_rresp),
|
|
.s_axi_bvalid (s_axi_ctrl_bvalid),
|
|
.s_axi_bready (s_axi_ctrl_bready),
|
|
.s_axi_bresp (s_axi_ctrl_bresp),
|
|
|
|
.ap_reset (ap_reset),
|
|
.ap_start (ap_start),
|
|
.ap_done (ap_done),
|
|
.ap_ready (ap_ready),
|
|
.ap_idle (ap_idle),
|
|
.interrupt (interrupt),
|
|
|
|
`ifdef SCOPE
|
|
.scope_bus_in (scope_bus_out),
|
|
.scope_bus_out (scope_bus_in),
|
|
`endif
|
|
|
|
.mem_base (mem_base),
|
|
|
|
.dcr_wr_valid (dcr_wr_valid),
|
|
.dcr_wr_addr (dcr_wr_addr),
|
|
.dcr_wr_data (dcr_wr_data)
|
|
);
|
|
|
|
wire [`XLEN-1:0] m_axi_mem_awaddr_w [C_M_AXI_MEM_NUM_BANKS];
|
|
wire [`XLEN-1:0] m_axi_mem_araddr_w [C_M_AXI_MEM_NUM_BANKS];
|
|
|
|
for (genvar i = 0; i < C_M_AXI_MEM_NUM_BANKS; ++i) begin
|
|
assign m_axi_mem_awaddr_a[i] = C_M_AXI_MEM_ADDR_WIDTH'(m_axi_mem_awaddr_w[i]) + C_M_AXI_MEM_ADDR_WIDTH'(mem_base[i]);
|
|
assign m_axi_mem_araddr_a[i] = C_M_AXI_MEM_ADDR_WIDTH'(m_axi_mem_araddr_w[i]) + C_M_AXI_MEM_ADDR_WIDTH'(mem_base[i]);
|
|
end
|
|
|
|
`SCOPE_IO_SWITCH (2)
|
|
|
|
Vortex_axi #(
|
|
.AXI_DATA_WIDTH (C_M_AXI_MEM_DATA_WIDTH),
|
|
.AXI_ADDR_WIDTH (`XLEN),
|
|
.AXI_TID_WIDTH (C_M_AXI_MEM_ID_WIDTH),
|
|
.AXI_NUM_BANKS (C_M_AXI_MEM_NUM_BANKS)
|
|
) vortex_axi (
|
|
`SCOPE_IO_BIND (1)
|
|
|
|
.clk (ap_clk),
|
|
.reset (reset || ap_reset || ~vx_running),
|
|
|
|
.m_axi_awvalid (m_axi_mem_awvalid_a),
|
|
.m_axi_awready (m_axi_mem_awready_a),
|
|
.m_axi_awaddr (m_axi_mem_awaddr_w),
|
|
.m_axi_awid (m_axi_mem_awid_a),
|
|
.m_axi_awlen (m_axi_mem_awlen_a),
|
|
`UNUSED_PIN (m_axi_awsize),
|
|
`UNUSED_PIN (m_axi_awburst),
|
|
`UNUSED_PIN (m_axi_awlock),
|
|
`UNUSED_PIN (m_axi_awcache),
|
|
`UNUSED_PIN (m_axi_awprot),
|
|
`UNUSED_PIN (m_axi_awqos),
|
|
`UNUSED_PIN (m_axi_awregion),
|
|
|
|
.m_axi_wvalid (m_axi_mem_wvalid_a),
|
|
.m_axi_wready (m_axi_mem_wready_a),
|
|
.m_axi_wdata (m_axi_mem_wdata_a),
|
|
.m_axi_wstrb (m_axi_mem_wstrb_a),
|
|
.m_axi_wlast (m_axi_mem_wlast_a),
|
|
|
|
.m_axi_bvalid (m_axi_mem_bvalid_a),
|
|
.m_axi_bready (m_axi_mem_bready_a),
|
|
.m_axi_bid (m_axi_mem_bid_a),
|
|
.m_axi_bresp (m_axi_mem_bresp_a),
|
|
|
|
.m_axi_arvalid (m_axi_mem_arvalid_a),
|
|
.m_axi_arready (m_axi_mem_arready_a),
|
|
.m_axi_araddr (m_axi_mem_araddr_w),
|
|
.m_axi_arid (m_axi_mem_arid_a),
|
|
.m_axi_arlen (m_axi_mem_arlen_a),
|
|
`UNUSED_PIN (m_axi_arsize),
|
|
`UNUSED_PIN (m_axi_arburst),
|
|
`UNUSED_PIN (m_axi_arlock),
|
|
`UNUSED_PIN (m_axi_arcache),
|
|
`UNUSED_PIN (m_axi_arprot),
|
|
`UNUSED_PIN (m_axi_arqos),
|
|
`UNUSED_PIN (m_axi_arregion),
|
|
|
|
.m_axi_rvalid (m_axi_mem_rvalid_a),
|
|
.m_axi_rready (m_axi_mem_rready_a),
|
|
.m_axi_rdata (m_axi_mem_rdata_a),
|
|
.m_axi_rlast (m_axi_mem_rlast_a),
|
|
.m_axi_rid (m_axi_mem_rid_a),
|
|
.m_axi_rresp (m_axi_mem_rresp_a),
|
|
|
|
.dcr_wr_valid (dcr_wr_valid),
|
|
.dcr_wr_addr (dcr_wr_addr),
|
|
.dcr_wr_data (dcr_wr_data),
|
|
|
|
.busy (vx_busy)
|
|
);
|
|
|
|
// SCOPE //////////////////////////////////////////////////////////////////////
|
|
|
|
`ifdef DBG_SCOPE_AFU
|
|
`ifdef SCOPE
|
|
`define TRIGGERS { \
|
|
reset, \
|
|
ap_start, \
|
|
ap_done, \
|
|
ap_idle, \
|
|
interrupt, \
|
|
vx_busy_wait, \
|
|
vx_busy, \
|
|
vx_running \
|
|
}
|
|
|
|
`define PROBES { \
|
|
vx_pending_writes \
|
|
}
|
|
|
|
VX_scope_tap #(
|
|
.SCOPE_ID (0),
|
|
.TRIGGERW ($bits(`TRIGGERS)),
|
|
.PROBEW ($bits(`PROBES))
|
|
) scope_tap (
|
|
.clk(clk),
|
|
.reset(scope_reset_w[0]),
|
|
.start(1'b0),
|
|
.stop(1'b0),
|
|
.triggers(`TRIGGERS),
|
|
.probes(`PROBES),
|
|
.bus_in(scope_bus_in_w[0]),
|
|
.bus_out(scope_bus_out_w[0])
|
|
);
|
|
`endif
|
|
`ifdef CHIPSCOPE
|
|
ila_afu ila_afu_inst (
|
|
.clk (ap_clk),
|
|
.probe0 ({
|
|
ap_start,
|
|
ap_done,
|
|
ap_idle,
|
|
interrupt
|
|
}),
|
|
.probe1 ({
|
|
vx_pending_writes,
|
|
vx_busy_wait,
|
|
vx_busy,
|
|
vx_running
|
|
})
|
|
);
|
|
`endif
|
|
`else
|
|
`SCOPE_IO_UNUSED_W(0)
|
|
`endif
|
|
|
|
`ifdef SIMULATION
|
|
`ifndef VERILATOR
|
|
// disable assertions until full reset
|
|
reg [`CLOG2(`RESET_DELAY+1)-1:0] assert_delay_ctr;
|
|
reg assert_enabled;
|
|
initial begin
|
|
$assertoff(0, vortex_axi);
|
|
end
|
|
always @(posedge ap_clk) begin
|
|
if (reset) begin
|
|
assert_delay_ctr <= '0;
|
|
assert_enabled <= 0;
|
|
end else begin
|
|
if (~assert_enabled) begin
|
|
if (assert_delay_ctr == (`RESET_DELAY-1)) begin
|
|
assert_enabled <= 1;
|
|
$asserton(0, vortex_axi); // enable assertions
|
|
end else begin
|
|
assert_delay_ctr <= assert_delay_ctr + 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
`endif
|
|
`endif
|
|
|
|
`ifdef DBG_TRACE_AFU
|
|
always @(posedge ap_clk) begin
|
|
for (integer i = 0; i < C_M_AXI_MEM_NUM_BANKS; ++i) begin
|
|
if (m_axi_mem_awvalid_a[i] && m_axi_mem_awready_a[i]) begin
|
|
`TRACE(2, ("%d: AFU Wr Req [%0d]: addr=0x%0h, tag=0x%0h\n", $time, i, m_axi_mem_awaddr_a[i], m_axi_mem_awid_a[i]));
|
|
end
|
|
if (m_axi_mem_wvalid_a[i] && m_axi_mem_wready_a[i]) begin
|
|
`TRACE(2, ("%d: AFU Wr Req [%0d]: data=0x%0h\n", $time, i, m_axi_mem_wdata_a[i]));
|
|
end
|
|
if (m_axi_mem_arvalid_a[i] && m_axi_mem_arready_a[i]) begin
|
|
`TRACE(2, ("%d: AFU Rd Req [%0d]: addr=0x%0h, tag=0x%0h\n", $time, i, m_axi_mem_araddr_a[i], m_axi_mem_arid_a[i]));
|
|
end
|
|
if (m_axi_mem_rvalid_a[i] && m_axi_mem_rready_a[i]) begin
|
|
`TRACE(2, ("%d: AVS Rd Rsp [%0d]: data=0x%0h, tag=0x%0h\n", $time, i, m_axi_mem_rdata_a[i], m_axi_mem_rid_a[i]));
|
|
end
|
|
end
|
|
end
|
|
`endif
|
|
|
|
endmodule
|