summaryrefslogtreecommitdiff
path: root/python/openvino/demo/ip/intel_ai_ip/verilog/dla_lt_ram_arb.sv
blob: 0705fef61e736d1bd266b205144af3663a3ab1e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// 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