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