use block_ram attribute for FPGA synthesis
[soc.git] / src / soc / experiment / cache_ram.py
1 # TODO: replace with Memory at some point
2 from nmigen import Elaboratable, Signal, Array, Module, Memory
3 from nmutil.util import Display
4
5
6 class CacheRam(Elaboratable):
7
8 def __init__(self, ROW_BITS=16, WIDTH = 64, TRACE=True, ADD_BUF=False,
9 ram_num=0):
10 self.ram_num = ram_num # for debug reporting
11 self.ROW_BITS = ROW_BITS
12 self.WIDTH = WIDTH
13 self.TRACE = TRACE
14 self.ADD_BUF = ADD_BUF
15 self.rd_en = Signal()
16 self.rd_addr = Signal(ROW_BITS)
17 self.rd_data_o = Signal(WIDTH)
18 self.wr_sel = Signal(WIDTH//8)
19 self.wr_addr = Signal(ROW_BITS)
20 self.wr_data = Signal(WIDTH)
21
22 def elaborate(self, platform):
23 m = Module()
24 comb, sync = m.d.comb, m.d.sync
25
26 ROW_BITS = self.ROW_BITS
27 WIDTH = self.WIDTH
28 TRACE = self.TRACE
29 ADD_BUF = self.ADD_BUF
30 SIZE = 2**ROW_BITS
31
32 # set up the Cache RAM Memory and create one read and one write port
33 # the read port is *not* transparent (does not pass write-thru-read)
34 #attribute ram_style of ram : signal is "block";
35 ram = Memory(depth=SIZE, width=WIDTH,
36 attrs={'syn_ramstyle': "block_ram"})
37 m.submodules.rdport = rdport = ram.read_port(transparent=False)
38 m.submodules.wrport = wrport = ram.write_port(granularity=8)
39
40 with m.If(TRACE):
41 with m.If(self.wr_sel.bool()):
42 sync += Display( "write ramno %d a: %%x "
43 "sel: %%x dat: %%x" % self.ram_num,
44 self.wr_addr,
45 self.wr_sel, self.wr_data)
46
47 # read data output and a latched copy. behaves like microwatt cacheram
48 rd_data0 = Signal(WIDTH)
49 rd_data0l = Signal(WIDTH)
50
51 # delay on read address/en
52 rd_delay = Signal()
53 rd_delay_addr = Signal.like(self.rd_addr)
54 sync += rd_delay_addr.eq(self.rd_addr)
55 sync += rd_delay.eq(self.rd_en)
56
57 # write port
58 comb += wrport.addr.eq(self.wr_addr)
59 comb += wrport.en.eq(self.wr_sel)
60 comb += wrport.data.eq(self.wr_data)
61
62 # read port (include a latch on the output, for microwatt compatibility)
63 comb += rdport.addr.eq(self.rd_addr)
64 comb += rdport.en.eq(self.rd_en)
65 with m.If(rd_delay):
66 comb += rd_data0.eq(rdport.data)
67 sync += rd_data0l.eq(rd_data0) # preserve latched data
68 with m.Else():
69 comb += rd_data0.eq(rd_data0l) # output latched (last-read)
70
71 if TRACE:
72 with m.If(rd_delay):
73 sync += Display("read ramno %d a: %%x dat: %%x" % self.ram_num,
74 rd_delay_addr, rd_data0)
75 pass
76
77 # extra delay requested?
78 if ADD_BUF:
79 sync += self.rd_data_o.eq(rd_data0)
80 else:
81 comb += self.rd_data_o.eq(rd_data0)
82
83 return m