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>
6 Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
8 dynamically partitionable shifter. Unlike part_shift_scalar, both
9 operands can be partitioned
13 * http://libre-riscv.org/3d_gpu/architecture/dynamic_simd/shift/
14 * http://bugs.libre-riscv.org/show_bug.cgi?id=173
16 from nmigen
import Signal
, Module
, Elaboratable
, Cat
, Mux
17 from ieee754
.part_mul_add
.partpoints
import PartitionPoints
21 class PartitionedDynamicShift(Elaboratable
):
22 def __init__(self
, width
, partition_points
):
24 self
.partition_points
= PartitionPoints(partition_points
)
26 self
.a
= Signal(width
)
27 self
.b
= Signal(width
)
28 self
.output
= Signal(width
)
30 def elaborate(self
, platform
):
34 gates
= Signal(self
.partition_points
.get_max_partition_count(width
)-1)
35 comb
+= gates
.eq(self
.partition_points
.as_sig())
38 keys
= list(self
.partition_points
.keys()) + [self
.width
]
41 # create a matrix of partial shift-results (similar to PartitionedMul
42 # matrices). These however have to be of length suitable to contain
43 # the full shifted "contribution". i.e. B from the LSB *could* contain
44 # a number great enough to shift the entirety of A LSB right up to
45 # the MSB of the output, however B from the *MSB* is *only* going
46 # to contribute to the *MSB* of the output.
47 for i
in range(len(keys
)):
50 for j
in range(len(keys
)):
52 row
.append(Signal(width
- start
,
53 name
="matrix[%d][%d]" % (i
, j
)))
61 for i
in range(len(keys
)):
63 a_intervals
.append(self
.a
[start
:end
])
64 b_intervals
.append(self
.b
[start
:end
])
65 out_intervals
.append(self
.output
[start
:end
])
66 intervals
.append([start
,end
])
69 # actually calculate the shift-partials here
70 for i
, b
in enumerate(b_intervals
):
72 for j
in range(i
, len(a_intervals
)):
75 result_width
= matrix
[i
][j
].width
76 bwidth
= math
.ceil(math
.log2(result_width
+ 1))
77 comb
+= matrix
[i
][j
].eq(a
<< b
[:bwidth
])
80 # now create a switch statement which sums the relevant partial results
81 # in each output-partition
83 intermed
= matrix
[0][0]
84 comb
+= out_intervals
[0].eq(intermed
)
85 for i
in range(1, len(out_intervals
)):
86 index
= gates
[:i
] # selects the 'i' least significant bits
88 element
= Signal(width
, name
="element%d" % i
)
89 for index
in range(1<<i
):
91 with m
.Switch(gates
[:i
]):
93 index
= math
.ceil(math
.log2(index
+ 1))
94 comb
+= element
.eq(matrix
[index
][i
])
96 temp
= Signal(width
, name
="intermed%d" % i
)
97 print(intermed
[keys
[0]:])
98 intermed
= Mux(gates
[i
-1], element
, element | intermed
[keys
[0]:])
99 comb
+= temp
.eq(intermed
)
100 comb
+= out_intervals
[i
].eq(intermed
)