fb7f3b26998679b624b5a03c255a0b063ce2e4d0
[ieee754fpu.git] / src / ieee754 / fpcommon / getop.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat, Mux, Array, Const, Elaboratable
6 from nmigen.lib.coding import PriorityEncoder
7 from nmigen.cli import main, verilog
8 from math import log
9
10 from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPOpIn, Overflow, FPBase, FPNumBase
11 from ieee754.fpcommon.fpbase import MultiShiftRMerge, Trigger
12 from nmutil.singlepipe import (ControlBase, StageChain, SimpleHandshake,
13 PassThroughStage, PrevControl)
14 from nmutil.multipipe import CombMuxOutPipe
15 from nmutil.multipipe import PriorityCombMuxInPipe
16
17 from ieee754.fpcommon.fpbase import FPState
18 from nmutil import nmoperator
19
20
21 class FPGetOpMod(Elaboratable):
22 def __init__(self, width):
23 self.in_op = FPOpIn(width)
24 self.in_op.data_i = Signal(width)
25 self.out_op = Signal(width)
26 self.out_decode = Signal(reset_less=True)
27
28 def elaborate(self, platform):
29 m = Module()
30 m.d.comb += self.out_decode.eq((self.in_op.ready_o) & \
31 (self.in_op.valid_i_test))
32 m.submodules.get_op_in = self.in_op
33 #m.submodules.get_op_out = self.out_op
34 with m.If(self.out_decode):
35 m.d.comb += [
36 self.out_op.eq(self.in_op.v),
37 ]
38 return m
39
40
41 class FPGetOp(FPState):
42 """ gets operand
43 """
44
45 def __init__(self, in_state, out_state, in_op, width):
46 FPState.__init__(self, in_state)
47 self.out_state = out_state
48 self.mod = FPGetOpMod(width)
49 self.in_op = in_op
50 self.out_op = Signal(width)
51 self.out_decode = Signal(reset_less=True)
52
53 def setup(self, m, in_op):
54 """ links module to inputs and outputs
55 """
56 setattr(m.submodules, self.state_from, self.mod)
57 m.d.comb += nmoperator.eq(self.mod.in_op, in_op)
58 m.d.comb += self.out_decode.eq(self.mod.out_decode)
59
60 def action(self, m):
61 with m.If(self.out_decode):
62 m.next = self.out_state
63 m.d.sync += [
64 self.in_op.ready_o.eq(0),
65 self.out_op.eq(self.mod.out_op)
66 ]
67 with m.Else():
68 m.d.sync += self.in_op.ready_o.eq(1)
69
70
71 class FPNumBase2Ops:
72
73 def __init__(self, width, id_wid, m_extra=True):
74 self.a = FPNumBase(width, m_extra)
75 self.b = FPNumBase(width, m_extra)
76 self.muxid = Signal(id_wid, reset_less=True)
77
78 def eq(self, i):
79 return [self.a.eq(i.a), self.b.eq(i.b), self.muxid.eq(i.muxid)]
80
81 def ports(self):
82 return [self.a, self.b, self.muxid]
83
84
85 class FPPipeContext:
86
87 def __init__(self, pspec):
88 """ creates a pipeline context. currently: operator (op) and muxid
89
90 opkls (within pspec) - the class to create that will be the
91 "operator". instance must have an "eq"
92 function.
93 """
94 self.id_wid = pspec.id_wid
95 self.op_wid = pspec.op_wid
96 self.muxid = Signal(self.id_wid, reset_less=True) # RS multiplex ID
97 opkls = pspec.opkls
98 if opkls is None:
99 self.op = Signal(self.op_wid, reset_less=True)
100 else:
101 self.op = opkls(pspec)
102
103 def eq(self, i):
104 ret = [self.muxid.eq(i.muxid)]
105 ret.append(self.op.eq(i.op))
106 return ret
107
108 def __iter__(self):
109 yield self.muxid
110 yield self.op
111
112 def ports(self):
113 return list(self)
114
115
116 class FPADDBaseData:
117
118 def __init__(self, pspec, n_ops=2):
119 width = pspec.width
120 self.ctx = FPPipeContext(pspec)
121 ops = []
122 for i in range(n_ops):
123 name = chr(ord("a")+i)
124 operand = Signal(width, name=name)
125 setattr(self, name, operand)
126 ops.append(operand)
127 self.muxid = self.ctx.muxid # make muxid available here: complicated
128 self.ops = ops
129
130 def eq(self, i):
131 ret = []
132 for op1, op2 in zip(self.ops, i.ops):
133 ret.append(op1.eq(op2))
134 ret.append(self.ctx.eq(i.ctx))
135 return ret
136
137 def __iter__(self):
138 if self.ops:
139 yield from self.ops
140 yield from self.ctx
141
142 def ports(self):
143 return list(self)
144
145
146 class FPGet2OpMod(PrevControl):
147 def __init__(self, width, id_wid, op_wid=None):
148 PrevControl.__init__(self)
149 self.width = width
150 self.id_wid = id_wid
151 self.data_i = self.ispec()
152 self.i = self.data_i
153 self.o = self.ospec()
154
155 def ispec(self):
156 return FPADDBaseData(self.width, self.id_wid, self.op_wid)
157
158 def ospec(self):
159 return FPADDBaseData(self.width, self.id_wid, self.op_wid)
160
161 def process(self, i):
162 return self.o
163
164 def elaborate(self, platform):
165 m = PrevControl.elaborate(self, platform)
166 with m.If(self.trigger):
167 m.d.comb += [
168 self.o.eq(self.data_i),
169 ]
170 return m
171
172
173 class FPGet2Op(FPState):
174 """ gets operands
175 """
176
177 def __init__(self, in_state, out_state, width, id_wid, op_wid=None):
178 FPState.__init__(self, in_state)
179 self.out_state = out_state
180 self.mod = FPGet2OpMod(width, id_wid, op_wid)
181 self.o = self.ospec()
182 self.in_stb = Signal(reset_less=True)
183 self.out_ack = Signal(reset_less=True)
184 self.out_decode = Signal(reset_less=True)
185
186 def ispec(self):
187 return self.mod.ispec()
188
189 def ospec(self):
190 return self.mod.ospec()
191
192 def trigger_setup(self, m, in_stb, in_ack):
193 """ links stb/ack
194 """
195 m.d.comb += self.mod.valid_i.eq(in_stb)
196 m.d.comb += in_ack.eq(self.mod.ready_o)
197
198 def setup(self, m, i):
199 """ links module to inputs and outputs
200 """
201 m.submodules.get_ops = self.mod
202 m.d.comb += self.mod.i.eq(i)
203 m.d.comb += self.out_ack.eq(self.mod.ready_o)
204 m.d.comb += self.out_decode.eq(self.mod.trigger)
205
206 def process(self, i):
207 return self.o
208
209 def action(self, m):
210 with m.If(self.out_decode):
211 m.next = self.out_state
212 m.d.sync += [
213 self.mod.ready_o.eq(0),
214 self.o.eq(self.mod.o),
215 ]
216 with m.Else():
217 m.d.sync += self.mod.ready_o.eq(1)
218
219