+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes
420 lines
14 KiB
Systemverilog
420 lines
14 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_ctrl #(
|
|
parameter AXI_ADDR_WIDTH = 8,
|
|
parameter AXI_DATA_WIDTH = 32,
|
|
parameter AXI_NUM_BANKS = 1
|
|
) (
|
|
// axi4 lite slave signals
|
|
input wire clk,
|
|
input wire reset,
|
|
input wire clk_en,
|
|
|
|
input wire s_axi_awvalid,
|
|
input wire [AXI_ADDR_WIDTH-1:0] s_axi_awaddr,
|
|
output wire s_axi_awready,
|
|
|
|
input wire s_axi_wvalid,
|
|
input wire [AXI_DATA_WIDTH-1:0] s_axi_wdata,
|
|
input wire [AXI_DATA_WIDTH/8-1:0] s_axi_wstrb,
|
|
output wire s_axi_wready,
|
|
|
|
output wire s_axi_bvalid,
|
|
output wire [1:0] s_axi_bresp,
|
|
input wire s_axi_bready,
|
|
|
|
input wire s_axi_arvalid,
|
|
input wire [AXI_ADDR_WIDTH-1:0] s_axi_araddr,
|
|
output wire s_axi_arready,
|
|
|
|
output wire s_axi_rvalid,
|
|
output wire [AXI_DATA_WIDTH-1:0] s_axi_rdata,
|
|
output wire [1:0] s_axi_rresp,
|
|
input wire s_axi_rready,
|
|
|
|
output wire ap_reset,
|
|
output wire ap_start,
|
|
input wire ap_done,
|
|
input wire ap_ready,
|
|
input wire ap_idle,
|
|
output wire interrupt,
|
|
|
|
`ifdef SCOPE
|
|
input wire scope_bus_in,
|
|
output wire scope_bus_out,
|
|
`endif
|
|
|
|
output wire [63:0] mem_base [AXI_NUM_BANKS],
|
|
|
|
output wire dcr_wr_valid,
|
|
output wire [`VX_DCR_ADDR_WIDTH-1:0] dcr_wr_addr,
|
|
output wire [`VX_DCR_DATA_WIDTH-1:0] dcr_wr_data
|
|
);
|
|
|
|
// Address Info
|
|
// 0x00 : Control signals
|
|
// bit 0 - ap_start (Read/Write/COH)
|
|
// bit 1 - ap_done (Read/COR)
|
|
// bit 2 - ap_idle (Read)
|
|
// bit 3 - ap_ready (Read)
|
|
// bit 4 - ap_reset (Write)
|
|
// bit 7 - auto_restart (Read/Write)
|
|
// others - reserved
|
|
// 0x04 : Global Interrupt Enable Register
|
|
// bit 0 - Global Interrupt Enable (Read/Write)
|
|
// others - reserved
|
|
// 0x08 : IP Interrupt Enable Register (Read/Write)
|
|
// bit 0 - Channel 0 (ap_done)
|
|
// bit 1 - Channel 1 (ap_ready)
|
|
// others - reserved
|
|
// 0x0c : IP Interrupt Status Register (Read/TOW)
|
|
// bit 0 - Channel 0 (ap_done)
|
|
// bit 1 - Channel 1 (ap_ready)
|
|
// others - reserved
|
|
// 0x10 : Low 32-bit Data signal of DEV_CAPS
|
|
// 0x14 : High 32-bit Data signal of DEV_CAPS
|
|
// 0x18 : Control signal of DEV_CAPS
|
|
// 0x1C : Low 32-bit Data signal of ISA_CAPS
|
|
// 0x20 : High 32-bit Data signal of ISA_CAPS
|
|
// 0x24 : Control signal of ISA_CAPS
|
|
// 0x28 : Low 32-bit Data signal of DCR
|
|
// 0x2C : High 32-bit Data signal of DCR
|
|
// 0x30 : Control signal of DCR
|
|
// 0x34 : Low 32-bit Data signal of SCP
|
|
// 0x38 : High 32-bit Data signal of SCP
|
|
// 0x3C : Control signal of SCP
|
|
// 0x40 : Low 32-bit Data signal of MEM
|
|
// 0x44 : High 32-bit Data signal of MEM
|
|
// 0x48 : Control signal of MEM
|
|
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
|
|
|
|
// Parameters
|
|
localparam
|
|
ADDR_AP_CTRL = 8'h00,
|
|
ADDR_GIE = 8'h04,
|
|
ADDR_IER = 8'h08,
|
|
ADDR_ISR = 8'h0C,
|
|
|
|
ADDR_DEV_0 = 8'h10,
|
|
ADDR_DEV_1 = 8'h14,
|
|
ADDR_DEV_CTRL = 8'h18,
|
|
|
|
ADDR_ISA_0 = 8'h1C,
|
|
ADDR_ISA_1 = 8'h20,
|
|
ADDR_ISA_CTRL = 8'h24,
|
|
|
|
ADDR_DCR_0 = 8'h28,
|
|
ADDR_DCR_1 = 8'h2C,
|
|
ADDR_DCR_CTRL = 8'h30,
|
|
|
|
ADDR_SCP_0 = 8'h34,
|
|
ADDR_SCP_1 = 8'h38,
|
|
ADDR_SCP_CTRL = 8'h3C,
|
|
|
|
ADDR_MEM_0 = 8'h40,
|
|
ADDR_MEM_1 = 8'h44,
|
|
ADDR_MEM_CTRL = 8'h48,
|
|
|
|
ADDR_BITS = 8;
|
|
|
|
localparam
|
|
WSTATE_IDLE = 2'd0,
|
|
WSTATE_DATA = 2'd1,
|
|
WSTATE_RESP = 2'd2;
|
|
|
|
localparam
|
|
RSTATE_IDLE = 2'd0,
|
|
RSTATE_DATA = 2'd1;
|
|
|
|
// device caps
|
|
wire [63:0] dev_caps = {16'b0,
|
|
8'(`SM_ENABLED ? `SMEM_LOG_SIZE : 0),
|
|
16'(`NUM_CORES * `NUM_CLUSTERS),
|
|
8'(`NUM_WARPS),
|
|
8'(`NUM_THREADS),
|
|
8'(`IMPLEMENTATION_ID)};
|
|
|
|
wire [63:0] isa_caps = {32'(`MISA_EXT),
|
|
2'(`CLOG2(`XLEN)-4),
|
|
30'(`MISA_STD)};
|
|
|
|
reg [1:0] wstate;
|
|
reg [ADDR_BITS-1:0] waddr;
|
|
wire [31:0] wmask;
|
|
wire s_axi_aw_fire;
|
|
wire s_axi_w_fire;
|
|
|
|
reg [1:0] rstate;
|
|
reg [31:0] rdata;
|
|
wire [ADDR_BITS-1:0] raddr;
|
|
wire s_axi_ar_fire;
|
|
|
|
reg ap_reset_r;
|
|
reg ap_start_r;
|
|
reg auto_restart_r;
|
|
reg gie_r;
|
|
reg [1:0] ier_r;
|
|
reg [1:0] isr_r;
|
|
reg [63:0] mem_r [AXI_NUM_BANKS];
|
|
reg [31:0] dcra_r;
|
|
reg [31:0] dcrv_r;
|
|
reg dcr_wr_valid_r;
|
|
|
|
`ifdef SCOPE
|
|
|
|
reg [63:0] scope_bus_wdata;
|
|
reg [63:0] scope_bus_rdata;
|
|
reg [5:0] scope_bus_ctr;
|
|
|
|
reg cmd_scope_reading;
|
|
reg cmd_scope_writing;
|
|
reg scope_bus_out_r;
|
|
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
cmd_scope_reading <= 0;
|
|
cmd_scope_writing <= 0;
|
|
scope_bus_ctr <= '0;
|
|
scope_bus_out_r <= 0;
|
|
end else if (clk_en) begin
|
|
if (s_axi_w_fire && waddr == ADDR_SCP_0) begin
|
|
scope_bus_wdata[31:0] <= (s_axi_wdata & wmask) | (scope_bus_wdata[31:0] & ~wmask);
|
|
end
|
|
if (s_axi_w_fire && waddr == ADDR_SCP_1) begin
|
|
scope_bus_wdata[63:32] <= (s_axi_wdata & wmask) | (scope_bus_wdata[63:32] & ~wmask);
|
|
cmd_scope_writing <= 1;
|
|
scope_bus_out_r <= 1;
|
|
scope_bus_ctr <= 63;
|
|
end
|
|
if (scope_bus_in) begin
|
|
cmd_scope_reading <= 1;
|
|
scope_bus_ctr <= 63;
|
|
end
|
|
if (cmd_scope_reading) begin
|
|
scope_bus_rdata <= {scope_bus_rdata[62:0], scope_bus_in};
|
|
scope_bus_ctr <= scope_bus_ctr - 1;
|
|
if (scope_bus_ctr == 0) begin
|
|
cmd_scope_reading <= 0;
|
|
end
|
|
end
|
|
if (cmd_scope_writing) begin
|
|
scope_bus_out_r <= 1'(scope_bus_wdata >> scope_bus_ctr);
|
|
scope_bus_ctr <= scope_bus_ctr - 1;
|
|
if (scope_bus_ctr == 0) begin
|
|
cmd_scope_writing <= 0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
assign scope_bus_out = scope_bus_out_r;
|
|
|
|
`endif
|
|
|
|
// AXI Write
|
|
|
|
assign s_axi_awready = (wstate == WSTATE_IDLE);
|
|
assign s_axi_wready = (wstate == WSTATE_DATA);
|
|
assign s_axi_bvalid = (wstate == WSTATE_RESP);
|
|
assign s_axi_bresp = 2'b00; // OKAY
|
|
|
|
assign s_axi_aw_fire = s_axi_awvalid && s_axi_awready;
|
|
assign s_axi_w_fire = s_axi_wvalid && s_axi_wready;
|
|
|
|
for (genvar i = 0; i < 4; ++i) begin
|
|
assign wmask[8 * i +: 8] = {8{s_axi_wstrb[i]}};
|
|
end
|
|
|
|
// wstate
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
wstate <= WSTATE_IDLE;
|
|
end else if (clk_en) begin
|
|
case (wstate)
|
|
WSTATE_IDLE: wstate <= s_axi_awvalid ? WSTATE_DATA : WSTATE_IDLE;
|
|
WSTATE_DATA: wstate <= s_axi_wvalid ? WSTATE_RESP : WSTATE_DATA;
|
|
WSTATE_RESP: wstate <= s_axi_bready ? WSTATE_IDLE : WSTATE_RESP;
|
|
default: wstate <= WSTATE_IDLE;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// waddr
|
|
always @(posedge clk) begin
|
|
if (clk_en) begin
|
|
if (s_axi_aw_fire)
|
|
waddr <= s_axi_awaddr[ADDR_BITS-1:0];
|
|
end
|
|
end
|
|
|
|
// wdata
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
ap_start_r <= 0;
|
|
ap_reset_r <= 0;
|
|
auto_restart_r <= 0;
|
|
|
|
gie_r <= 0;
|
|
ier_r <= '0;
|
|
isr_r <= '0;
|
|
|
|
dcra_r <= '0;
|
|
dcrv_r <= '0;
|
|
dcr_wr_valid_r <= 0;
|
|
|
|
for (integer i = 0; i < AXI_NUM_BANKS; ++i) begin
|
|
mem_r[i] <= '0;
|
|
end
|
|
end else if (clk_en) begin
|
|
if (ap_ready)
|
|
ap_start_r <= auto_restart_r;
|
|
|
|
dcr_wr_valid_r <= 0;
|
|
|
|
if (s_axi_w_fire) begin
|
|
case (waddr)
|
|
ADDR_AP_CTRL: begin
|
|
if (s_axi_wstrb[0]) begin
|
|
if (s_axi_wdata[0])
|
|
ap_start_r <= 1;
|
|
if (s_axi_wdata[4])
|
|
ap_reset_r <= 1;
|
|
if (s_axi_wdata[7])
|
|
auto_restart_r <= 1;
|
|
end
|
|
end
|
|
ADDR_GIE: begin
|
|
if (s_axi_wstrb[0])
|
|
gie_r <= s_axi_wdata[0];
|
|
end
|
|
ADDR_IER: begin
|
|
if (s_axi_wstrb[0])
|
|
ier_r <= s_axi_wdata[1:0];
|
|
end
|
|
ADDR_ISR: begin
|
|
if (s_axi_wstrb[0])
|
|
isr_r <= isr_r ^ s_axi_wdata[1:0];
|
|
end
|
|
ADDR_DCR_0: begin
|
|
dcra_r <= (s_axi_wdata & wmask) | (dcra_r & ~wmask);
|
|
end
|
|
ADDR_DCR_1: begin
|
|
dcrv_r <= (s_axi_wdata & wmask) | (dcrv_r & ~wmask);
|
|
dcr_wr_valid_r <= 1;
|
|
end
|
|
default: begin
|
|
for (integer i = 0; i < AXI_NUM_BANKS; ++i) begin
|
|
if (waddr == (ADDR_MEM_0 + i * 12)) begin
|
|
mem_r[i][31:0] <= (s_axi_wdata & wmask) | (mem_r[i][31:0] & ~wmask);
|
|
end
|
|
if (waddr == (ADDR_MEM_1 + i * 12)) begin
|
|
mem_r[i][63:32] <= (s_axi_wdata & wmask) | (mem_r[i][63:32] & ~wmask);
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
|
|
if (ier_r[0] & ap_done)
|
|
isr_r[0] <= 1'b1;
|
|
if (ier_r[1] & ap_ready)
|
|
isr_r[1] <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
// AXI Read
|
|
|
|
assign s_axi_arready = (rstate == RSTATE_IDLE);
|
|
assign s_axi_rvalid = (rstate == RSTATE_DATA);
|
|
assign s_axi_rdata = rdata;
|
|
assign s_axi_rresp = 2'b00; // OKAY
|
|
|
|
assign s_axi_ar_fire = s_axi_arvalid && s_axi_arready;
|
|
assign raddr = s_axi_araddr[ADDR_BITS-1:0];
|
|
|
|
// rstate
|
|
always @(posedge clk) begin
|
|
if (reset) begin
|
|
rstate <= RSTATE_IDLE;
|
|
end else if (clk_en) begin
|
|
case (rstate)
|
|
RSTATE_IDLE: rstate <= s_axi_arvalid ? RSTATE_DATA : RSTATE_IDLE;
|
|
RSTATE_DATA: rstate <= (s_axi_rready & s_axi_rvalid) ? RSTATE_IDLE : RSTATE_DATA;
|
|
default: rstate <= RSTATE_IDLE;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// rdata
|
|
always @(posedge clk) begin
|
|
if (clk_en) begin
|
|
if (s_axi_ar_fire) begin
|
|
rdata <= '0;
|
|
case (raddr)
|
|
ADDR_AP_CTRL: begin
|
|
rdata[0] <= ap_start_r;
|
|
rdata[1] <= ap_done;
|
|
rdata[2] <= ap_idle;
|
|
rdata[3] <= ap_ready;
|
|
rdata[7] <= auto_restart_r;
|
|
end
|
|
ADDR_GIE: begin
|
|
rdata <= 32'(gie_r);
|
|
end
|
|
ADDR_IER: begin
|
|
rdata <= 32'(ier_r);
|
|
end
|
|
ADDR_ISR: begin
|
|
rdata <= 32'(isr_r);
|
|
end
|
|
ADDR_DEV_0: begin
|
|
rdata <= dev_caps[31:0];
|
|
end
|
|
ADDR_DEV_1: begin
|
|
rdata <= dev_caps[63:32];
|
|
end
|
|
ADDR_ISA_0: begin
|
|
rdata <= isa_caps[31:0];
|
|
end
|
|
ADDR_ISA_1: begin
|
|
rdata <= isa_caps[63:32];
|
|
end
|
|
`ifdef SCOPE
|
|
ADDR_SCP_0: begin
|
|
rdata <= scope_bus_rdata[31:0];
|
|
end
|
|
ADDR_SCP_1: begin
|
|
rdata <= scope_bus_rdata[63:32];
|
|
end
|
|
`endif
|
|
default:;
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
assign ap_reset = ap_reset_r;
|
|
assign ap_start = ap_start_r;
|
|
assign interrupt = gie_r & (| isr_r);
|
|
|
|
assign mem_base = mem_r;
|
|
|
|
assign dcr_wr_valid = dcr_wr_valid_r;
|
|
assign dcr_wr_addr = `VX_DCR_ADDR_WIDTH'(dcra_r);
|
|
assign dcr_wr_data = `VX_DCR_DATA_WIDTH'(dcrv_r);
|
|
|
|
endmodule
|