970ac7cfb5c476b6020fdeccadc7b9f4d4b3ff00
[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 DivPipeKindConfig:
37 def __init__(self,
38 core_config,
39 core_input_data_class,
40 core_interstage_data_class,
41 core_output_data_class,
42 core_setup_stage_class,
43 core_calculate_stage_class,
44 core_final_stage_class):
45 self.core_config = core_config
46 self.core_input_data_class = core_input_data_class
47 self.core_interstage_data_class = core_interstage_data_class
48 self.core_output_data_class = core_output_data_class
49 self.core_setup_stage_class = core_setup_stage_class
50 self.core_calculate_stage_class = core_calculate_stage_class
51 self.core_final_stage_class = core_final_stage_class
52
53
54 class DivPipeKind(enum.Enum):
55 # use ieee754.div_rem_sqrt_rsqrt.core.DivPipeCore*
56 DivPipeCore = enum.auto()
57 # use nmigen's built-in div and rem operators -- only suitable for simulation
58 SimOnly = enum.auto()
59 # use a FSM-based div core
60 FSMCore = enum.auto()
61
62 @property
63 def config(self):
64 if self == DivPipeKind.DivPipeCore:
65 return DivPipeKindConfig(
66 core_config=DivPipeCoreConfig(
67 bit_width=64,
68 fract_width=64,
69 log2_radix=1,
70 supported=[DP.UDivRem]
71 ),
72 core_input_data_class=DivPipeCoreInputData,
73 core_interstage_data_class=DivPipeCoreInterstageData,
74 core_output_data_class=DivPipeCoreOutputData,
75 core_setup_stage_class=DivPipeCoreSetupStage,
76 core_calculate_stage_class=DivPipeCoreCalculateStage,
77 core_final_stage_class=DivPipeCoreFinalStage)
78 elif self == DivPipeKind.SimOnly:
79 # import here to avoid import loop
80 from soc.fu.div.sim_only_core import (
81 SimOnlyCoreConfig, SimOnlyCoreInputData,
82 SimOnlyCoreInterstageData, SimOnlyCoreOutputData,
83 SimOnlyCoreSetupStage, SimOnlyCoreCalculateStage,
84 SimOnlyCoreFinalStage)
85 return DivPipeKindConfig(
86 core_config=SimOnlyCoreConfig(),
87 core_input_data_class=SimOnlyCoreInputData,
88 core_interstage_data_class=SimOnlyCoreInterstageData,
89 core_output_data_class=SimOnlyCoreOutputData,
90 core_setup_stage_class=SimOnlyCoreSetupStage,
91 core_calculate_stage_class=SimOnlyCoreCalculateStage,
92 core_final_stage_class=SimOnlyCoreFinalStage)
93 else:
94 # ensure we didn't forget any cases
95 # -- I wish Python had a switch/match statement
96 assert self == DivPipeKind.FSMCore
97 # TODO(programmerjake): implement
98 raise NotImplementedError()
99
100
101 class DivPipeSpec(CommonPipeSpec):
102 def __init__(self, id_wid, div_pipe_kind):
103 super().__init__(id_wid=id_wid)
104 self.div_pipe_kind = div_pipe_kind
105 self.core_config = div_pipe_kind.config.core_config
106
107 regspec = (DivInputData.regspec, DivMulOutputData.regspec)
108 opsubsetkls = CompLogicalOpSubset
109
110
111 class CoreBaseData(DivInputData):
112 def __init__(self, pspec, core_data_class):
113 super().__init__(pspec)
114 self.core = core_data_class(pspec.core_config)
115 self.divisor_neg = Signal(reset_less=True)
116 self.dividend_neg = Signal(reset_less=True)
117 self.div_by_zero = Signal(reset_less=True)
118
119 # set if an overflow for divide extended instructions is detected
120 # because `abs_dividend >= abs_divisor` for the appropriate bit width;
121 # 0 if the instruction is not a divide extended instruction
122 self.dive_abs_ov32 = Signal(reset_less=True)
123 self.dive_abs_ov64 = Signal(reset_less=True)
124
125 def __iter__(self):
126 yield from super().__iter__()
127 yield from self.core.__iter__(self)
128 yield self.divisor_neg
129 yield self.dividend_neg
130
131 def eq(self, rhs):
132 return self.eq_without_core(rhs) + self.core.eq(rhs.core)
133
134 def eq_without_core(self, rhs):
135 return super().eq(rhs) + \
136 [self.divisor_neg.eq(rhs.divisor_neg),
137 self.dividend_neg.eq(rhs.dividend_neg),
138 self.dive_abs_ov32.eq(rhs.dive_abs_ov32),
139 self.dive_abs_ov64.eq(rhs.dive_abs_ov64),
140 self.div_by_zero.eq(rhs.div_by_zero)]
141
142
143 class CoreInputData(CoreBaseData):
144 def __init__(self, pspec):
145 super().__init__(pspec, pspec.div_pipe_kind.config.core_input_data_class)
146
147
148 class CoreInterstageData(CoreBaseData):
149 def __init__(self, pspec):
150 super().__init__(pspec, pspec.div_pipe_kind.config.core_interstage_data_class)
151
152
153 class CoreOutputData(CoreBaseData):
154 def __init__(self, pspec):
155 super().__init__(pspec, pspec.div_pipe_kind.config.core_output_data_class)