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
,
96 class ReservationStations(Elaboratable
):
97 """ Reservation-Station pipeline
99 Input: num_rows - number of input and output Reservation Stations
101 Requires: the addition of an "alu" object, from which ispec and ospec
102 are taken, and inpipe and outpipe are connected to it
104 * fan-in on inputs (an array of BaseData: a,b,mid)
106 * fan-out on outputs (an array of FPPackData: z,mid)
108 Fan-in and Fan-out are combinatorial.
110 def __init__(self
, num_rows
, maskwid
=0, feedback_width
=None):
111 self
.num_rows
= nr
= num_rows
112 self
.feedback_width
= feedback_width
113 self
.inpipe
= InMuxPipe(nr
, self
.i_specfn
, maskwid
) # fan-in
114 self
.outpipe
= MuxOutPipe(nr
, self
.o_specfn
, maskwid
) # fan-out
116 self
.p
= self
.inpipe
.p
# kinda annoying,
117 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
118 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
120 def elaborate(self
, platform
):
122 m
.submodules
.inpipe
= self
.inpipe
123 m
.submodules
.alu
= self
.alu
124 m
.submodules
.outpipe
= self
.outpipe
126 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.alu
.p
)
127 m
.d
.comb
+= self
.alu
.connect_to_next(self
.outpipe
)
129 if self
.feedback_width
is None:
132 # connect all outputs above the feedback width back to their inputs
133 # (hence, feedback). pipeline stages are then expected to *modify*
134 # the muxid (with care) in order to use the "upper numbered" RSes
135 # for storing partially-completed results. micro-coding, basically
137 for i
in range(self
.feedback_width
, self
.num_rows
):
138 self
.outpipe
.n
[i
].connect_to_next(self
.inpipe
.p
[i
])
146 return self
.alu
.ispec()
149 return self
.alu
.ospec()