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
|
//
// 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}
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
$readmemh(INIT_FILE, ram, 0, (1<<AWIDTH)-1);
end else begin
integer i;
initial
for (i = 0; i < (1<<AWIDTH); i = i + 1)
ram[i] = {DWIDTH{1'b0}};
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)
doa_rr <= doa_r;
always @(posedge clkb)
if (enb)
dob_rr <= dob_r;
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)
ram[addra] <= dia;
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
if (web)
ram[addrb] <= dib;
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 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)
ram[addra] <= dia;
else
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
if (web)
ram[addrb] <= dib;
else
dob_r <= ram[addrb];
end
end
end endgenerate
endmodule
|