1 """ concurrent unit from mitch alsup augmentations to 6600 scoreboard
3 This work is funded through NLnet under Grant 2019-02-012
9 * data goes through a pipeline
10 * results fan back out.
12 the output data format has to have a member "muxid", which is used
13 as the array index on fan-out
15 Associated bugreports:
17 * https://bugs.libre-soc.org/show_bug.cgi?id=538
21 from nmigen
import Module
, Elaboratable
, Signal
22 from nmigen
.asserts
import Assert
23 from nmigen
.cli
import main
, verilog
25 from nmutil
.singlepipe
import PassThroughStage
26 from nmutil
.multipipe
import CombMuxOutPipe
27 from nmutil
.multipipe
import PriorityCombMuxInPipe
31 return int(log(n
) / log(2))
36 def __init__(self
, pspec
):
37 """ creates a pipeline context. currently: operator (op) and muxid
39 opkls (within pspec) - the class to create that will be the
40 "operator". instance must have an "eq"
43 self
.id_wid
= pspec
.id_wid
44 self
.op_wid
= pspec
.op_wid
45 self
.muxid
= Signal(self
.id_wid
, reset_less
=True) # RS multiplex ID
48 self
.op
= Signal(self
.op_wid
, reset_less
=True)
50 self
.op
= opkls(pspec
)
53 ret
= [self
.muxid
.eq(i
.muxid
)]
54 ret
.append(self
.op
.eq(i
.op
))
55 # don't forget to update matches if you add fields later.
58 def matches(self
, another
):
60 Returns a list of Assert()s validating that this context
61 matches the other context.
63 # I couldn't figure a clean way of overloading the == operator.
65 Assert(self
.muxid
== another
.muxid
),
66 Assert(self
.op
== another
.op
),
74 if hasattr(self
.op
, "ports"):
75 return [self
.muxid
] + self
.op
.ports()
80 class InMuxPipe(PriorityCombMuxInPipe
):
81 def __init__(self
, num_rows
, iospecfn
, maskwid
=0):
82 self
.num_rows
= num_rows
83 stage
= PassThroughStage(iospecfn
)
84 PriorityCombMuxInPipe
.__init
__(self
, stage
, p_len
=self
.num_rows
,
88 class MuxOutPipe(CombMuxOutPipe
):
89 def __init__(self
, num_rows
, iospecfn
, maskwid
=0):
90 self
.num_rows
= num_rows
91 stage
= PassThroughStage(iospecfn
)
92 CombMuxOutPipe
.__init
__(self
, stage
, n_len
=self
.num_rows
,
97 """ALUProxy: create a series of ALUs that look like the ALU being
98 sandwiched in between the fan-in and fan-out. One ALU looks like
99 it is multiple concurrent ALUs
101 def __init__(self
, alu
, p
, n
):
107 class ReservationStations(Elaboratable
):
108 """ Reservation-Station pipeline
110 Input: num_rows - number of input and output Reservation Stations
112 Requires: the addition of an "alu" object, from which ispec and ospec
113 are taken, and inpipe and outpipe are connected to it
115 * fan-in on inputs (an array of BaseData: a,b,mid)
117 * fan-out on outputs (an array of FPPackData: z,mid)
119 Fan-in and Fan-out are combinatorial.
121 def __init__(self
, num_rows
, maskwid
=0, feedback_width
=None):
122 self
.num_rows
= nr
= num_rows
123 self
.feedback_width
= feedback_width
124 self
.inpipe
= InMuxPipe(nr
, self
.i_specfn
, maskwid
) # fan-in
125 self
.outpipe
= MuxOutPipe(nr
, self
.o_specfn
, maskwid
) # fan-out
127 self
.p
= self
.inpipe
.p
# kinda annoying,
128 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
129 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
131 def setup_pseudoalus(self
):
132 """setup_pseudoalus: establishes a suite of pseudo-alus
133 that look to all pipeline-intents-and-purposes just like the original
136 for i
in range(self
.num_rows
):
137 self
.pseudoalus
.append(ALUProxy(self
.alu
, self
.p
[i
], self
.n
[i
]))
139 def elaborate(self
, platform
):
141 m
.submodules
.inpipe
= self
.inpipe
142 m
.submodules
.alu
= self
.alu
143 m
.submodules
.outpipe
= self
.outpipe
145 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.alu
.p
)
146 m
.d
.comb
+= self
.alu
.connect_to_next(self
.outpipe
)
148 if self
.feedback_width
is None:
151 # connect all outputs above the feedback width back to their inputs
152 # (hence, feedback). pipeline stages are then expected to *modify*
153 # the muxid (with care) in order to use the "upper numbered" RSes
154 # for storing partially-completed results. micro-coding, basically
156 for i
in range(self
.feedback_width
, self
.num_rows
):
157 self
.outpipe
.n
[i
].connect_to_next(self
.inpipe
.p
[i
])
165 return self
.alu
.ispec()
168 return self
.alu
.ospec()