209 lines
10 KiB
Systemverilog
209 lines
10 KiB
Systemverilog
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright 2018 Western Digital Corporation or it's affiliates.
|
|
//
|
|
// 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.
|
|
|
|
//********************************************************************************
|
|
// $Id$
|
|
//
|
|
// Owner:
|
|
// Function: SVCI to AXI4 Bridge
|
|
// Comments:
|
|
//
|
|
//********************************************************************************
|
|
module svci_to_axi4 #(parameter TAG = 1,
|
|
ID = 1,
|
|
PRTY = 1) (
|
|
|
|
input logic clk,
|
|
input logic rst_l,
|
|
input logic scan_mode,
|
|
input logic bus_clk_en,
|
|
input logic clk_override,
|
|
|
|
// AXI signals
|
|
// AXI Write Channels
|
|
output logic axi_awvalid,
|
|
input logic axi_awready,
|
|
output logic axi_awposted,
|
|
output logic [TAG-1:0] axi_awid,
|
|
output logic [31:0] axi_awaddr,
|
|
output logic [2:0] axi_awsize,
|
|
output logic [2:0] axi_awprot,
|
|
output logic [7:0] axi_awlen,
|
|
output logic [1:0] axi_awburst,
|
|
output logic [ID-1:0] axi_awmid,
|
|
output logic [PRTY-1:0] axi_awprty,
|
|
|
|
output logic axi_wvalid,
|
|
input logic axi_wready,
|
|
output logic [63:0] axi_wdata,
|
|
output logic [7:0] axi_wstrb,
|
|
output logic axi_wlast,
|
|
|
|
input logic axi_bvalid,
|
|
output logic axi_bready,
|
|
input logic axi_bposted,
|
|
input logic [1:0] axi_bresp,
|
|
input logic [TAG-1:0] axi_bid,
|
|
input logic [ID-1:0] axi_bmid,
|
|
input logic [PRTY-1:0] axi_bprty,
|
|
|
|
// AXI Read Channels
|
|
output logic axi_arvalid,
|
|
input logic axi_arready,
|
|
output logic [TAG-1:0] axi_arid,
|
|
output logic [31:0] axi_araddr,
|
|
output logic [2:0] axi_arsize,
|
|
output logic [2:0] axi_arprot,
|
|
output logic [7:0] axi_arlen,
|
|
output logic [1:0] axi_arburst,
|
|
output logic [ID-1:0] axi_armid,
|
|
output logic [PRTY-1:0] axi_arprty,
|
|
|
|
input logic axi_rvalid,
|
|
output logic axi_rready,
|
|
input logic [TAG-1:0] axi_rid,
|
|
input logic [63:0] axi_rdata,
|
|
input logic [1:0] axi_rresp,
|
|
input logic [ID-1:0] axi_rmid,
|
|
input logic [PRTY-1:0] axi_rprty,
|
|
|
|
// SVCI signals
|
|
input logic svci_cmd_valid,
|
|
output logic svci_cmd_ready,
|
|
input logic [TAG-1:0] svci_cmd_tag,
|
|
input logic [ID-1:0] svci_cmd_mid,
|
|
input logic [31:0] svci_cmd_addr,
|
|
input logic [63:0] svci_cmd_wdata,
|
|
input logic [7:0] svci_cmd_wbe,
|
|
input logic [2:0] svci_cmd_length,
|
|
input logic [2:0] svci_cmd_opc,
|
|
input logic [PRTY-1:0] svci_cmd_prty,
|
|
input logic dma_slv_algn_err,
|
|
|
|
output logic svci_rsp_valid,
|
|
input logic svci_rsp_ready,
|
|
output logic [TAG-1:0] svci_rsp_tag,
|
|
output logic [ID-1:0] svci_rsp_mid,
|
|
output logic [63:0] svci_rsp_rdata,
|
|
output logic [3:0] svci_rsp_opc,
|
|
output logic [PRTY-1:0] svci_rsp_prty
|
|
);
|
|
|
|
logic cmdbuf_wr_en, cmdbuf_data_en, cmdbuf_rst, cmdbuf_data_rst;
|
|
logic cmdbuf_full;
|
|
logic cmdbuf_vld, cmdbuf_data_vld;
|
|
logic [2:0] cmdbuf_opc, cmdbuf_size;
|
|
logic [7:0] cmdbuf_wstrb;
|
|
logic [31:0] cmdbuf_addr;
|
|
logic [63:0] cmdbuf_wdata;
|
|
logic [TAG-1:0] cmdbuf_tag;
|
|
logic [ID-1:0] cmdbuf_mid;
|
|
logic [PRTY-1:0] cmdbuf_prty;
|
|
|
|
logic wrbuf_en, wrbuf_rst;
|
|
logic wrbuf_vld;
|
|
logic wrbuf_posted;
|
|
logic [TAG-1:0] wrbuf_tag;
|
|
logic [ID-1:0] wrbuf_mid;
|
|
logic [1:0] wrbuf_resp;
|
|
logic [63:0] error_address; // SVCI needs the error address back on the rdata.
|
|
logic [PRTY-1:0] wrbuf_prty;
|
|
|
|
logic [1:0] axi_bresp_in; // need to map 2 errors in to 3 errors
|
|
logic bus_clk;
|
|
|
|
// Command buffer
|
|
assign cmdbuf_wr_en = svci_cmd_valid & svci_cmd_ready;
|
|
assign cmdbuf_data_en = cmdbuf_wr_en & (svci_cmd_opc[2:1] == 2'b01);
|
|
assign cmdbuf_rst = ((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en;
|
|
assign cmdbuf_data_rst = (axi_wvalid & axi_wready) & (cmdbuf_opc[2:1] == 2'b01) & ~cmdbuf_data_en;
|
|
|
|
assign cmdbuf_full = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready))) | (cmdbuf_data_vld & ~((axi_wvalid & axi_wready) & (cmdbuf_opc[2:1] == 2'b01)));
|
|
|
|
rvdffsc #(.WIDTH(1)) cmdbuf_vldff(.din(1'b1), .dout(cmdbuf_vld), .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .*);
|
|
rvdffsc #(.WIDTH(1)) cmdbuf_data_vldff(.din(1'b1), .dout(cmdbuf_data_vld), .en(cmdbuf_data_en), .clear(cmdbuf_data_rst), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(3)) cmdbuf_opcff(.din(svci_cmd_opc[2:0]), .dout(cmdbuf_opc[2:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(3)) cmdbuf_sizeff(.din(svci_cmd_length[2:0]), .dout(cmdbuf_size[2:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
|
|
rvdffe #(.WIDTH(8)) cmdbuf_wstrbff(.din(svci_cmd_wbe[7:0]), .dout(cmdbuf_wstrb[7:0]), .en(cmdbuf_wr_en & bus_clk_en), .*);
|
|
rvdffe #(.WIDTH(32)) cmdbuf_addrff(.din(svci_cmd_addr[31:0]), .dout(cmdbuf_addr[31:0]), .en(cmdbuf_wr_en & bus_clk_en), .*);
|
|
rvdffe #(.WIDTH(64)) cmdbuf_wdataff(.din(svci_cmd_wdata[63:0]), .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_data_en & bus_clk_en), .*);
|
|
rvdffs #(.WIDTH(TAG)) cmdbuf_tagff(.din(svci_cmd_tag[TAG-1:0]), .dout(cmdbuf_tag[TAG-1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(ID)) cmdbuf_midff(.din(svci_cmd_mid[ID-1:0]), .dout(cmdbuf_mid[ID-1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(PRTY)) cmdbuf_prtyff(.din(svci_cmd_prty[PRTY-1:0]), .dout(cmdbuf_prty[PRTY-1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .*);
|
|
|
|
// AXI Write Channels
|
|
assign axi_awvalid = cmdbuf_vld & (cmdbuf_opc[2:1] == 2'b01);
|
|
assign axi_awposted = axi_awvalid & ~cmdbuf_opc[0];
|
|
assign axi_awid[TAG-1:0] = cmdbuf_tag[TAG-1:0];
|
|
assign axi_awaddr[31:0] = cmdbuf_addr[31:0];
|
|
assign axi_awsize[2:0] = cmdbuf_size[2:0];
|
|
assign axi_awprot[2:0] = 3'b0;
|
|
assign axi_awlen[7:0] = '0;
|
|
assign axi_awburst[1:0] = 2'b01;
|
|
assign axi_awmid = cmdbuf_mid[ID-1:0];
|
|
assign axi_awprty = cmdbuf_prty[PRTY-1:0];
|
|
|
|
assign axi_wvalid = cmdbuf_data_vld;
|
|
assign axi_wdata[63:0] = cmdbuf_wdata[63:0];
|
|
assign axi_wstrb[7:0] = cmdbuf_wstrb[7:0];
|
|
assign axi_wlast = 1'b1;
|
|
|
|
assign axi_bready = ~wrbuf_vld | svci_rsp_ready;
|
|
|
|
// AXI Read Channels
|
|
assign axi_arvalid = cmdbuf_vld & (cmdbuf_opc[2:0] == 3'b0);
|
|
assign axi_arid[TAG-1:0] = cmdbuf_tag[TAG-1:0];
|
|
assign axi_araddr[31:0] = cmdbuf_addr[31:0];
|
|
assign axi_arsize[2:0] = cmdbuf_size[2:0];
|
|
assign axi_arprot = 3'b0;
|
|
assign axi_arlen[7:0] = '0;
|
|
assign axi_arburst[1:0] = 2'b01;
|
|
assign axi_armid = cmdbuf_mid[ID-1:0];
|
|
assign axi_rready = ~wrbuf_vld & svci_rsp_ready;
|
|
assign axi_arprty = cmdbuf_prty[PRTY-1:0];
|
|
|
|
// SVCI_response signals
|
|
assign svci_rsp_valid = wrbuf_vld | axi_rvalid;
|
|
assign svci_rsp_tag[TAG-1:0] = wrbuf_vld ? wrbuf_tag[TAG-1:0] : axi_rid[TAG-1:0];
|
|
assign svci_rsp_mid[ID-1:0] = wrbuf_vld ? wrbuf_mid[ID-1:0] : axi_rmid[ID-1:0];
|
|
assign svci_rsp_rdata[63:0] = wrbuf_vld ? {32'b0, error_address[31:0]} : axi_rdata[63:0]; // rdata
|
|
assign svci_rsp_opc[3:2] = wrbuf_vld ? {1'b1, ~wrbuf_posted} : 2'b0;
|
|
// assign svci_rsp_opc[1:0] = wrbuf_vld ? {wrbuf_resp[1] ? (wrbuf_resp[0] ? 2'b10 : 2'b01) : 2'b0} : // AXI Slave Error -> SVCI Slave Error, AXI Decode Error -> SVCI Address Error
|
|
// {axi_rresp[1] ? (axi_rresp[0] ? 2'b10 : 2'b01) : 2'b0};
|
|
assign svci_rsp_opc[1:0] = wrbuf_vld ? wrbuf_resp[1:0] : // AXI Slave Error -> SVCI Slave Error, AXI Decode Error -> SVCI Address Error
|
|
{axi_rresp[1] ? (axi_rresp[0] ? 2'b10 : {dma_slv_algn_err, 1'b1}) : 2'b0};
|
|
assign svci_rsp_prty[PRTY-1:0] = wrbuf_vld ? wrbuf_prty[PRTY-1:0] : axi_rprty[PRTY-1:0];
|
|
|
|
assign svci_cmd_ready = ~cmdbuf_full;
|
|
|
|
// Write Response Buffer. Errors for writes need to send the Error address back on the rsp_rdata for SVCI. The address is sent back on axi_rdata bus for both reads and writes that have errors.
|
|
// assign wrbuf_en = axi_bvalid & svci_rsp_ready & (~axi_bposted | axi_bresp[1]);
|
|
assign wrbuf_en = axi_bvalid & axi_bready & (~axi_bposted | axi_bresp[1]);
|
|
assign wrbuf_rst = svci_rsp_valid & svci_rsp_ready & svci_rsp_opc[3] & ~wrbuf_en;
|
|
assign axi_bresp_in[1:0] = {axi_bresp[1] ? (axi_bresp[0] ? 2'b10 : {dma_slv_algn_err, 1'b1}) : 2'b0};
|
|
rvdffsc #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(32)) wrbuf_erroff (.din(axi_rdata[31:0]), .dout(error_address[31:0]), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(1)) wrbuf_postedff(.din(axi_bposted), .dout(wrbuf_posted), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(TAG)) wrbuf_tagff (.din(axi_bid[TAG-1:0]), .dout(wrbuf_tag[TAG-1:0]), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(ID)) wrbuf_midff (.din(axi_bmid[ID-1:0]), .dout(wrbuf_mid[ID-1:0]), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(PRTY))wrbuf_prtyff (.din(axi_bprty[PRTY-1:0]), .dout(wrbuf_prty[PRTY-1:0]), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
rvdffs #(.WIDTH(2)) wrbuf_respff (.din(axi_bresp_in[1:0]), .dout(wrbuf_resp[1:0]), .en(wrbuf_en), .clk(bus_clk), .*);
|
|
|
|
// Clock header logic
|
|
rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
|
|
|
|
endmodule // svci_to_axi4
|
|
|