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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Used by ram_2port.v
// Requires `RAM_MOD_NAME and `RAM_DIRECTIVE to be defined
module `RAM_MOD_NAME #(
parameter DWIDTH = 32, // Width of the memory block
parameter AWIDTH = 9, // log2 of the depth of the memory block
parameter RW_MODE = "READ-FIRST", // Read-write mode {READ-FIRST, WRITE-FIRST, NO-CHANGE, B-READ-ONLY}
parameter OUT_REG = 0, // Instantiate an output register? (+1 cycle of read latency)
parameter INIT_FILE = "" // Optionally initialize memory with this file
) (
input wire clka,
input wire ena,
input wire wea,
input wire [AWIDTH-1:0] addra,
input wire [DWIDTH-1:0] dia,
output wire [DWIDTH-1:0] doa,
input wire clkb,
input wire enb,
input wire web,
input wire [AWIDTH-1:0] addrb,
input wire [DWIDTH-1:0] dib,
output wire [DWIDTH-1:0] dob
);
`RAM_DIRECTIVE reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
// Initialize ram to a specified file or to all zeros to match hardware
generate if (INIT_FILE != "") begin
initial begin
$readmemh(INIT_FILE, ram, 0, (1<<AWIDTH)-1);
end
end else begin
integer i;
initial begin
for (i = 0; i < (1<<AWIDTH); i = i + 1) begin
ram[i] = {DWIDTH{1'b0}};
end
end
end endgenerate
reg [DWIDTH-1:0] doa_r = 'h0, dob_r = 'h0;
generate if (OUT_REG == 1) begin
// A 2 clock cycle read latency with improve clock-to-out timing
reg [DWIDTH-1:0] doa_rr = 'h0, dob_rr = 'h0;
always @(posedge clka)
if (ena) begin
doa_rr <= doa_r;
end
always @(posedge clkb)
if (enb) begin
dob_rr <= dob_r;
end
assign doa = doa_rr;
assign dob = dob_rr;
end else begin
// A 1 clock cycle read latency at the cost of a longer clock-to-out timing
assign doa = doa_r;
assign dob = dob_r;
end endgenerate
generate if (RW_MODE == "READ-FIRST") begin
// When data is written, the prior memory contents at the write
// address are presented on the output port.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
end
dob_r <= ram[addrb];
end
end
end else if (RW_MODE == "WRITE-FIRST") begin
// The data being written to the RAM also resides on the output port.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
doa_r <= dia;
end else begin
doa_r <= ram[addra];
end
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
dob_r <= dib;
end else begin
dob_r <= ram[addrb];
end
end
end
end else if (RW_MODE == "NO-CHANGE") begin
// This is a no change RAM which retains the last read value on the output during writes
// which is the most power efficient mode.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end else begin
doa_r <= ram[addra];
end
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
end else begin
dob_r <= ram[addrb];
end
end
end
end else if (RW_MODE == "B-READ-ONLY") begin
// This is a RAM where port A is using READ-FIRST strategy and port B supports read only.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
dob_r <= ram[addrb];
end
end
end else begin
ERROR_Invalid_RW_MODE_selection();
end endgenerate
endmodule
|