Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / fu / div / pipe_data.py
1 import enum
2 from nmigen import Signal, Const
3 from soc.fu.pipe_data import FUBaseData
4 from soc.fu.alu.pipe_data import CommonPipeSpec
5 from soc.fu.logical.logical_input_record import CompLogicalOpSubset
6 from ieee754.div_rem_sqrt_rsqrt.core import (
7 DivPipeCoreConfig, DivPipeCoreInputData, DP,
8 DivPipeCoreInterstageData, DivPipeCoreOutputData,
9 DivPipeCoreSetupStage, DivPipeCoreCalculateStage, DivPipeCoreFinalStage)
10
11
12 class DivInputData(FUBaseData):
13 def __init__(self, pspec):
14 super().__init__(pspec, False)
15 # convenience
16 self.a, self.b = self.ra, self.rb
17
18 @property
19 def regspec(self):
20 return [('INT', 'ra', self.intrange), # RA
21 ('INT', 'rb', self.intrange), # RB/immediate
22 ('XER', 'xer_so', '32'), ] # XER bit 32: SO
23
24
25 # output stage shared between div and mul: like ALUOutputData but no CA/32
26 class DivMulOutputData(FUBaseData):
27
28 def __init__(self, pspec):
29 super().__init__(pspec, True)
30 # convenience
31 self.cr0 = self.cr_a
32
33 @property
34 def regspec(self):
35 return [('INT', 'o', self.intrange),
36 ('CR', 'cr_a', '0:3'),
37 ('XER', 'xer_ov', '33,44'), # bit0: ov, bit1: ov32
38 ('XER', 'xer_so', '32')]
39
40
41 class DivPipeKindConfigBase:
42 def __init__(self,
43 core_config,
44 core_input_data_class,
45 core_interstage_data_class,
46 core_output_data_class):
47 self.core_config = core_config
48 self.core_input_data_class = core_input_data_class
49 self.core_interstage_data_class = core_interstage_data_class
50 self.core_output_data_class = core_output_data_class
51
52
53 class DivPipeKindConfigCombPipe(DivPipeKindConfigBase):
54 def __init__(self,
55 core_config,
56 core_input_data_class,
57 core_interstage_data_class,
58 core_output_data_class,
59 core_setup_stage_class,
60 core_calculate_stage_class,
61 core_final_stage_class):
62 super().__init__(core_config, core_input_data_class,
63 core_interstage_data_class, core_output_data_class)
64 self.core_setup_stage_class = core_setup_stage_class
65 self.core_calculate_stage_class = core_calculate_stage_class
66 self.core_final_stage_class = core_final_stage_class
67
68
69 class DivPipeKindConfigFSM(DivPipeKindConfigBase):
70 def __init__(self,
71 core_config,
72 core_input_data_class,
73 core_output_data_class,
74 core_stage_class):
75 core_interstage_data_class = None
76 super().__init__(core_config, core_input_data_class,
77 core_interstage_data_class, core_output_data_class)
78 self.core_stage_class = core_stage_class
79
80
81 class DivPipeKind(enum.Enum):
82 # use ieee754.div_rem_sqrt_rsqrt.core.DivPipeCore*
83 DivPipeCore = enum.auto()
84 # use nmigen's built-in div and rem operators -- only suitable for
85 # simulation
86 SimOnly = enum.auto()
87 # use a FSM-based div core
88 FSMDivCore = enum.auto()
89
90 @property
91 def config(self):
92 if self == DivPipeKind.DivPipeCore:
93 return DivPipeKindConfigCombPipe(
94 core_config=DivPipeCoreConfig(
95 bit_width=64,
96 fract_width=64,
97 log2_radix=1,
98 supported=[DP.UDivRem]
99 ),
100 core_input_data_class=DivPipeCoreInputData,
101 core_interstage_data_class=DivPipeCoreInterstageData,
102 core_output_data_class=DivPipeCoreOutputData,
103 core_setup_stage_class=DivPipeCoreSetupStage,
104 core_calculate_stage_class=DivPipeCoreCalculateStage,
105 core_final_stage_class=DivPipeCoreFinalStage)
106 if self == DivPipeKind.SimOnly:
107 # import here to avoid import loop
108 from soc.fu.div.sim_only_core import (
109 SimOnlyCoreConfig, SimOnlyCoreInputData,
110 SimOnlyCoreInterstageData, SimOnlyCoreOutputData,
111 SimOnlyCoreSetupStage, SimOnlyCoreCalculateStage,
112 SimOnlyCoreFinalStage)
113 return DivPipeKindConfigCombPipe(
114 core_config=SimOnlyCoreConfig(),
115 core_input_data_class=SimOnlyCoreInputData,
116 core_interstage_data_class=SimOnlyCoreInterstageData,
117 core_output_data_class=SimOnlyCoreOutputData,
118 core_setup_stage_class=SimOnlyCoreSetupStage,
119 core_calculate_stage_class=SimOnlyCoreCalculateStage,
120 core_final_stage_class=SimOnlyCoreFinalStage)
121 # ensure we didn't forget any cases
122 # -- I wish Python had a switch/match statement
123 assert self == DivPipeKind.FSMDivCore
124
125 # import here to avoid import loop
126 from soc.fu.div.fsm import (
127 FSMDivCoreConfig, FSMDivCoreInputData,
128 FSMDivCoreOutputData, FSMDivCoreStage)
129 return DivPipeKindConfigFSM(
130 core_config=FSMDivCoreConfig(),
131 core_input_data_class=FSMDivCoreInputData,
132 core_output_data_class=FSMDivCoreOutputData,
133 core_stage_class=FSMDivCoreStage)
134
135
136 class DivPipeSpec(CommonPipeSpec):
137 def __init__(self, id_wid, parent_pspec, div_pipe_kind):
138 super().__init__(id_wid=id_wid, parent_pspec=parent_pspec)
139 self.div_pipe_kind = div_pipe_kind
140 self.core_config = div_pipe_kind.config.core_config
141
142 regspecklses = (DivInputData, DivMulOutputData)
143 opsubsetkls = CompLogicalOpSubset
144
145
146 class DivPipeSpecDivPipeCore(DivPipeSpec):
147 def __init__(self, id_wid, parent_pspec):
148 super().__init__(id_wid=id_wid,
149 parent_pspec=parent_pspec,
150 div_pipe_kind=DivPipeKind.DivPipeCore)
151
152
153 class DivPipeSpecFSMDivCore(DivPipeSpec):
154 def __init__(self, id_wid, parent_pspec):
155 super().__init__(id_wid=id_wid,
156 parent_pspec=parent_pspec,
157 div_pipe_kind=DivPipeKind.FSMDivCore)
158
159
160 class DivPipeSpecSimOnly(DivPipeSpec):
161 def __init__(self, id_wid, parent_pspec):
162 super().__init__(id_wid=id_wid,
163 parent_pspec=parent_pspec,
164 div_pipe_kind=DivPipeKind.SimOnly)
165
166
167 class CoreBaseData(DivInputData):
168 def __init__(self, pspec, core_data_class):
169 super().__init__(pspec)
170 self.core = core_data_class(pspec.core_config)
171 self.divisor_neg = Signal(reset_less=True)
172 self.dividend_neg = Signal(reset_less=True)
173 self.div_by_zero = Signal(reset_less=True)
174
175 # set if an overflow for divide extended instructions is detected
176 # because `abs_dividend >= abs_divisor` for the appropriate bit width;
177 # 0 if the instruction is not a divide extended instruction
178 self.dive_abs_ov32 = Signal(reset_less=True)
179 self.dive_abs_ov64 = Signal(reset_less=True)
180
181 def __iter__(self):
182 yield from super().__iter__()
183 yield from self.core.__iter__(self)
184 yield self.divisor_neg
185 yield self.dividend_neg
186
187 def eq(self, rhs):
188 return self.eq_without_core(rhs) + self.core.eq(rhs.core)
189
190 def eq_without_core(self, rhs):
191 return super().eq(rhs) + \
192 [self.divisor_neg.eq(rhs.divisor_neg),
193 self.dividend_neg.eq(rhs.dividend_neg),
194 self.dive_abs_ov32.eq(rhs.dive_abs_ov32),
195 self.dive_abs_ov64.eq(rhs.dive_abs_ov64),
196 self.div_by_zero.eq(rhs.div_by_zero)]
197
198
199 class CoreInputData(CoreBaseData):
200 def __init__(self, pspec):
201 super().__init__(pspec,
202 pspec.div_pipe_kind.config.core_input_data_class)
203
204
205 class CoreInterstageData(CoreBaseData):
206 def __init__(self, pspec):
207 data_class = pspec.div_pipe_kind.config.core_interstage_data_class
208 if data_class is None:
209 raise ValueError(
210 f"CoreInterstageData not supported for {pspec.div_pipe_kind}")
211 super().__init__(pspec, data_class)
212
213
214 class CoreOutputData(CoreBaseData):
215 def __init__(self, pspec):
216 super().__init__(pspec,
217 pspec.div_pipe_kind.config.core_output_data_class)