/ coreblocks / func_blocks / fu / fpu / int_to_float.py
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