// Copyright 2020-2024 Intel Corporation. // // This software and the related documents are Intel copyrighted materials, // and your use of them is governed by the express license under which they // were provided to you ("License"). Unless the License provides otherwise, // you may not use, modify, copy, publish, distribute, disclose or transmit // this software or the related documents without Intel's prior written // permission. // // This software and the related documents are provided as is, with no express // or implied warranties, other than those that are expressly stated in the // License. /** * dla_ram_arb.sv * * arbiter module for full duplex dual port RAM. * * Operation: * The module accepts two read requests, and a single write request. The write * request takes highest priority. A write request will be sent to either port A or B * if either are free. Otherwise, if there is a read request on both port A and B, then * the write will take place on port B and the read request will be ignored. * The user should check the current_read_a/b outputs to confirm the address that is * being read. * * Assumptions: * Must be used with full duplex RAM that has a 2-cycle read latency. * */ `resetall `undefineall `default_nettype none import dla_common_pkg::*; module dla_lt_ram_arb #(parameter ADDRESS_WIDTH, parameter DATA_WIDTH) ( input wire clk, input wire i_rstn, //PORT A READ REQUESTS input wire [ADDRESS_WIDTH-1:0] i_a_address, input wire i_a_valid_read_req, //PORT B READ REQUESTS input wire [ADDRESS_WIDTH-1:0] i_b_address, input wire i_b_valid_read_req, //WRITE REQUESTS input wire [ADDRESS_WIDTH-1:0] i_write_address, input wire i_write_req, input wire [DATA_WIDTH-1:0] i_write_data, //OUTPUTS A output logic [ADDRESS_WIDTH-1:0] o_arb_address_a, output logic o_arb_write_valid_a, output logic [DATA_WIDTH-1:0] o_arb_data_a, output logic [ADDRESS_WIDTH-1:0] o_current_read_a, // Address of value currently driven on port A (assumes 2-cycle read delay!) //OUTPUTS B output logic [ADDRESS_WIDTH-1:0] o_arb_address_b, output logic o_arb_write_valid_b, output logic [DATA_WIDTH-1:0] o_arb_data_b, output logic [ADDRESS_WIDTH-1:0] o_current_read_b ); logic [ADDRESS_WIDTH-1:0] current_read_a_[1:0]; logic [ADDRESS_WIDTH-1:0] current_read_b_[1:0]; assign o_current_read_a = current_read_a_[0]; assign o_current_read_b = current_read_b_[0]; assign o_arb_data_a = i_write_data; assign o_arb_data_b = i_write_data; always_ff @(posedge clk) begin if (!i_rstn) begin current_read_a_ <= '{default: '0}; current_read_b_ <= '{default: '0}; end current_read_a_[1] <= o_arb_address_a; current_read_a_[0] <= current_read_a_[1]; current_read_b_[1] <= o_arb_address_b; current_read_b_[0] <= current_read_b_[1]; end always_comb begin : arbitrate o_arb_address_a = i_a_address; o_arb_write_valid_a = 1'b0; o_arb_address_b = i_b_address; o_arb_write_valid_b = 1'b0; if ((i_write_req == 1'b1 && i_a_valid_read_req == 1'b0) || (i_write_req == 1'b1 && i_a_valid_read_req == 1'b1 && i_a_address == i_write_address)) begin // Port A does not have a read request, or read request is for the same address. o_arb_address_a = i_write_address; o_arb_write_valid_a = 1'b1; end else if ((i_write_req == 1'b1 && i_b_valid_read_req == 1'b0) || (i_write_req == 1'b1 && i_b_valid_read_req == 1'b1 && i_b_address == i_write_address)) begin // Port B does not have a read request or read request is for the same address. o_arb_address_b = i_write_address; o_arb_write_valid_b = 1'b1; end else if (i_write_req == 1'b1 && i_b_valid_read_req == 1'b1 && i_a_valid_read_req == 1'b1 && i_write_address != i_b_address && i_write_address != i_a_address) begin // Both A and B have a read request, and there is a write request at a unique address. // Then send the write request to port B and ignore the read. This disparity will be visible to the user by checking the current_read_b value. o_arb_address_b = i_write_address; // instead of b_address... o_arb_write_valid_b = 1'b1; end end endmodule //ram_arb