missed critical functions in cut/paste copy of PipeContext
[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.cli import main, verilog
14
15 from nmutil.singlepipe import PassThroughStage
16 from nmutil.multipipe import CombMuxOutPipe
17 from nmutil.multipipe import PriorityCombMuxInPipe
18
19
20 def num_bits(n):
21 return int(log(n) / log(2))
22
23 class PipeContext:
24
25 def __init__(self, pspec):
26 """ creates a pipeline context. currently: operator (op) and muxid
27
28 opkls (within pspec) - the class to create that will be the
29 "operator". instance must have an "eq"
30 function.
31 """
32 self.id_wid = pspec.id_wid
33 self.op_wid = pspec.op_wid
34 self.muxid = Signal(self.id_wid, reset_less=True) # RS multiplex ID
35 opkls = pspec.opkls
36 if opkls is None:
37 self.op = Signal(self.op_wid, reset_less=True)
38 else:
39 self.op = opkls(pspec)
40
41 def eq(self, i):
42 ret = [self.muxid.eq(i.muxid)]
43 ret.append(self.op.eq(i.op))
44 return ret
45
46 def __iter__(self):
47 yield self.muxid
48 yield self.op
49
50 def ports(self):
51 if hasattr(self.op, "ports"):
52 return [self.muxid] + self.op.ports()
53 else:
54 return list(self)
55
56
57 class InMuxPipe(PriorityCombMuxInPipe):
58 def __init__(self, num_rows, iospecfn, maskwid=0):
59 self.num_rows = num_rows
60 stage = PassThroughStage(iospecfn)
61 PriorityCombMuxInPipe.__init__(self, stage, p_len=self.num_rows,
62 maskwid=maskwid)
63
64
65 class MuxOutPipe(CombMuxOutPipe):
66 def __init__(self, num_rows, iospecfn, maskwid=0):
67 self.num_rows = num_rows
68 stage = PassThroughStage(iospecfn)
69 CombMuxOutPipe.__init__(self, stage, n_len=self.num_rows,
70 maskwid=maskwid)
71
72
73 class ReservationStations(Elaboratable):
74 """ Reservation-Station pipeline
75
76 Input: num_rows - number of input and output Reservation Stations
77
78 Requires: the addition of an "alu" object, from which ispec and ospec
79 are taken, and inpipe and outpipe are connected to it
80
81 * fan-in on inputs (an array of BaseData: a,b,mid)
82 * ALU pipeline
83 * fan-out on outputs (an array of FPPackData: z,mid)
84
85 Fan-in and Fan-out are combinatorial.
86 """
87 def __init__(self, num_rows, maskwid=0, feedback_width=None):
88 self.num_rows = nr = num_rows
89 self.feedback_width = feedback_width
90 self.inpipe = InMuxPipe(nr, self.i_specfn, maskwid) # fan-in
91 self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid) # fan-out
92
93 self.p = self.inpipe.p # kinda annoying,
94 self.n = self.outpipe.n # use pipe in/out as this class in/out
95 self._ports = self.inpipe.ports() + self.outpipe.ports()
96
97 def elaborate(self, platform):
98 m = Module()
99 m.submodules.inpipe = self.inpipe
100 m.submodules.alu = self.alu
101 m.submodules.outpipe = self.outpipe
102
103 m.d.comb += self.inpipe.n.connect_to_next(self.alu.p)
104 m.d.comb += self.alu.connect_to_next(self.outpipe)
105
106 if self.feedback_width is None:
107 return m
108
109 # connect all outputs above the feedback width back to their inputs
110 # (hence, feedback). pipeline stages are then expected to *modify*
111 # the muxid (with care) in order to use the "upper numbered" RSes
112 # for storing partially-completed results. micro-coding, basically
113
114 for i in range(self.feedback_width, self.num_rows):
115 self.outpipe.n[i].connect_to_next(self.inpipe.p[i])
116
117 return m
118
119 def ports(self):
120 return self._ports
121
122 def i_specfn(self):
123 return self.alu.ispec()
124
125 def o_specfn(self):
126 return self.alu.ospec()