Skip to content

Commit 3398ae9

Browse files
committed
ReadRAM is upgraded like the combination of Variable and RAM, so that RAM assignments are configurable at runtime.
1 parent d574388 commit 3398ae9

File tree

3 files changed

+224
-26
lines changed

3 files changed

+224
-26
lines changed

tests/extension/thread_/stream_read_ram/thread_stream_read_ram.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ def mkLed():
3030
a = strm.source('a')
3131
r_addr = a
3232

33-
r = strm.ReadRAM(ram_ext, r_addr, port=1)
33+
r = strm.read_RAM('ext', r_addr)
3434
b = r + 100
3535

3636
strm.sink(b, 'b')
3737

3838
def comp_stream(size, offset):
3939
strm.set_source('a', ram_a, offset, size)
4040
strm.set_sink('b', ram_b, offset, size)
41+
strm.set_read_RAM('ext', ram_ext)
4142
strm.run()
4243
strm.join()
4344

veriloggen/stream/stypes.py

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3169,48 +3169,66 @@ def _implement(self, m, seq, svalid=None, senable=None):
31693169
self.sig_data = data
31703170

31713171

3172-
class ReadRAM(_UnaryOperator):
3173-
latency = 1
3174-
3175-
def __init__(self, ram, addr, width=None, point=None, signed=True, port=0):
3176-
_UnaryOperator.__init__(self, addr)
3172+
class ReadRAM(_BinaryOperator):
3173+
latency = 3
31773174

3178-
self.ram = ram
3175+
def __init__(self, addr, reset, width=None, point=None, signed=True, ram_name=None):
3176+
_BinaryOperator.__init__(self, addr, reset)
31793177

3180-
if width is None:
3181-
self.width = ram.datawidth
3182-
else:
3178+
if width is not None:
31833179
self.width = width
31843180

3185-
if point is None:
3186-
self.point = 0 if not hasattr(ram, 'point') else ram.point
3187-
else:
3181+
if point is not None:
31883182
self.point = point
31893183

31903184
self.signed = signed
3191-
self.port = port
31923185

3193-
self.graph_label = 'Read ' + ram.name if hasattr(ram, 'name') else 'Read RAM'
3186+
self.graph_label = 'ReadRAM' if ram_name is None else ('ReadRAM\n%s' % ram_name)
31943187
self.graph_shape = 'box'
31953188

31963189
def _implement(self, m, seq, svalid=None, senable=None):
3190+
if self.latency < 2:
3191+
raise ValueError("Latency mismatch '%d' < '%s'" %
3192+
(self.latency, 2))
3193+
3194+
if senable is not None:
3195+
raise NotImplementedError('senable is not supported.')
3196+
31973197
datawidth = self.bit_length()
3198-
addrwidth = int(log(self.ram.length, 2))
31993198
signed = self.get_signed()
3200-
32013199
rdata = m.Wire(self.name('rdata'), datawidth, signed=signed)
3200+
self.read_data = rdata
32023201

3203-
raddr = m.Wire(self.name('raddr'), addrwidth)
3204-
raddr.assign(self.right.sig_data)
3202+
if self.latency == 2:
3203+
data = m.Wire(self.name('data'), datawidth, signed=signed)
3204+
self.sig_data = data
3205+
3206+
elif self.latency == 3:
3207+
data = m.Reg(self.name('data'), datawidth, initval=0, signed=signed)
3208+
self.sig_data = data
3209+
seq(data(rdata), cond=senable)
32053210

3206-
if hasattr(self.ram, 'connect'):
3207-
self.ram.connect(self.port, raddr, 0, 0)
3208-
rdata.assign(self.ram.rdata(self.port))
3211+
else:
3212+
prev_data = None
32093213

3210-
elif hasattr(self.ram, 'connect_rtl'):
3211-
self.ram.connect_rtl(self.port, raddr, 0, 0, rdata)
3214+
for i in range(self.latency - 2):
3215+
data = m.Reg(self.name('data_d%d' % i), datawidth,
3216+
initval=0, signed=signed)
3217+
if i == 0:
3218+
seq(data(rdata), cond=senable)
3219+
else:
3220+
seq(data(prev_data), cond=senable)
3221+
prev_data = data
32123222

3213-
self.sig_data = rdata
3223+
self.sig_data = data
3224+
3225+
@property
3226+
def addr(self):
3227+
return self.left.sig_data
3228+
3229+
@property
3230+
def enable(self):
3231+
return vtypes.Not(self.right.sig_data)
32143232

32153233

32163234
def make_condition(*cond, **kwargs):

veriloggen/thread/stream.py

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class Stream(BaseStream):
4343
'set_sink', 'set_sink_pattern', 'set_sink_multidim',
4444
'set_sink_multipattern', 'set_sink_immediate',
4545
'set_sink_empty', 'set_constant',
46+
'set_read_RAM',
4647
'read_sink',
4748
'run', 'join', 'done',
4849
'source_join', 'source_done',
@@ -100,6 +101,7 @@ def __init__(self, m, name, clk, rst,
100101
self.sinks = OrderedDict()
101102
self.constants = OrderedDict()
102103
self.substreams = []
104+
self.read_rams = OrderedDict()
103105

104106
self.var_name_map = OrderedDict()
105107
self.var_id_map = OrderedDict()
@@ -334,6 +336,40 @@ def substream(self, substrm):
334336
self.substreams.append(sub)
335337
return sub
336338

339+
def read_RAM(self, name, addr, datawidth=None, point=0, signed=True):
340+
if self.stream_synthesized:
341+
raise ValueError(
342+
'cannot modify the stream because already synthesized')
343+
344+
_id = self.var_id_count
345+
if name is None:
346+
name = 'read_ram_%d' % _id
347+
348+
if name in self.var_name_map:
349+
raise ValueError("'%s' is already defined in stream '%s'" %
350+
(name, self.name))
351+
352+
prefix = self._prefix(name)
353+
354+
self.var_id_count += 1
355+
356+
if datawidth is None:
357+
datawidth = self.datawidth
358+
359+
var = self.ReadRAM(addr, width=datawidth, point=point, signed=signed, ram_name=name)
360+
361+
self.read_rams[name] = var
362+
self.var_id_map[_id] = var
363+
self.var_name_map[name] = var
364+
self.var_id_name_map[_id] = name
365+
self.var_name_id_map[name] = _id
366+
367+
var.read_ram_id_map = OrderedDict()
368+
var.read_ram_sel = self.module.Reg('_%s_read_ram_sel' % prefix,
369+
self.ram_sel_width, initval=0)
370+
371+
return var
372+
337373
def set_source(self, fsm, name, ram, offset, size, stride=1, port=0):
338374
""" intrinsic method to assign RAM property to a source stream """
339375

@@ -906,6 +942,35 @@ def set_constant(self, fsm, name, value, raw=False):
906942

907943
fsm.goto_next()
908944

945+
def set_read_RAM(self, fsm, name, ram, port=0):
946+
""" intrinsic method to assign RAM property to a read-RAM interface """
947+
948+
if not self.stream_synthesized:
949+
self._implement_stream()
950+
951+
if isinstance(name, str):
952+
var = self.var_name_map[name]
953+
elif isinstance(name, vtypes.Str):
954+
name = name.value
955+
var = self.var_name_map[name]
956+
elif isinstance(name, int):
957+
var = self.var_id_map[name]
958+
elif isinstance(name, vtypes.Int):
959+
name = name.value
960+
var = self.var_id_map[name]
961+
else:
962+
raise TypeError('Unsupported index name')
963+
964+
if name not in self.read_rams:
965+
raise NameError("No such stream '%s'" % name)
966+
967+
set_cond = self._set_flag(fsm)
968+
969+
port = vtypes.to_int(port)
970+
self._setup_read_ram(ram, var, port, set_cond)
971+
972+
fsm.goto_next()
973+
909974
def read_sink(self, fsm, name):
910975
""" intrinsic method to read the last output of a sink stream """
911976

@@ -2110,6 +2175,119 @@ def _synthesize_set_sink_multipattern(self, var, name):
21102175
var.sink_multipat_num_patterns == 0).goto_init()
21112176
var.sink_multipat_fsm.If(self.term_sink).goto_init()
21122177

2178+
def _setup_read_ram(self, ram, var, port, set_cond):
2179+
if ram._id() in var.read_ram_id_map:
2180+
ram_id = var.read_ram_id_map[ram._id()]
2181+
self.seq.If(set_cond)(
2182+
var.read_ram_sel(ram_id)
2183+
)
2184+
return
2185+
2186+
if ram._id() not in self.ram_id_map:
2187+
ram_id = self.ram_id_count
2188+
self.ram_id_count += 1
2189+
self.ram_id_map[ram._id()] = ram_id
2190+
else:
2191+
ram_id = self.ram_id_map[ram._id()]
2192+
2193+
var.read_ram_id_map[ram._id()] = ram_id
2194+
2195+
self.seq.If(set_cond)(
2196+
var.read_ram_sel(ram_id)
2197+
)
2198+
2199+
ram_cond = (var.read_ram_sel == ram_id)
2200+
renable = vtypes.Ands(var.enable, ram_cond)
2201+
2202+
d, v = ram.read_rtl(var.addr, port=port, cond=renable)
2203+
add_mux(var.read_data, ram_cond, d)
2204+
2205+
if (self.dump and
2206+
(self.dump_mode == 'all' or
2207+
self.dump_mode == 'ram' or
2208+
(self.dump_mode == 'selective' and
2209+
hasattr(ram, 'dump') and ram.dump))):
2210+
self._setup_read_ram_dump(ram, var, renable, d)
2211+
2212+
def _setup_read_ram_dump(self, ram, var, read_enable, read_data):
2213+
pipeline_depth = self.pipeline_depth()
2214+
log_pipeline_depth = max(
2215+
int(math.ceil(math.log(max(pipeline_depth, 10), 10))), 1)
2216+
2217+
addr_base = (ram.dump_addr_base if hasattr(ram, 'dump_addr_base') else
2218+
self.dump_base)
2219+
addr_base_char = ('b' if addr_base == 2 else
2220+
'o' if addr_base == 8 else
2221+
'd' if addr_base == 10 else
2222+
'x')
2223+
addr_prefix = ('0b' if addr_base == 2 else
2224+
'0o' if addr_base == 8 else
2225+
' ' if addr_base == 10 else
2226+
'0x')
2227+
addr_vfmt = ''.join([addr_prefix, '%', addr_base_char])
2228+
2229+
data_base = (ram.dump_data_base if hasattr(ram, 'dump_data_base') else
2230+
self.dump_base)
2231+
data_base_char = ('b' if data_base == 2 else
2232+
'o' if data_base == 8 else
2233+
'd' if (data_base == 10 and
2234+
(not hasattr(ram, 'point') or ram.point <= 0)) else
2235+
# 'f' if (data_base == 10 and
2236+
# hasattr(ram, 'point') and ram.point > 0) else
2237+
'g' if (data_base == 10 and
2238+
hasattr(ram, 'point') and ram.point > 0) else
2239+
'x')
2240+
data_prefix = ('0b' if data_base == 2 else
2241+
'0o' if data_base == 8 else
2242+
' ' if data_base == 10 else
2243+
'0x')
2244+
# if data_base_char == 'f':
2245+
# point_len = int(math.ceil(ram.point / math.log(10, 2)))
2246+
# point_len = max(point_len, 8)
2247+
# total_len = int(math.ceil(ram.datawidth / math.log(10, 2)))
2248+
# total_len = max(total_len, point_len)
2249+
# data_vfmt = ''.join([data_prefix, '%',
2250+
# '%d.%d' % (total_len + 1, point_len),
2251+
# data_base_char])
2252+
# else:
2253+
# data_vfmt = ''.join([data_prefix, '%', data_base_char])
2254+
data_vfmt = ''.join([data_prefix, '%', data_base_char])
2255+
2256+
name = ram.name
2257+
fmt = ''.join(['(', self.name, ' step:%d, ',
2258+
'read, ', ' ' * (log_pipeline_depth + 2),
2259+
'age:%d) ', name,
2260+
'[', addr_vfmt, '] = ', data_vfmt])
2261+
2262+
dump_ram_step_name = ('_stream_dump_ram_step_%d_%s' %
2263+
(self.object_id, name))
2264+
dump_ram_step = self.module.Reg(dump_ram_step_name, 32, initval=0)
2265+
2266+
enable = self.seq.Prev(read_enable, 2)
2267+
age = dump_ram_step
2268+
addr = self.seq.Prev(var.addr, 2)
2269+
if hasattr(ram, 'point') and ram.point > 0:
2270+
data = vtypes.Div(vtypes.SystemTask('itor', read_data),
2271+
1.0 * (2 ** ram.point))
2272+
elif hasattr(ram, 'point') and ram.point < 0:
2273+
data = vtypes.Times(read_data, 2 ** -ram.point)
2274+
else:
2275+
data = read_data
2276+
2277+
self.seq(
2278+
dump_ram_step(0)
2279+
)
2280+
self.seq.If(enable)(
2281+
dump_ram_step.inc()
2282+
)
2283+
self.seq.If(self.dump_enable)(
2284+
dump_ram_step.inc()
2285+
)
2286+
2287+
self.seq.If(enable, vtypes.Not(self.dump_mask))(
2288+
vtypes.Display(fmt, dump_ram_step, age, addr, data)
2289+
)
2290+
21132291
def _set_flag(self, fsm, prefix='_set_flag'):
21142292
flag = self.module.TmpReg(initval=0, prefix=prefix)
21152293
cond = fsm.here
@@ -2166,7 +2344,8 @@ def __getattr__(self, attr):
21662344
f.__name__.startswith('Counter') or
21672345
f.__name__.startswith('Pulse') or
21682346
f.__name__.startswith('RingBuffer') or
2169-
f.__name__.startswith('Scratchpad'))):
2347+
f.__name__.startswith('Scratchpad') or
2348+
f.__name__.startswith('ReadRAM'))):
21702349
if self.reduce_reset is None:
21712350
self.reduce_reset = self.module.Reg(
21722351
'_'.join(['', self.name, 'reduce_reset']), initval=1)

0 commit comments

Comments
 (0)