7a21969c2e303bc963acaa03a012e06114483ceb
1 # // Copyright 2018 ETH Zurich and University of Bologna.
2 # // Copyright and related rights are licensed under the Solderpad Hardware
3 # // License, Version 0.51 (the "License"); you may not use this file except in
4 # // compliance with the License. You may obtain a copy of the License at
5 # // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
6 # // or agreed to in writing, software, hardware and materials distributed under
7 # // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8 # // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 # // specific language governing permissions and limitations under the License.
12 # * ram_tp_write_first
14 # * This code implements a parameterizable two-port memory. Port 0 can read and
15 # * write while Port 1 can read only. Xilinx Vivado will infer a BRAM in
16 # * "write first" mode, i.e., upon a read and write to the same address, the
17 # * new value is read. Note: Port 1 outputs invalid data in the cycle after
18 # * the write when reading the same address.
20 # * For more information, see Xilinx PG058 Block Memory Generator Product Guide.
23 from nmigen
import Signal
, Module
, Const
, Cat
, Elaboratable
24 from nmigen
import Memory
28 # module ram_tp_write_first
36 # input [ADDR_WIDTH-1:0] addr0,
37 # input [ADDR_WIDTH-1:0] addr1,
38 # input [DATA_WIDTH-1:0] d_i,
39 # output [DATA_WIDTH-1:0] d0_o,
40 # output [DATA_WIDTH-1:0] d1_o
44 class ram_tp_write_first(Elaboratable
):
47 self
.we
= Signal() # input
48 self
.addr0
= Signal(ADDR_WIDTH
) # input
49 self
.addr1
= Signal(ADDR_WIDTH
) # input
50 self
.d_i
= Signal(DATA_WIDTH
) # input
51 self
.d0_o
= Signal(DATA_WIDTH
) # output
52 self
.d1_o
= Signal(DATA_WIDTH
) # output
54 DEPTH
= int(math
.pow(2, ADDR_WIDTH
))
55 self
.ram
= Memory(DATA_WIDTH
, DEPTH
)
58 # localparam DEPTH = 2**ADDR_WIDTH;
60 # (* ram_style = "block" *) reg [DATA_WIDTH-1:0] ram[DEPTH];
61 # reg [ADDR_WIDTH-1:0] raddr0;
62 # reg [ADDR_WIDTH-1:0] raddr1;
64 # always_ff @(posedge clk) begin
65 # if(we == 1'b1) begin
72 # assign d0_o = ram[raddr0];
73 # assign d1_o = ram[raddr1];
76 def elaborate(self
, platform
=None):
78 m
.submodules
.read_ram0
= read_ram0
= self
.ram
.read_port()
79 m
.submodules
.read_ram1
= read_ram1
= self
.ram
.read_port()
80 m
.submodules
.write_ram
= write_ram
= self
.ram
.write_port()
83 m
.d
.comb
+= write_ram
.en
.eq(self
.we
)
84 m
.d
.comb
+= write_ram
.addr
.eq(self
.addr0
)
85 m
.d
.comb
+= write_ram
.data
.eq(self
.d_i
)
88 m
.d
.comb
+= read_ram0
.addr
.eq(self
.addr0
)
89 m
.d
.comb
+= read_ram1
.addr
.eq(self
.addr1
)
90 m
.d
.sync
+= self
.d0_o
.eq(read_ram0
.data
)
91 m
.d
.sync
+= self
.d1_o
.eq(read_ram1
.data
)