[Libre-soc-bugs] [Bug 713] PartitionedSignal enhancement to add partition-context-aware lengths
bugzilla-daemon at libre-soc.org
bugzilla-daemon at libre-soc.org
Fri Oct 8 01:36:29 BST 2021
https://bugs.libre-soc.org/show_bug.cgi?id=713
--- Comment #36 from Jacob Lifshay <programmerjake at gmail.com> ---
(In reply to Luke Kenneth Casson Leighton from comment #34)
> (In reply to Luke Kenneth Casson Leighton from comment #32)
>
> > what are the implications of that being a nmigen AST
> > code-fragment rather than a plain slice on a Signal...
> > i'll have to think that through.
>
> got it.
>
> it wasn't actually whether it's a code-fragment or not at all
> (which comes with inherent risks of AST Expression duplication
> which yosys can *in no way* properly handle and optimise away)
only if you never run `opt`...expression deduplication is a pretty trivial
compiler optimization. In my experience, yosys deduplicates built-in
expressions just fine.
>
> it was the submodules.
we can deduplicate expressions ourselves pretty easily:
def deduped(f):
map = {}
def wrapper(*args, **kwargs):
key0 = []
for arg in args:
key0.append(id(arg))
key1 = []
for k, v in kwargs.items():
key1.append((id(k), id(v)))
key = tuple(key0), tuple(key1)
if key in map:
return map[key][0]
retval = f(*args, **kwargs)
# keep reference to args and kwargs to avoid ids
# getting reused for something else. we can't use weakref,
# too many things don't work with it such as `list` and `dict`
map[key] = retval, args, kwargs
return retval
return wrapper
class PartitionedSignal:
...
@deduped
def __add__(self, other):
...
@deduped
def __sub__(self, other):
...
...
>
> example:
>
> https://git.libre-soc.org/?p=ieee754fpu.git;a=blob;f=src/ieee754/part_ass/
> assign.py;h=00cebc6dab33a25f93d4e790dd7883fc859bae9e;hb=HEAD#l88
>
> that Switch, to support elwidths, would become Switch(self.elwidth)
>
> the next problem is: how do you now reduce the number of Case() statements
> needed to four, or, more to the point, on doing so which bits of data do
> you copy from which partition, without the prerequisite information?
easy, each `part_wid` wide bit slice in any PartitionedSignal can be
independently muxed -- as long as the condition is first converted to the
layout:
{
ElWid.I8: 1,
ElWid.I16: 1,
ElWid.I32: 1,
ElWid.I64: 1,
}
with padding being a sign-extended version of each lane... Aka. the result of
PartitionedSignal.bool(). (or what *should* be the result if design were left
to me).
lanes for elwid=16
0 1 2 3 4 5 6 7
[-u1-pppp][-u1-pppp][-u1-pppp][-u1-pppp]
example value for that layout for elwid==16 and lanes of False, True, False,
True:
0 1 2 3 4 5 6 7
0 0 1 1 0 0 1 1
m.Case simply is an If/Elif that uses the results of
PartitionedSignal.matches() instead of .bool().
a = PartitionedSignal(XLEN - 2)
b = PartitionedSignal(3)
with m.If(a):
with m.Switch(b):
with m.Case('1-0'):
m.d.comb += c.eq(d)
with m.Elif(b == 1):
m.d.sync += e.eq(f)
compiles to (full trace, with unnecessary assignments omitted):
a = PartitionedSignal(XLEN - 2)
b = PartitionedSignal(3)
# If.enter
if_cond = cond_stack[-1] & a.bool()
cond_stack.append(if_cond)
# If body
# Switch.enter
switch_value_stack.append(b)
# Switch body
# Case.enter
case_cond = cond_stack[-1] & switch_value_stack[-1].matches('1-0')
cond_stack.append(case_cond)
# Case body
# assign c.eq(d)
rhs = d.cast_to(c.layout)
for i in range(part_count):
with m.If(cond_stack[-1].sig[i]): # cond_stack all have part_wid == 1
# slice computation should just be c.layout.part_slice(i)
start = c.layout.part_wid * i
s = slice(start, start + c.layout.part_wid)
m.d.comb += c.sig[s].eq(rhs.sig[s])
# Case.exit
cond_stack.pop()
# Switch.exit
switch_value_stack.pop()
# If.exit
else_cond = ~cond_stack.pop()
else_cond &= cond_stack[-1]
# Elif.enter
if_cond = else_cond & (b == 1).bool()
cond_stack.append(if_cond)
# Elif body
# assign e.eq(f)
rhs = f.cast_to(e.layout)
for i in range(part_count):
with m.If(cond_stack[-1].sig[i]): # cond_stack all have part_wid == 1
# slice computation should just be e.layout.part_slice(i)
start = e.layout.part_wid * i
s = slice(start, start + e.layout.part_wid)
m.d.sync += e.sig[s].eq(rhs.sig[s])
# Elif.exit
--
You are receiving this mail because:
You are on the CC list for the bug.
More information about the libre-soc-bugs
mailing list