test_float_to_int.py
1 from coreblocks.func_blocks.fu.fpu.float_to_int import * 2 from coreblocks.func_blocks.fu.fpu.fpu_common import FPUParams, RoundingModes, Errors 3 from test.func_blocks.fu.fpu.fpu_test_common import ToFloatConverter, python_to_float 4 from transactron.testing import * 5 from amaranth import * 6 import random 7 import ctypes 8 from dataclasses import dataclass 9 10 # Few notes for later. 11 # 1. Due to the precision of float some conditions for out of bound numbers 12 # are impossible to fulfill/test due to lack of precision (both for 32 and 64 bit integers). 13 # Add more tests later when more precise versions of floating point numbers are available 14 # 2. Due to the fact that we are not using rounding module but separatly 15 # compute if rounding is needed, it may be worth to test all rounding modes or 16 # modify rounding module to return one bit of information signifying if rounding occured 17 18 converter = ToFloatConverter(FPUParams(sig_width=24, exp_width=8)) 19 20 21 @dataclass 22 class TCase: 23 op: dict[str, int] 24 signed: int 25 result: int 26 errors: int 27 28 29 max_un_int = (2**64) - 1 30 min_sig_int = 2**63 31 max_sig_int = (2**63) - 1 32 33 test_cases = [ 34 # Test 1: Zero 35 TCase( 36 converter.from_hex("00000000"), 37 1, 38 0, 39 0, 40 ), 41 # Test 2: NaN 42 TCase( 43 converter.from_hex("FFC00000"), 44 0, 45 max_un_int, 46 Errors.INVALID_OPERATION, 47 ), 48 # Test 3: -Inf 49 TCase( 50 converter.from_hex("FF800000"), 51 1, 52 min_sig_int, 53 Errors.INVALID_OPERATION, 54 ), 55 # Test 4: +Inf 56 TCase( 57 converter.from_hex("7F800000"), 58 1, 59 max_sig_int, 60 Errors.INVALID_OPERATION, 61 ), 62 # Test 4: Rounding 63 TCase( 64 converter.from_hex("3FFFFFFF"), 65 1, 66 2, 67 Errors.INEXACT, 68 ), 69 # Test 5: Out of bound negative 70 TCase( 71 converter.from_hex("DF000001"), 72 1, 73 min_sig_int, 74 Errors.INVALID_OPERATION, 75 ), 76 # Test 6: Out of bound positive 77 TCase( 78 converter.from_hex("5F000000"), 79 1, 80 max_sig_int, 81 Errors.INVALID_OPERATION, 82 ), 83 # Test 7: Mag less than one, out of bound 84 TCase( 85 converter.from_hex("bf7fffff"), 86 0, 87 0, 88 Errors.INVALID_OPERATION, 89 ), 90 ] 91 92 93 class TestFTI(TestCaseWithSimulator): 94 95 def test_manual(self): 96 params = FPUParams(sig_width=24, exp_width=8) 97 fti = SimpleTestCircuit(FloatToIntModule(fpu_params=params, int_width=64)) 98 99 async def fti_ec_test(sim: TestbenchContext): 100 input_dict = {} 101 for tc in test_cases: 102 input_dict["op"] = tc.op 103 input_dict["signed"] = tc.signed 104 input_dict["rounding_mode"] = RoundingModes.ROUND_NEAREST_EVEN 105 106 resp = await fti.fti_request.call(sim, input_dict) 107 assert tc.result == resp["result"] 108 assert tc.errors == resp["errors"] 109 110 async def fti_python_test(sim: TestbenchContext): 111 seed = 42 112 random.seed(seed) 113 test_runs = 20 114 115 for i in range(test_runs): 116 117 input_dict = {} 118 op_sig = random.uniform(-(2 ** (63)), 2 ** (63) - 1) 119 op_unsig = random.uniform(0, 2 ** (63)) 120 121 fl_sig = python_to_float(op_sig) 122 fl_unsig = python_to_float(op_unsig) 123 124 expected_value_sig = int(fl_sig) 125 expected_value_unsig = int(fl_unsig) 126 127 input_sig = converter.from_float(op_sig) 128 input_unsig = converter.from_float(op_unsig) 129 130 input_dict["op"] = input_sig 131 input_dict["signed"] = 1 132 input_dict["rounding_mode"] = RoundingModes.ROUND_NEAREST_EVEN 133 134 resp = await fti.fti_request.call(sim, input_dict) 135 136 resp_signed = ctypes.c_int64(resp["result"]).value 137 assert expected_value_sig == resp_signed 138 139 input_dict["op"] = input_unsig 140 input_dict["signed"] = 0 141 input_dict["rounding_mode"] = RoundingModes.ROUND_NEAREST_EVEN 142 143 resp = await fti.fti_request.call(sim, input_dict) 144 assert expected_value_unsig == resp["result"] 145 146 async def test_process(sim: TestbenchContext): 147 await fti_python_test(sim) 148 await fti_ec_test(sim) 149 150 with self.run_simulation(fti) as sim: 151 sim.add_testbench(test_process)