f79f980691510a430caf995b57ec08b0122f4e51
[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 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(FUBaseData):
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, parent_pspec, div_pipe_kind):
133 super().__init__(id_wid=id_wid, parent_pspec=parent_pspec)
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, parent_pspec):
143 super().__init__(id_wid=id_wid,
144 parent_pspec=parent_pspec,
145 div_pipe_kind=DivPipeKind.DivPipeCore)
146
147
148 class DivPipeSpecFSMDivCore(DivPipeSpec):
149 def __init__(self, id_wid, parent_pspec):
150 super().__init__(id_wid=id_wid,
151 parent_pspec=parent_pspec,
152 div_pipe_kind=DivPipeKind.FSMDivCore)
153
154
155 class DivPipeSpecSimOnly(DivPipeSpec):
156 def __init__(self, id_wid, parent_pspec):
157 super().__init__(id_wid=id_wid,
158 parent_pspec=parent_pspec,
159 div_pipe_kind=DivPipeKind.SimOnly)
160
161
162 class CoreBaseData(DivInputData):
163 def __init__(self, pspec, core_data_class):
164 super().__init__(pspec)
165 self.core = core_data_class(pspec.core_config)
166 self.divisor_neg = Signal(reset_less=True)
167 self.dividend_neg = Signal(reset_less=True)
168 self.div_by_zero = Signal(reset_less=True)
169
170 # set if an overflow for divide extended instructions is detected
171 # because `abs_dividend >= abs_divisor` for the appropriate bit width;
172 # 0 if the instruction is not a divide extended instruction
173 self.dive_abs_ov32 = Signal(reset_less=True)
174 self.dive_abs_ov64 = Signal(reset_less=True)
175
176 def __iter__(self):
177 yield from super().__iter__()
178 yield from self.core.__iter__(self)
179 yield self.divisor_neg
180 yield self.dividend_neg
181
182 def eq(self, rhs):
183 return self.eq_without_core(rhs) + self.core.eq(rhs.core)
184
185 def eq_without_core(self, rhs):
186 return super().eq(rhs) + \
187 [self.divisor_neg.eq(rhs.divisor_neg),
188 self.dividend_neg.eq(rhs.dividend_neg),
189 self.dive_abs_ov32.eq(rhs.dive_abs_ov32),
190 self.dive_abs_ov64.eq(rhs.dive_abs_ov64),
191 self.div_by_zero.eq(rhs.div_by_zero)]
192
193
194 class CoreInputData(CoreBaseData):
195 def __init__(self, pspec):
196 super().__init__(pspec,
197 pspec.div_pipe_kind.config.core_input_data_class)
198
199
200 class CoreInterstageData(CoreBaseData):
201 def __init__(self, pspec):
202 data_class = pspec.div_pipe_kind.config.core_interstage_data_class
203 if data_class is None:
204 raise ValueError(
205 f"CoreInterstageData not supported for {pspec.div_pipe_kind}")
206 super().__init__(pspec, data_class)
207
208
209 class CoreOutputData(CoreBaseData):
210 def __init__(self, pspec):
211 super().__init__(pspec,
212 pspec.div_pipe_kind.config.core_output_data_class)