int_to_float.py
1 from amaranth import * 2 from transactron import TModule, Method, def_method 3 from transactron.utils.transactron_helpers import from_method_layout 4 from transactron.utils.amaranth_ext import count_leading_zeros 5 from coreblocks.func_blocks.fu.fpu.fpu_common import ( 6 FPUParams, 7 Errors, 8 RoundingModes, 9 IntConversionValues, 10 create_data_output_layout, 11 ) 12 13 from coreblocks.func_blocks.fu.fpu.fpu_rounding_module import FPURounding 14 15 16 class IntToFloatMethodLayout: 17 """FPU integer to float conversion module method layout 18 19 Parameters 20 ---------- 21 fpu_params: FPUParams 22 FPU parameters 23 int_values: IntConversionValues 24 Values for int to float conversion 25 """ 26 27 def __init__(self, *, fpu_params: FPUParams, int_values: IntConversionValues): 28 self.itf_in_layout = [ 29 ("op", int_values.int_width), 30 ("signed", 1), 31 ("rounding_mode", RoundingModes), 32 ] 33 """ 34 | Input layout for int to float conversion 35 | op - layout containing data of the integer 36 | signed - bit indicating if op is signed or unsigned 37 | rounding_mode - selected rounding mode 38 """ 39 self.itf_out_layout = create_data_output_layout(fpu_params) 40 """ 41 | Output layout for int to float conversion created using 42 :meth:`create_data_output_layout <coreblocks.func_blocks.fu.fpu.fpu_common.create_data_output_layout>` 43 """ 44 45 46 class IntToFloatModule(Elaboratable): 47 """Module for int to float conversion 48 Module responsible for performing conversion from int to float. 49 50 Parameters 51 ---------- 52 fpu_params: FPUParams 53 FPU module parameters 54 int_values: IntConversionValues 55 Values for int to float conversion 56 57 Attributes 58 ---------- 59 itf_request: Method 60 Transactional method for initiating conversion. 61 Takes 'itf_in_layout' as argument 62 Returns result as 'itf_out_layout' 63 """ 64 65 def __init__(self, *, fpu_params: FPUParams, int_values: IntConversionValues): 66 67 self.conv_params = fpu_params 68 self.int_values = int_values 69 self.method_layouts = IntToFloatMethodLayout(fpu_params=self.conv_params, int_values=self.int_values) 70 self.itf_request = Method( 71 i=self.method_layouts.itf_in_layout, 72 o=self.method_layouts.itf_out_layout, 73 ) 74 75 def elaborate(self, platform): 76 m = TModule() 77 78 m.submodules.rounding_module = rounding_module = FPURounding(fpu_params=self.conv_params) 79 80 @def_method(m, self.itf_request) 81 def _(op, signed, rounding_mode): 82 is_zero = Signal() 83 m.d.av_comb += is_zero.eq(op == 0) 84 85 sign = Signal() 86 m.d.av_comb += sign.eq(signed & op[-1]) 87 88 abs_ext_sig = Signal(self.int_values.ext_width) 89 m.d.av_comb += abs_ext_sig.eq(Mux(sign, (-(op.as_signed())).as_unsigned(), op)) 90 91 n_shift = Signal(self.int_values.shift_width) 92 m.d.av_comb += n_shift.eq(count_leading_zeros(abs_ext_sig)) 93 94 norm_ext_sig = Signal(self.int_values.ext_width) 95 m.d.av_comb += norm_ext_sig.eq(abs_ext_sig << n_shift) 96 97 round_bit = Signal() 98 sticky_bit = Signal() 99 m.d.av_comb += round_bit.eq( 100 Mux(is_zero, 0, 0 if self.int_values.exact else norm_ext_sig[self.int_values.round_bit_index]) 101 ) 102 m.d.av_comb += sticky_bit.eq( 103 Mux( 104 is_zero, 0, 0 if self.int_values.exact else norm_ext_sig[0 : self.int_values.msb_sticky_index].any() 105 ) 106 ) 107 108 ur_norm_sig = Signal(self.conv_params.sig_width) 109 ur_exp = Signal(self.conv_params.exp_width) 110 shifted_ext_sig = norm_ext_sig >> self.int_values.ext_to_dst_shift 111 m.d.av_comb += ur_norm_sig.eq(Mux(is_zero, 0, norm_ext_sig if self.int_values.exact else shifted_ext_sig)) 112 m.d.av_comb += ur_exp.eq(Mux(is_zero, 0, self.int_values.exp_base_value - n_shift)) 113 114 resp = rounding_module.rounding_request( 115 m, 116 sign=sign, 117 sig=ur_norm_sig, 118 exp=ur_exp, 119 round_bit=round_bit, 120 sticky_bit=sticky_bit, 121 rounding_mode=rounding_mode, 122 ) 123 rounding_response = Signal(from_method_layout(rounding_module.method_layouts.rounding_out_layout)) 124 m.d.av_comb += rounding_response.eq(resp) 125 126 errors = Signal(Errors) 127 with m.If(rounding_response["inexact"]): 128 m.d.av_comb += errors.eq(Errors.INEXACT) 129 130 return {"sign": sign, "sig": rounding_response["sig"], "exp": rounding_response["exp"], "errors": errors} 131 132 return m