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