1 """IEEE Floating Point Divider
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jacob Lifshay
6 Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
9 from nmigen
import Module
, Signal
, Elaboratable
, Cat
10 from nmigen
.cli
import main
, verilog
12 from ieee754
.fpcommon
.fpbase
import FPState
13 from ieee754
.fpcommon
.postcalc
import FPAddStage1Data
14 from ieee754
.div_rem_sqrt_rsqrt
.div_pipe
import DivPipeOutputData
17 class FPDivStage2Mod(FPState
, Elaboratable
):
18 """ Last stage of div: preparation for normalisation.
20 NOTE: this phase does NOT do ACTUAL DIV processing, it ONLY
21 does "conversion" *out* of the Q/REM last stage
24 def __init__(self
, pspec
):
30 return DivPipeOutputData(self
.pspec
) # Q/Rem in...
33 # XXX REQUIRED. MUST NOT BE CHANGED. this is the format
34 # required for ongoing processing (normalisation, correction etc.)
35 return FPAddStage1Data(self
.pspec
) # out to post-process
40 def setup(self
, m
, i
):
41 """ links module to inputs and outputs
43 m
.submodules
.div1
= self
44 m
.d
.comb
+= self
.i
.eq(i
)
46 def elaborate(self
, platform
):
50 # copies sign and exponent and mantissa (mantissa and exponent to be
52 comb
+= self
.o
.z
.eq(self
.i
.z
)
54 # Operations and input/output mantissa ranges:
68 with m
.If(~self
.i
.out_do_z
):
69 # following section partially normalizes result to range [1.0, 2.0)
70 fw
= self
.pspec
.core_config
.fract_width
71 qr_int_part
= Signal(2, reset_less
=True)
72 comb
+= qr_int_part
.eq(self
.i
.quotient_root
[fw
:][:2])
74 need_shift
= Signal(reset_less
=True)
76 # shift left when result is less than 2.0 since result_m has 1 more
77 # fraction bit, making assigning to it the equivalent of
79 # this all comes out to:
80 # if quotient_root < 2.0:
81 # # div by 2 from assign; mul by 2 from shift left
82 # result = (quotient_root * 2) / 2
84 # # div by 2 from assign
85 # result = quotient_root / 2
86 comb
+= need_shift
.eq(qr_int_part
< 2)
88 # one extra fraction bit to accommodate the result when not
89 # shifting and for effective div by 2
90 result_m_fract_width
= fw
+ 1
91 # 1 integer bit since the numbers are less than 2.0
92 result_m
= Signal(1 + result_m_fract_width
, reset_less
=True)
93 result_e
= Signal(len(self
.i
.z
.e
), reset_less
=True)
96 result_m
.eq(self
.i
.quotient_root
<< need_shift
),
97 result_e
.eq(self
.i
.z
.e
+ (1 - need_shift
))
100 # result_m is now in the range [1.0, 2.0)
102 self
.o
.z
.m
.eq(result_m
[3:]), # mantissa
103 self
.o
.of
.m0
.eq(result_m
[3]), # copy of mantissa LSB
104 self
.o
.of
.guard
.eq(result_m
[2]), # guard
105 self
.o
.of
.round_bit
.eq(result_m
[1]), # round
106 self
.o
.of
.sticky
.eq(result_m
[0] | self
.i
.remainder
.bool()),
107 self
.o
.z
.e
.eq(result_e
),
110 comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
111 comb
+= self
.o
.oz
.eq(self
.i
.oz
)
112 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
117 class FPDivStage2(FPState
):
119 def __init__(self
, pspec
):
120 FPState
.__init
__(self
, "divider_1")
121 self
.mod
= FPDivStage2Mod(pspec
)
122 self
.out_z
= FPNumBaseRecord(pspec
, False)
123 self
.out_of
= Overflow()
124 self
.norm_stb
= Signal()
126 def setup(self
, m
, i
):
127 """ links module to inputs and outputs
131 m
.d
.sync
+= self
.norm_stb
.eq(0) # sets to zero when not in div1 state
133 m
.d
.sync
+= self
.out_of
.eq(self
.mod
.out_of
)
134 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
135 m
.d
.sync
+= self
.norm_stb
.eq(1)
138 m
.next
= "normalise_1"