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
|