+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes minor update minor update minor update minor update minor update minor update cleanup cleanup cache bindings and memory perf refactory minor update minor update hw unit tests fixes minor update minor update minor update minor update minor update minor udpate minor update minor update minor update minor update minor update minor update minor update minor updates minor updates minor update minor update minor update minor update minor update minor update minor updates minor updates minor updates minor updates minor update minor update
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),
|
|
`UNUSED_PIN (m_axi_awlen),
|
|
`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
|