add extra name in plru for debugging
[nmutil.git] / src / nmutil / concurrentunit.py
1 """ concurrent unit from mitch alsup augmentations to 6600 scoreboard
2
3 * data fans in
4 * data goes through a pipeline
5 * results fan back out.
6
7 the output data format has to have a member "muxid", which is used
8 as the array index on fan-out
9 """
10
11 from math import log
12 from nmigen import Module, Elaboratable, Signal
13 from nmigen.asserts import Assert
14 from nmigen.cli import main, verilog
15
16 from nmutil.singlepipe import PassThroughStage
17 from nmutil.multipipe import CombMuxOutPipe
18 from nmutil.multipipe import PriorityCombMuxInPipe
19
20
21 def num_bits(n):
22 return int(log(n) / log(2))
23
24 class PipeContext:
25
26 def __init__(self, pspec):
27 """ creates a pipeline context. currently: operator (op) and muxid
28
29 opkls (within pspec) - the class to create that will be the
30 "operator". instance must have an "eq"
31 function.
32 """
33 self.id_wid = pspec.id_wid
34 self.op_wid = pspec.op_wid
35 self.muxid = Signal(self.id_wid, reset_less=True) # RS multiplex ID
36 opkls = pspec.opkls
37 if opkls is None:
38 self.op = Signal(self.op_wid, reset_less=True)
39 else:
40 self.op = opkls(pspec)
41
42 def eq(self, i):
43 ret = [self.muxid.eq(i.muxid)]
44 ret.append(self.op.eq(i.op))
45 # don't forget to update matches if you add fields later.
46 return ret
47
48 def matches(self, another):
49 """
50 Returns a list of Assert()s validating that this context
51 matches the other context.
52 """
53 # I couldn't figure a clean way of overloading the == operator.
54 return [
55 Assert(self.muxid == another.muxid),
56 Assert(self.op == another.op),
57 ]
58
59 def __iter__(self):
60 yield self.muxid
61 yield self.op
62
63 def ports(self):
64 if hasattr(self.op, "ports"):
65 return [self.muxid] + self.op.ports()
66 else:
67 return list(self)
68
69
70 class InMuxPipe(PriorityCombMuxInPipe):
71 def __init__(self, num_rows, iospecfn, maskwid=0):
72 self.num_rows = num_rows
73 stage = PassThroughStage(iospecfn)
74 PriorityCombMuxInPipe.__init__(self, stage, p_len=self.num_rows,
75 maskwid=maskwid)
76
77
78 class MuxOutPipe(CombMuxOutPipe):
79 def __init__(self, num_rows, iospecfn, maskwid=0):
80 self.num_rows = num_rows
81 stage = PassThroughStage(iospecfn)
82 CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows,
83 maskwid=maskwid)
84
85
86 class ReservationStations(Elaboratable):
87 """ Reservation-Station pipeline
88
89 Input: num_rows - number of input and output Reservation Stations
90
91 Requires: the addition of an "alu" object, from which ispec and ospec
92 are taken, and inpipe and outpipe are connected to it
93
94 * fan-in on inputs (an array of BaseData: a,b,mid)
95 * ALU pipeline
96 * fan-out on outputs (an array of FPPackData: z,mid)
97
98 Fan-in and Fan-out are combinatorial.
99 """
100 def __init__(self, num_rows, maskwid=0, feedback_width=None):
101 self.num_rows = nr = num_rows
102 self.feedback_width = feedback_width
103 self.inpipe = InMuxPipe(nr, self.i_specfn, maskwid) # fan-in
104 self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid) # fan-out
105
106 self.p = self.inpipe.p # kinda annoying,
107 self.n = self.outpipe.n # use pipe in/out as this class in/out
108 self._ports = self.inpipe.ports() + self.outpipe.ports()
109
110 def elaborate(self, platform):
111 m = Module()
112 m.submodules.inpipe = self.inpipe
113 m.submodules.alu = self.alu
114 m.submodules.outpipe = self.outpipe
115
116 m.d.comb += self.inpipe.n.connect_to_next(self.alu.p)
117 m.d.comb += self.alu.connect_to_next(self.outpipe)
118
119 if self.feedback_width is None:
120 return m
121
122 # connect all outputs above the feedback width back to their inputs
123 # (hence, feedback). pipeline stages are then expected to *modify*
124 # the muxid (with care) in order to use the "upper numbered" RSes
125 # for storing partially-completed results. micro-coding, basically
126
127 for i in range(self.feedback_width, self.num_rows):
128 self.outpipe.n[i].connect_to_next(self.inpipe.p[i])
129
130 return m
131
132 def ports(self):
133 return self._ports
134
135 def i_specfn(self):
136 return self.alu.ispec()
137
138 def o_specfn(self):
139 return self.alu.ospec()