1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
5 Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
7 dynamically-partitionable "comparison" class, directly equivalent
8 to Signal.__eq__ except SIMD-partitionable
12 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/mux
13 * http://bugs.libre-riscv.org/show_bug.cgi?id=132
16 from nmigen
import Signal
, Module
, Elaboratable
, Mux
17 from ieee754
.part_mul_add
.partpoints
import PartitionPoints
18 from ieee754
.part_mul_add
.partpoints
import make_partition2
21 modcount
= 0 # global for now
22 def PMux(m
, mask
, sel
, a
, b
, ctx
):
25 width
= len(a
.sig
) # get width
26 part_pts
= make_partition2(mask
, width
) # create partition points
27 pm
= PartitionedMux(width
, part_pts
, ctx
)
28 m
.d
.comb
+= pm
.a
.eq(a
.sig
)
29 m
.d
.comb
+= pm
.b
.eq(b
.sig
)
30 m
.d
.comb
+= pm
.sel
.eq(sel
)
31 setattr(m
.submodules
, "pmux%d" % modcount
, pm
)
35 class PartitionedMux(Elaboratable
):
36 """PartitionedMux: Partitioned "Mux"
38 takes a partition point set, subdivides a and b into blocks
39 and "selects" them. the assumption is that "sel" has had
40 its LSB propagated up throughout the entire partition, and
41 consequently the incoming selector (sel) can completely
42 ignore what the *actual* partition bits are.
44 def __init__(self
, width
, partition_points
, ctx
):
47 self
.partition_points
= PartitionPoints(partition_points
)
48 self
.mwidth
= len(self
.partition_points
)+1
49 self
.a
= Signal(width
, reset_less
=True)
50 self
.b
= Signal(width
, reset_less
=True)
51 self
.sel
= Signal(self
.mwidth
, reset_less
=True)
52 self
.output
= Signal(width
, reset_less
=True)
53 assert self
.partition_points
.fits_in_width(width
), \
54 "partition_points doesn't fit in width"
56 def elaborate(self
, platform
):
60 # loop across all partition ranges.
61 # drop the selection directly into the output.
62 keys
= list(self
.partition_points
.keys()) + [self
.width
]
64 for i
in range(len(keys
)):
66 mux
= self
.output
[stt
:end
]
67 comb
+= mux
.eq(Mux(self
.sel
[i
], self
.a
[stt
:end
], self
.b
[stt
:end
]))
68 stt
= end
# for next time round loop
73 return [self
.a
.sig
, self
.b
.sig
, self
.sel
, self
.output
]