33
44from .. import tracer
55from ._ast import *
6- from ._ir import Elaboratable , Instance , Fragment
6+ from ._ir import Elaboratable , Fragment
7+ from ..utils import ceil_log2
78
89
910__all__ = ["Memory" , "ReadPort" , "WritePort" , "DummyPort" ]
1011
1112
13+ class MemoryIdentity : pass
14+
15+
16+ class MemorySimRead :
17+ def __init__ (self , identity , addr ):
18+ assert isinstance (identity , MemoryIdentity )
19+ self ._identity = identity
20+ self ._addr = Value .cast (addr )
21+
22+ def eq (self , value ):
23+ return MemorySimWrite (self ._identity , self ._addr , value )
24+
25+
26+ class MemorySimWrite :
27+ def __init__ (self , identity , addr , data ):
28+ assert isinstance (identity , MemoryIdentity )
29+ self ._identity = identity
30+ self ._addr = Value .cast (addr )
31+ self ._data = Value .cast (data )
32+
33+
34+ class MemoryInstance (Fragment ):
35+ class _ReadPort :
36+ def __init__ (self , * , domain , addr , data , en , transparency ):
37+ assert domain is None or isinstance (domain , str )
38+ if domain == "comb" :
39+ domain = None
40+ self ._domain = domain
41+ self ._addr = Value .cast (addr )
42+ self ._data = Value .cast (data )
43+ self ._en = Value .cast (en )
44+ self ._transparency = tuple (transparency )
45+ assert len (self ._en ) == 1
46+ if domain is None :
47+ assert isinstance (self ._en , Const )
48+ assert self ._en .width == 1
49+ assert self ._en .value == 1
50+
51+ class _WritePort :
52+ def __init__ (self , * , domain , addr , data , en ):
53+ assert isinstance (domain , str )
54+ assert domain != "comb"
55+ self ._domain = domain
56+ self ._addr = Value .cast (addr )
57+ self ._data = Value .cast (data )
58+ self ._en = Value .cast (en )
59+ if len (self ._data ):
60+ assert len (self ._data ) % len (self ._en ) == 0
61+
62+ @property
63+ def _granularity (self ):
64+ if not len (self ._data ):
65+ return 1
66+ return len (self ._data ) // len (self ._en )
67+
68+
69+ def __init__ (self , * , identity , width , depth , init = None , attrs = None , src_loc = None ):
70+ super ().__init__ ()
71+ assert isinstance (identity , MemoryIdentity )
72+ self ._identity = identity
73+ self ._width = operator .index (width )
74+ self ._depth = operator .index (depth )
75+ self ._init = tuple (init ) if init is not None else ()
76+ assert len (self ._init ) <= self ._depth
77+ self ._init += (0 ,) * (self ._depth - len (self ._init ))
78+ for x in self ._init :
79+ assert isinstance (x , int )
80+ self ._attrs = attrs or {}
81+ self ._src_loc = src_loc
82+ self ._read_ports = []
83+ self ._write_ports = []
84+
85+ def read_port (self , * , domain , addr , data , en , transparency ):
86+ port = self ._ReadPort (domain = domain , addr = addr , data = data , en = en , transparency = transparency )
87+ assert len (port ._data ) == self ._width
88+ assert len (port ._addr ) == ceil_log2 (self ._depth )
89+ for x in port ._transparency :
90+ assert isinstance (x , int )
91+ assert x in range (len (self ._write_ports ))
92+ for signal in port ._data ._rhs_signals ():
93+ self .add_driver (signal , port ._domain )
94+ self ._read_ports .append (port )
95+
96+ def write_port (self , * , domain , addr , data , en ):
97+ port = self ._WritePort (domain = domain , addr = addr , data = data , en = en )
98+ assert len (port ._data ) == self ._width
99+ assert len (port ._addr ) == ceil_log2 (self ._depth )
100+ self ._write_ports .append (port )
101+ return len (self ._write_ports ) - 1
102+
103+
12104class Memory (Elaboratable ):
13105 """A word addressable storage.
14106
@@ -50,16 +142,10 @@ def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=T
50142 self .depth = depth
51143 self .attrs = OrderedDict (() if attrs is None else attrs )
52144
53- # Array of signals for simulation.
54- self ._array = Array ()
55- if simulate :
56- for addr in range (self .depth ):
57- self ._array .append (Signal (self .width , name = "{}({})"
58- .format (name or "memory" , addr )))
59-
60145 self .init = init
61146 self ._read_ports = []
62147 self ._write_ports = []
148+ self ._identity = MemoryIdentity ()
63149
64150 @property
65151 def init (self ):
@@ -73,11 +159,8 @@ def init(self, new_init):
73159 .format (len (self .init ), self .depth ))
74160
75161 try :
76- for addr in range (len (self ._array )):
77- if addr < len (self ._init ):
78- self ._array [addr ].reset = operator .index (self ._init [addr ])
79- else :
80- self ._array [addr ].reset = 0
162+ for addr , val in enumerate (self ._init ):
163+ operator .index (val )
81164 except TypeError as e :
82165 raise TypeError ("Memory initialization value at address {:x}: {}"
83166 .format (addr , e )) from None
@@ -116,52 +199,24 @@ def write_port(self, *, src_loc_at=0, **kwargs):
116199
117200 def __getitem__ (self , index ):
118201 """Simulation only."""
119- return self ._array [ index ]
202+ return MemorySimRead ( self ._identity , index )
120203
121204 def elaborate (self , platform ):
122- f = MemoryInstance (self , self ._read_ports , self ._write_ports )
205+ f = MemoryInstance (identity = self ._identity , width = self .width , depth = self .depth , init = self .init , attrs = self .attrs , src_loc = self .src_loc )
206+ write_ports = {}
207+ for port in self ._write_ports :
208+ port ._MustUse__used = True
209+ iport = f .write_port (domain = port .domain , addr = port .addr , data = port .data , en = port .en )
210+ write_ports .setdefault (port .domain , []).append (iport )
123211 for port in self ._read_ports :
124212 port ._MustUse__used = True
125213 if port .domain == "comb" :
126- # Asynchronous port
127- f .add_statements (None , port .data .eq (self ._array [port .addr ]))
128- f .add_driver (port .data )
129- else :
130- # Synchronous port
131- data = self ._array [port .addr ]
132- for write_port in self ._write_ports :
133- if port .domain == write_port .domain and port .transparent :
134- if len (write_port .en ) > 1 :
135- parts = []
136- for index , en_bit in enumerate (write_port .en ):
137- offset = index * write_port .granularity
138- bits = slice (offset , offset + write_port .granularity )
139- cond = en_bit & (port .addr == write_port .addr )
140- parts .append (Mux (cond , write_port .data [bits ], data [bits ]))
141- data = Cat (parts )
142- else :
143- cond = write_port .en & (port .addr == write_port .addr )
144- data = Mux (cond , write_port .data , data )
145- f .add_statements (
146- port .domain ,
147- Switch (port .en , {
148- 1 : port .data .eq (data )
149- })
150- )
151- f .add_driver (port .data , port .domain )
152- for port in self ._write_ports :
153- port ._MustUse__used = True
154- if len (port .en ) > 1 :
155- for index , en_bit in enumerate (port .en ):
156- offset = index * port .granularity
157- bits = slice (offset , offset + port .granularity )
158- write_data = self ._array [port .addr ][bits ].eq (port .data [bits ])
159- f .add_statements (port .domain , Switch (en_bit , { 1 : write_data }))
214+ f .read_port (domain = "comb" , addr = port .addr , data = port .data , en = Const (1 ), transparency = ())
160215 else :
161- write_data = self . _array [ port . addr ]. eq ( port . data )
162- f . add_statements ( port . domain , Switch ( port .en , { 1 : write_data }))
163- for signal in self . _array :
164- f .add_driver ( signal , port .domain )
216+ transparency = []
217+ if port .transparent :
218+ transparency = write_ports . get ( port . domain , [])
219+ f .read_port ( domain = port . domain , addr = port .addr , data = port . data , en = port . en , transparency = transparency )
165220 return f
166221
167222
@@ -308,12 +363,3 @@ def __init__(self, *, data_width, addr_width, domain="sync", name=None, granular
308363 name = f"{ name } _data" , src_loc_at = 1 )
309364 self .en = Signal (data_width // granularity ,
310365 name = f"{ name } _en" , src_loc_at = 1 )
311-
312-
313- class MemoryInstance (Fragment ):
314- def __init__ (self , memory , read_ports , write_ports ):
315- super ().__init__ ()
316- self .memory = memory
317- self .read_ports = read_ports
318- self .write_ports = write_ports
319- self .attrs = memory .attrs
0 commit comments