comments on what goes into CommonPipeSpec
[soc.git] / src / soc / fu / pipe_data.py
1 from nmutil.concurrentunit import PipeContext
2 from nmutil.dynamicpipe import SimpleHandshakeRedir
3 from nmigen import Signal
4 from soc.decoder.power_decoder2 import Data
5 from soc.fu.regspec import get_regspec_bitwidth
6
7
8 class IntegerData:
9 """IntegerData: base class for all pipeline data structures
10
11 this class auto-constructs parameters (placing them in self.data)
12 based on "regspecs". this is conceptually similar to nmigen Record
13 (Layout, actually) except that Layout does not contain the right type
14 of information for connecting up to Register Files.
15
16 by having a base class that handles creation of pipeline input/output
17 in a structured fashion, CompUnits may conform to that same structured
18 API, and when it comes to actually connecting up to regfiles, the same
19 holds true.
20
21 the alternative is mountains of explicit code (which quickly becomes
22 unmaintainable).
23
24 note the mode parameter - output. output pipeline data structures
25 need to have an "ok" flag added, which is used by the CompUnit and
26 by the Register File to determine if the output shall in fact be
27 written to the register file or not.
28
29 input data has *already* been determined to have had to have been read,
30 this by PowerDecoder2.
31 """
32
33 def __init__(self, pspec, output):
34 self.ctx = PipeContext(pspec) # context for ReservationStation usage
35 self.muxid = self.ctx.muxid
36 self.data = []
37 self.is_output = output
38 for i, (regfile, regname, widspec) in enumerate(self.regspec):
39 wid = get_regspec_bitwidth([self.regspec], 0, i)
40 if output:
41 sig = Data(wid, name=regname)
42 else:
43 sig = Signal(wid, name=regname, reset_less=True)
44 setattr(self, regname, sig)
45 self.data.append(sig)
46
47 def __iter__(self):
48 yield from self.ctx
49 yield from self.data
50
51 def eq(self, i):
52 eqs = [self.ctx.eq(i.ctx)]
53 assert len(self.data) == len(i.data), \
54 "length of %s mismatch against %s: %s %s" % \
55 (repr(self), repr(i), repr(self.data), repr(i.data))
56 for j in range(len(self.data)):
57 assert type(self.data[j]) == type(i.data[j]), \
58 "type mismatch in IntegerData %s %s" % \
59 (repr(self.data[j]), repr(i.data[j]))
60 eqs.append(self.data[j].eq(i.data[j]))
61 return eqs
62
63 def ports(self):
64 return self.ctx.ports() # TODO: include self.data
65
66
67 # hmmm there has to be a better way than this
68 def get_rec_width(rec):
69 recwidth = 0
70 # Setup random inputs for dut.op
71 for p in rec.ports():
72 width = p.width
73 recwidth += width
74 return recwidth
75
76
77 class CommonPipeSpec:
78 def __init__(self, id_wid):
79 # this defines what type of pipeline base class (dynamic mixin)
80 # is to be used for *ALL* pipelines. replace with MaskCancellableRedir
81 # when the Dependency Matrices are added: mask and stop signals will
82 # then "magically" appear right the way through every single pipeline
83 self.pipekls = SimpleHandshakeRedir
84
85 # this is for the ReservationStation muxid width
86 self.id_wid = id_wid
87
88 # this is the "operation context" which is passed through all pipeline
89 # stages. it is a PowerDecoder2 subset (actually Decode2ToOperand)
90 self.opkls = lambda _: self.opsubsetkls(name="op")
91 self.op_wid = get_rec_width(self.opkls(None)) # hmm..
92
93 # gets set up by Pipeline API.
94 self.stage = None