Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / fu / div / pipeline.py
1 from nmutil.singlepipe import ControlBase
2 from nmutil.pipemodbase import PipeModBaseChain
3 from soc.fu.mul.output_stage import DivMulOutputStage
4 from soc.fu.div.input_stage import DivMulInputStage
5 from soc.fu.div.output_stage import DivOutputStage
6 from soc.fu.div.setup_stage import DivSetupStage
7 from soc.fu.div.core_stages import (DivCoreSetupStage, DivCoreCalculateStage,
8 DivCoreFinalStage)
9 from soc.fu.div.pipe_data import DivPipeKindConfigCombPipe
10
11
12 class DivStagesStart(PipeModBaseChain):
13 def get_chain(self):
14 alu_input = DivMulInputStage(self.pspec)
15 return [alu_input]
16
17
18 class DivStagesSetup(PipeModBaseChain):
19 def get_chain(self):
20 div_setup = DivSetupStage(self.pspec)
21 if isinstance(self.pspec.div_pipe_kind.config,
22 DivPipeKindConfigCombPipe):
23 core_setup = [DivCoreSetupStage(self.pspec)]
24 else:
25 core_setup = ()
26 return [div_setup, *core_setup]
27
28
29 class DivStagesMiddle(PipeModBaseChain):
30 def __init__(self, pspec, stage_start_index, stage_end_index):
31 assert isinstance(pspec.div_pipe_kind.config,
32 DivPipeKindConfigCombPipe),\
33 "DivStagesMiddle must be used with a DivPipeKindConfigCombPipe"
34 self.stage_start_index = stage_start_index
35 self.stage_end_index = stage_end_index
36 super().__init__(pspec)
37
38 def get_chain(self):
39 stages = []
40 for index in range(self.stage_start_index, self.stage_end_index):
41 stages.append(DivCoreCalculateStage(self.pspec, index))
42 return stages
43
44
45 class DivStagesEnd(PipeModBaseChain):
46 def get_chain(self):
47 if isinstance(self.pspec.div_pipe_kind.config,
48 DivPipeKindConfigCombPipe):
49 core_final = [DivCoreFinalStage(self.pspec)]
50 else:
51 core_final = ()
52 div_out = DivOutputStage(self.pspec)
53 self.div_out = div_out # debugging - bug #425
54 return [*core_final, div_out]
55
56
57 class DivStagesFinalise(PipeModBaseChain):
58 def get_chain(self):
59 alu_out = DivMulOutputStage(self.pspec)
60 return [alu_out]
61
62
63 class DivBasePipe(ControlBase):
64 def __init__(self, pspec, compute_steps_per_stage=4):
65 ControlBase.__init__(self)
66 self.pspec = pspec
67 self.pipe_start = DivStagesStart(pspec)
68 self.pipe_setup = DivStagesSetup(pspec)
69 self.pipe_middles = []
70 if isinstance(self.pspec.div_pipe_kind.config,
71 DivPipeKindConfigCombPipe):
72 compute_steps = pspec.core_config.n_stages
73 for start in range(0, compute_steps, compute_steps_per_stage):
74 end = min(start + compute_steps_per_stage, compute_steps)
75 self.pipe_middles.append(DivStagesMiddle(pspec, start, end))
76 else:
77 self.pipe_middles.append(
78 self.pspec.div_pipe_kind.config.core_stage_class(pspec))
79 self.pipe_end = DivStagesEnd(pspec)
80 self.pipe_final = DivStagesFinalise(pspec)
81 self._eqs = self.connect([self.pipe_start,
82 self.pipe_setup,
83 *self.pipe_middles,
84 self.pipe_end,
85 self.pipe_final])
86
87 def elaborate(self, platform):
88 m = ControlBase.elaborate(self, platform)
89 m.submodules.pipe_start = self.pipe_start
90 m.submodules.pipe_setup = self.pipe_setup
91 for i in range(len(self.pipe_middles)):
92 name = f"pipe_middle_{i}"
93 setattr(m.submodules, name, self.pipe_middles[i])
94 m.submodules.pipe_end = self.pipe_end
95 m.submodules.pipe_final = self.pipe_final
96 m.d.comb += self._eqs
97 return m