3
3
4
4
from .. import tracer
5
5
from ._ast import *
6
- from ._ir import Elaboratable , Instance , Fragment
6
+ from ._ir import Elaboratable , Fragment
7
+ from ..utils import ceil_log2
7
8
8
9
9
10
__all__ = ["Memory" , "ReadPort" , "WritePort" , "DummyPort" ]
10
11
11
12
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
+
12
104
class Memory (Elaboratable ):
13
105
"""A word addressable storage.
14
106
@@ -50,16 +142,10 @@ def __init__(self, *, width, depth, init=None, name=None, attrs=None, simulate=T
50
142
self .depth = depth
51
143
self .attrs = OrderedDict (() if attrs is None else attrs )
52
144
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
-
60
145
self .init = init
61
146
self ._read_ports = []
62
147
self ._write_ports = []
148
+ self ._identity = MemoryIdentity ()
63
149
64
150
@property
65
151
def init (self ):
@@ -73,11 +159,8 @@ def init(self, new_init):
73
159
.format (len (self .init ), self .depth ))
74
160
75
161
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 )
81
164
except TypeError as e :
82
165
raise TypeError ("Memory initialization value at address {:x}: {}"
83
166
.format (addr , e )) from None
@@ -116,52 +199,24 @@ def write_port(self, *, src_loc_at=0, **kwargs):
116
199
117
200
def __getitem__ (self , index ):
118
201
"""Simulation only."""
119
- return self ._array [ index ]
202
+ return MemorySimRead ( self ._identity , index )
120
203
121
204
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 )
123
211
for port in self ._read_ports :
124
212
port ._MustUse__used = True
125
213
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 = ())
160
215
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 )
165
220
return f
166
221
167
222
@@ -308,12 +363,3 @@ def __init__(self, *, data_width, addr_width, domain="sync", name=None, granular
308
363
name = f"{ name } _data" , src_loc_at = 1 )
309
364
self .en = Signal (data_width // granularity ,
310
365
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