From c20a656d1033e5d8909145baa307ad4ca3d99c70 Mon Sep 17 00:00:00 2001 From: Mateusz Marszalek Date: Mon, 25 Nov 2024 21:02:41 +0100 Subject: [PATCH 1/4] Init commit --- coreblocks/func_blocks/fu/fpu/far_path.py | 304 ++++++++++++++++++++ coreblocks/func_blocks/fu/fpu/fpu_common.py | 18 +- 2 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 coreblocks/func_blocks/fu/fpu/far_path.py diff --git a/coreblocks/func_blocks/fu/fpu/far_path.py b/coreblocks/func_blocks/fu/fpu/far_path.py new file mode 100644 index 000000000..7b2c36e3a --- /dev/null +++ b/coreblocks/func_blocks/fu/fpu/far_path.py @@ -0,0 +1,304 @@ +from amaranth import * +from transactron import TModule, Method, def_method +from coreblocks.func_blocks.fu.fpu.fpu_common import RoundingModes, FPUParams + + +class FarPathMethodLayout: + """Far path module layouts for methods + + Parameters + ---------- + fpu_params; FPUParams + FPU parameters + """ + + def __init__(self, *, fpu_params: FPUParams): + + self.far_path_in_layout = [ + ("r_sign", 1)("sig_a", fpu_params.sig_width), + ("sig_b", fpu_params.sig_width), + ("exp", fpu_params.exp_width), + ("sub_op", 1), + ("rounding_mode", RoundingModes), + ("guard_bit", 1), + ("round_bit", 1), + ("sticky_bit", 1), + ] + self.far_path_out_layout = [ + ("out_exp", fpu_params.exp_width), + ("out_sig", fpu_params.sig_width + 1), + ("output_round", 1), + ("output_sticky", 1), + ] + + +class FarPathModule(Elaboratable): + """Far Path module + + Parameters + ---------- + fpu_params: FPUParams + FPU rounding module parameters + + Attributes + ---------- + far_path_request: Method + Transactional method for initiating far path computation. + Takes 'far_path_in_layout' as argument. + Returns result as 'far_path_out_layout'. + """ + + def __init__(self, *, fpu_params: FPUParams): + + self.params = fpu_params + self.method_layouts = FarPathMethodLayout(fpu_params=self.params) + self.far_path_request = Method( + i=self.method_layouts.far_path_in_layout, + o=self.method_layouts.far_path_out_layout, + ) + + def elaborate(self, platform): + m = TModule() + + input_sig_add_0_a = Signal(self.params.sig_width) + input_sig_add_0_b = Signal(self.params.sig_width) + input_sig_add_1_a = Signal(self.params.sig_width) + input_sig_add_1_b = Signal(self.params.sig_width) + output_sig_add_0 = Signal(self.params.sig_width + 1) + output_sig_add_1 = Signal(self.params.sig_width + 1) + output_sig_add_1_check = Signal(self.params.sig_width + 1) + output_sig = Signal(self.params.sig_width + 1) + output_exp = Signal(self.params.exp_width + 1) + + output_round_bit = Signal() + output_sticky_bit = Signal() + final_guard_bit = Signal() + final_round_bit = Signal() + final_sticky_bit = Signal() + + round_up_inc_1 = Signal() + round_down_inc_1 = Signal() + round_to_inf_special_case = Signal() + xor_sig = Signal(self.params.sig_width) + carry_sig = Signal(self.params.sig_width) + carry_add1 = Signal() + rgs_any = Signal() + rgs_all = Signal() + + # No right shift + NRS = Signal() + # One right shift + ORS = Signal() + # No left shift + NLS = Signal() + # One left shift + OLS = Signal() + NXS = Signal() + + NXS_list = [None for _ in range(RoundingModes)] + ORS_list = [None for _ in range(RoundingModes)] + OLS_list = [None for _ in range(RoundingModes)] + + Shift_in_bit = [None for _ in range(RoundingModes)] + + g = Signal() + + @def_method(m, self.far_path_request) + def _( + r_sign, + sig_a, + sig_b, + exp, + sub_op, + rounding_mode, + guard_bit, + round_bit, + sticky_bit, + ): + # TODO double check for round_up and round_down + m.d.av_comb += input_sig_add_0_a.eq(sig_a) + m.d.av_comb += input_sig_add_0_b.eq(sig_b) + m.d.av_comb += xor_sig.eq(sig_a ^ sig_b) + m.d.av_comb += carry_sig.eq(sig_a & sig_b) + m.d.av_comb += carry_add1.eq(carry_sig[-1]) + m.d.av_comb += rgs_any.eq(guard_bit | round_bit | sticky_bit) + m.d.av_comb += rgs_all.eq(guard_bit & round_bit & sticky_bit) + m.d.av_comb += output_sig_add_1_check.eq(sig_a + sig_b + 1) + m.d.av_comb += round_to_inf_special_case.eq((~sub_op) & + ((rounding_mode == RoundingModes.ROUND_DOWN) + | (rounding_mode == RoundingModes.ROUND_UP))) + + with m.If( round_to_inf_special_case + ): + m.d.av_comb += input_sig_add_1_a.eq((carry_sig << 1) | (~xor_sig[0])) + m.d.av_comb += input_sig_add_1_b.eq(xor_sig) + with m.Else(): + m.d.av_comb += input_sig_add_1_a.eq(sig_a) + m.d.av_comb += input_sig_add_1_b.eq(sig_b) + m.d.av_comb += carry_add1.eq(0) + + m.d.av_comb += output_sig_add_0.eq(input_sig_add_0_a + input_sig_add_0_b) + m.d.av_comb += output_sig_add_1.eq(input_sig_add_1_a + input_sig_add_1_b + 1) + m.d.av_comb += output_sig_add_1[-1].eq(output_sig_add_1[-1] | carry_add1) + + m.d.av_comb += NRS.eq((~sig_op) & (~output_sig_add_0[-1])) + m.d.av_comb += ORS.eq((~sig_op) & (output_sig_add_0[-1])) + m.d.av_comb += NLS.eq( + sig_op + & ( + ((~rgs_any) & output_sig_add_1_check[-2]) + | (rgs_any & output_sig_add_0[-2]) + ) + ) + m.d.av_comb += OLS.eq( + sig_op + & ( + ((~rgs_any) & (~output_sig_add_1_check[-2])) + | (rgs_any & (~output_sig_add_0[-2])) + ) + ) + m.d.av_comb += NXS.eq(NLS | NRS) + + subtraction = sub_op & ((~r_sign) | (~rgs_any)) + addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & ((~r_sig) & (rgs_any))) + m.d.av_comb += NXS_list[RoundingModes.ROUND_UP].eq(subtraction | addition) + + subtraction = sub_op & (r_sign | (~rgs_any)) + addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & (r_sig & (rgs_any))) + m.d.av_comb += NXS_list[RoundingModes.ROUND_DOWN].eq(subtraction | addition) + + m.d.av_comb += NXS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) + + subtraction = sub_op & ( + (~guard_bit) + | (guard_bit & (~round_bit) & (~sticky_bit) & (sig_a[0] ^ sig_b[0])) + ) + addition = ( + (~sub_op) & guard_bit & (round_bit | sticky_bit | (sig_a[0] ^ sig_b[0])) + ) + m.d.av_comb += NXS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( + subtraction | addition + ) + + subtraction = sub_op & ((~guard_bit) ^ ((~round_bit) & (~sticky_bit))) + addition = (~sub_op) & guard_bit + m.d.av_comb += NXS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( + subtraction | addition + ) + + m.d.av_comb += ORS_list[RoundingModes.ROUND_UP].eq( + (~r_sign) & ((sig_a[0] ^ sig_b[0]) | rgs_any) + ) + m.d.av_comb += ORS_list[RoundingModes.ROUND_DOWN].eq( + r_sign & ((sig_a[0] ^ sig_b[0]) | rgs_any) + ) + m.d.av_comb += ORS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) + m.d.av_comb += ORS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( + (sig_a[0] ^ sig_b[0]) & (rgs_any | (sig_a[1] ^ sig_b[1])) + ) + m.d.av_comb += ORS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( + sig_a[0] ^ sig_b[0] + ) + + m.d.av_comb += OLS_list[RoundingModes.ROUND_UP].eq( + ((~r_sign) & (~guard_bit)) | (r_sign & (~rgs_any)) + ) + m.d.av_comb += OLS_list[RoundingModes.ROUND_DOWN].eq( + (r_sign & (~guard_bit)) | (~(r_sign) & (~rgs_any)) + ) + m.d.av_comb += OLS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) + m.d.av_comb += OLS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( + (~guard_bit) & ((~round_bit) | (~sticky_bit)) + ) + m.d.av_comb += OLS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( + (~guard_bit) & ((~round_bit) | (~sticky_bit)) + ) + + m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_UP].eq( + ((~r_sign) & guard_bit) + | ( + r_sign + & ( + (guard_bit & (~round_bit) & (~sticky_bit)) + | ((~guard_bit) & (round_bit | sticky_bit)) + ) + ) + ) + m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_DOWN].eq( + (r_sign & guard_bit) + | ( + (~r_sign) + & ( + (guard_bit & (~round_bit) & (~sticky_bit)) + | ((~guard_bit) & (round_bit | sticky_bit)) + ) + ) + ) + m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_ZERO].eq( + ((~guard_bit) & (round_bit | sticky_bit)) + | (guard_bit & (~round_bit) & (~sticky_bit)) + ) + m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_NEAREST_EVEN].eq( + ((~guard_bit) & round_bit & sticky_bit) | (guard_bit & (~round_bit)) + ) + m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_NEAREST_AWAY].eq( + ((~guard_bit) & round_bit & sticky_bit) + | (guard_bit & (~(round_bit & sticky_bit))) + ) + + m.d.av_comb += g.eq( + (ORS & ORS_list[rounding_mode]) + | (NXS & NXS_list) + | (OLS & OLS_list[rounding_mode]) + ) + + m.d.av_comb += round_up_inc_1.eq(rounding_mode.ROUND_UP & NRS & (~g) & (~(sig_a[0] ^ sig_b[0])) & ((~r_sig) & (rgs_any))) + m.d.av_comb += round_down_inc_1.eq(rounding_mode.ROUND_DOWN & NRS & (~g) & (~(sig_a[0] ^ sig_b[0])) & (r_sig & (rgs_any))) + + with m.If(g): + m.d.av_comb += output_sig.eq(output_sig_add_1) + with m.Else(): + m.d.av_comb += output_sig.eq(output_sig_add_0) + m.d.av_comb += output_exp.eq(exp) + + with m.If(round_down_inc_1 | round_down_inc_1): + m.d.av_comb += output_sig.eq(output_sig | 1) + + with m.If(sub_op): + m.d.av_comb += final_guard_bit.eq( + (~guard_bit) ^ ((~round_bit) & (~sticky_bit)) + ) + m.d.av_comb += final_round_bit.eq((~round_bit) ^ (~sticky_bit)) + m.d.av_comb += final_sticky_bit.eq(sticky_bit) + + with m.Else(): + m.d.av_comb += final_guard_bit.eq(guard_bit) + m.d.av_comb += final_round_bit.eq(round_bit) + m.d.av_comb += final_sticky_bit.eq(sticky_bit) + + with m.If(ORS): + m.d.av_comb += output_sticky_bit.eq( + final_guard_bit | final_round_bit | final_sticky_bit + ) + m.d.av_comb += output_round_bit.eq(sig_a[0] ^ sig_b[0]) + with m.Elif(OLS): + m.d.av_comb += output_sticky_bit.eq(final_sticky_bit) + m.d.av_comb += output_round_bit.eq(final_round_bit) + with m.Else(): + m.d.av_comb += output_sticky_bit.eq(final_round_bit | final_sticky_bit) + m.d.av_comb += output_round_bit.eq(final_guard_bit) + + with m.If((~sub_op) & output_sig[-1]): + m.d.av_comb += output_sig.eq(output_sig >> 1) + m.d.av_comb += output_exp.eq(output_exp + 1) + + with m.If(sub_op & (~output_sig[-2])): + m.d.av_comb += output_sig.eq(output_sig << 1) + m.d.av_comb += output_exp.eq(output_exp - 1) + + return { + "out_exp": output_exp, + "out_sig": output_sig, + "output_round_bit": output_round_bit, + "output_sticky_bit": output_sticky_bit, + } diff --git a/coreblocks/func_blocks/fu/fpu/fpu_common.py b/coreblocks/func_blocks/fu/fpu/fpu_common.py index 14ad02739..2ac2d2687 100644 --- a/coreblocks/func_blocks/fu/fpu/fpu_common.py +++ b/coreblocks/func_blocks/fu/fpu/fpu_common.py @@ -1,4 +1,20 @@ -from amaranth.lib import enum +from amaranth.lib import enum, data + + +def create_data_layout(sig_width: int, exp_width: int): + return data.StructLayout( + { + "sign": 1, + "sig": sig_width, + "exp": exp_width, + "is_inf": 1, + "is_nan": 1, + "is_zero": 1, + } + ) + + +float_number_layout = create_data_layout(24, 8) class RoundingModes(enum.Enum): From 73ff498175abd00f2932e29a966efd4acc533c5d Mon Sep 17 00:00:00 2001 From: Mateusz Marszalek Date: Sun, 1 Dec 2024 22:56:32 +0100 Subject: [PATCH 2/4] First tests --- coreblocks/func_blocks/fu/fpu/far_path.py | 26 ++++----- test/func_blocks/fu/fpu/test_far_path.py | 65 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 test/func_blocks/fu/fpu/test_far_path.py diff --git a/coreblocks/func_blocks/fu/fpu/far_path.py b/coreblocks/func_blocks/fu/fpu/far_path.py index 7b2c36e3a..a5dd73baf 100644 --- a/coreblocks/func_blocks/fu/fpu/far_path.py +++ b/coreblocks/func_blocks/fu/fpu/far_path.py @@ -15,7 +15,8 @@ class FarPathMethodLayout: def __init__(self, *, fpu_params: FPUParams): self.far_path_in_layout = [ - ("r_sign", 1)("sig_a", fpu_params.sig_width), + ("r_sign", 1), + ("sig_a", fpu_params.sig_width), ("sig_b", fpu_params.sig_width), ("exp", fpu_params.exp_width), ("sub_op", 1), @@ -95,11 +96,11 @@ def elaborate(self, platform): OLS = Signal() NXS = Signal() - NXS_list = [None for _ in range(RoundingModes)] - ORS_list = [None for _ in range(RoundingModes)] - OLS_list = [None for _ in range(RoundingModes)] + NXS_list = [Signal() for _ in range(RoundingModes)] + ORS_list = [Signal() for _ in range(RoundingModes)] + OLS_list = [Signal() for _ in range(RoundingModes)] - Shift_in_bit = [None for _ in range(RoundingModes)] + Shift_in_bit = [Signal() for _ in range(RoundingModes)] g = Signal() @@ -115,7 +116,6 @@ def _( round_bit, sticky_bit, ): - # TODO double check for round_up and round_down m.d.av_comb += input_sig_add_0_a.eq(sig_a) m.d.av_comb += input_sig_add_0_b.eq(sig_b) m.d.av_comb += xor_sig.eq(sig_a ^ sig_b) @@ -141,17 +141,17 @@ def _( m.d.av_comb += output_sig_add_1.eq(input_sig_add_1_a + input_sig_add_1_b + 1) m.d.av_comb += output_sig_add_1[-1].eq(output_sig_add_1[-1] | carry_add1) - m.d.av_comb += NRS.eq((~sig_op) & (~output_sig_add_0[-1])) - m.d.av_comb += ORS.eq((~sig_op) & (output_sig_add_0[-1])) + m.d.av_comb += NRS.eq((~sub_op) & (~output_sig_add_0[-1])) + m.d.av_comb += ORS.eq((~sub_op) & (output_sig_add_0[-1])) m.d.av_comb += NLS.eq( - sig_op + sub_op & ( ((~rgs_any) & output_sig_add_1_check[-2]) | (rgs_any & output_sig_add_0[-2]) ) ) m.d.av_comb += OLS.eq( - sig_op + sub_op & ( ((~rgs_any) & (~output_sig_add_1_check[-2])) | (rgs_any & (~output_sig_add_0[-2])) @@ -204,7 +204,7 @@ def _( ((~r_sign) & (~guard_bit)) | (r_sign & (~rgs_any)) ) m.d.av_comb += OLS_list[RoundingModes.ROUND_DOWN].eq( - (r_sign & (~guard_bit)) | (~(r_sign) & (~rgs_any)) + (r_sign & (~guard_bit)) | ((~r_sign) & (~rgs_any)) ) m.d.av_comb += OLS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) m.d.av_comb += OLS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( @@ -292,8 +292,8 @@ def _( m.d.av_comb += output_sig.eq(output_sig >> 1) m.d.av_comb += output_exp.eq(output_exp + 1) - with m.If(sub_op & (~output_sig[-2])): - m.d.av_comb += output_sig.eq(output_sig << 1) + with m.If(sub_op & (~output_sig[-2]) & out_exp > 0): + m.d.av_comb += output_sig.eq((output_sig << 1) | Shift_in_bit[rounding_mode]) m.d.av_comb += output_exp.eq(output_exp - 1) return { diff --git a/test/func_blocks/fu/fpu/test_far_path.py b/test/func_blocks/fu/fpu/test_far_path.py new file mode 100644 index 000000000..939919f69 --- /dev/null +++ b/test/func_blocks/fu/fpu/test_far_path.py @@ -0,0 +1,65 @@ +from coreblocks.func_blocks.fu.fpu.far_path import * +from coreblocks.func_blocks.fu.fpu.fpu_common import ( + RoundingModes, + FPUParams, +) +from transactron import TModule +from transactron.lib import AdapterTrans +from parameterized import parameterized +from transactron.testing import * +from amaranth import * + + +class TestFarPath(TestCaseWithSimulator): + class FarPathModule(Elaboratable): + def __init__(self, params: FPUParams): + self.params = params + + def elaborate(self, platform): + m = TModule() + m.submodules.fp = fp = self.far_path = FarPathModule(fpu_params=self.params) + m.submodules.compute = self.far_path_request_adapter = TestbenchIO(AdapterTrans(fp.far_path_request)) + return m + + + params = FPUParams(sig_width=24, exp_width=8) + + + def test_far_path_addition(self): + params = FPUParams(sig_width=24, exp_width=8) + far_path = TestFarPath.FarPathModule(params) + async def test_ORS(sim:TestbenchContext): + test_cases = [ + #one right_shift 000000000000000000000000 + { + "r_sign": 0, + "sig_a": 0b111110000000000000000001, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit":0, + "round_bit":1, + "sticky_bit":0, + } + ] + expected_results = [ + { + "out_exp":11, + "out_sig":0b100000000000000000000000, + "output_round":1, + "output_sticky":1, + } + ] + for i in range(len(test_cases)): + resp = await far_path.far_path_request_adapter.call(sim,input_dict[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] + + async def test_process(sim:TestbenchContext): + await test_ORS(sim) + + with self.run_simulation(fpurt) as sim: + sim.add_testbench(test_process) From 6644e91ce8f68f3a083cb96868b468d6384a20a0 Mon Sep 17 00:00:00 2001 From: Mateusz Marszalek Date: Mon, 2 Dec 2024 05:50:25 +0100 Subject: [PATCH 3/4] Added tests --- coreblocks/func_blocks/fu/fpu/far_path.py | 281 ++--- test/func_blocks/fu/fpu/test_far_path.py | 1247 ++++++++++++++++++++- 2 files changed, 1365 insertions(+), 163 deletions(-) diff --git a/coreblocks/func_blocks/fu/fpu/far_path.py b/coreblocks/func_blocks/fu/fpu/far_path.py index a5dd73baf..055fe4584 100644 --- a/coreblocks/func_blocks/fu/fpu/far_path.py +++ b/coreblocks/func_blocks/fu/fpu/far_path.py @@ -27,7 +27,7 @@ def __init__(self, *, fpu_params: FPUParams): ] self.far_path_out_layout = [ ("out_exp", fpu_params.exp_width), - ("out_sig", fpu_params.sig_width + 1), + ("out_sig", fpu_params.sig_width), ("output_round", 1), ("output_sticky", 1), ] @@ -70,6 +70,8 @@ def elaborate(self, platform): output_sig_add_1_check = Signal(self.params.sig_width + 1) output_sig = Signal(self.params.sig_width + 1) output_exp = Signal(self.params.exp_width + 1) + output_final_exp = Signal(self.params.exp_width) + output_final_sig = Signal(self.params.sig_width) output_round_bit = Signal() output_sticky_bit = Signal() @@ -77,7 +79,7 @@ def elaborate(self, platform): final_round_bit = Signal() final_sticky_bit = Signal() - round_up_inc_1 = Signal() + round_up_inc_1 = Signal() round_down_inc_1 = Signal() round_to_inf_special_case = Signal() xor_sig = Signal(self.params.sig_width) @@ -87,20 +89,39 @@ def elaborate(self, platform): rgs_all = Signal() # No right shift - NRS = Signal() + nrs = Signal() # One right shift - ORS = Signal() + ors = Signal() # No left shift - NLS = Signal() + nls = Signal() # One left shift - OLS = Signal() - NXS = Signal() - - NXS_list = [Signal() for _ in range(RoundingModes)] - ORS_list = [Signal() for _ in range(RoundingModes)] - OLS_list = [Signal() for _ in range(RoundingModes)] - - Shift_in_bit = [Signal() for _ in range(RoundingModes)] + ols = Signal() + nxs = Signal() + + nxs_rtne = Signal() + nxs_rtna = Signal() + nxs_zero = Signal() + nxs_up = Signal() + nxs_down = Signal() + + ors_rtne = Signal() + ors_rtna = Signal() + ors_zero = Signal() + ors_up = Signal() + ors_down = Signal() + + ols_rtne = Signal() + ols_rtna = Signal() + ols_zero = Signal() + ols_up = Signal() + ols_down = Signal() + + shift_in_bit_rtne = Signal() + shift_in_bit_rtna = Signal() + shift_in_bit_zero = Signal() + shift_in_bit_up = Signal() + shift_in_bit_down = Signal() + shift_in_bit = Signal() g = Signal() @@ -124,12 +145,11 @@ def _( m.d.av_comb += rgs_any.eq(guard_bit | round_bit | sticky_bit) m.d.av_comb += rgs_all.eq(guard_bit & round_bit & sticky_bit) m.d.av_comb += output_sig_add_1_check.eq(sig_a + sig_b + 1) - m.d.av_comb += round_to_inf_special_case.eq((~sub_op) & - ((rounding_mode == RoundingModes.ROUND_DOWN) - | (rounding_mode == RoundingModes.ROUND_UP))) + m.d.av_comb += round_to_inf_special_case.eq( + (~sub_op) & ((rounding_mode == RoundingModes.ROUND_DOWN) | (rounding_mode == RoundingModes.ROUND_UP)) + ) - with m.If( round_to_inf_special_case - ): + with m.If(round_to_inf_special_case): m.d.av_comb += input_sig_add_1_a.eq((carry_sig << 1) | (~xor_sig[0])) m.d.av_comb += input_sig_add_1_b.eq(xor_sig) with m.Else(): @@ -138,136 +158,109 @@ def _( m.d.av_comb += carry_add1.eq(0) m.d.av_comb += output_sig_add_0.eq(input_sig_add_0_a + input_sig_add_0_b) - m.d.av_comb += output_sig_add_1.eq(input_sig_add_1_a + input_sig_add_1_b + 1) - m.d.av_comb += output_sig_add_1[-1].eq(output_sig_add_1[-1] | carry_add1) - - m.d.av_comb += NRS.eq((~sub_op) & (~output_sig_add_0[-1])) - m.d.av_comb += ORS.eq((~sub_op) & (output_sig_add_0[-1])) - m.d.av_comb += NLS.eq( - sub_op - & ( - ((~rgs_any) & output_sig_add_1_check[-2]) - | (rgs_any & output_sig_add_0[-2]) - ) + m.d.av_comb += output_sig_add_1.eq( + (input_sig_add_1_a + input_sig_add_1_b + 1) | (carry_add1 << (self.params.sig_width - 1)) ) - m.d.av_comb += OLS.eq( - sub_op - & ( - ((~rgs_any) & (~output_sig_add_1_check[-2])) - | (rgs_any & (~output_sig_add_0[-2])) - ) + + m.d.av_comb += nrs.eq((~sub_op) & (~output_sig_add_0[-1])) + m.d.av_comb += ors.eq((~sub_op) & (output_sig_add_0[-1])) + m.d.av_comb += nls.eq( + sub_op & (((~rgs_any) & output_sig_add_1_check[-2]) | (rgs_any & output_sig_add_0[-2])) ) - m.d.av_comb += NXS.eq(NLS | NRS) + m.d.av_comb += ols.eq( + sub_op & (((~rgs_any) & (~output_sig_add_1_check[-2])) | (rgs_any & (~output_sig_add_0[-2]))) + ) + m.d.av_comb += nxs.eq(nls | nrs) subtraction = sub_op & ((~r_sign) | (~rgs_any)) - addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & ((~r_sig) & (rgs_any))) - m.d.av_comb += NXS_list[RoundingModes.ROUND_UP].eq(subtraction | addition) + addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & ((~r_sign) & (rgs_any))) + m.d.av_comb += nxs_up.eq(subtraction | addition) subtraction = sub_op & (r_sign | (~rgs_any)) - addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & (r_sig & (rgs_any))) - m.d.av_comb += NXS_list[RoundingModes.ROUND_DOWN].eq(subtraction | addition) + addition = (~sub_op) & ((sig_a[0] ^ sig_b[0]) & (r_sign & (rgs_any))) + m.d.av_comb += nxs_down.eq(subtraction | addition) - m.d.av_comb += NXS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) + m.d.av_comb += nxs_zero.eq(sub_op & (~rgs_any)) - subtraction = sub_op & ( - (~guard_bit) - | (guard_bit & (~round_bit) & (~sticky_bit) & (sig_a[0] ^ sig_b[0])) - ) - addition = ( - (~sub_op) & guard_bit & (round_bit | sticky_bit | (sig_a[0] ^ sig_b[0])) - ) - m.d.av_comb += NXS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( - subtraction | addition - ) + subtraction = sub_op & ((~guard_bit) | (guard_bit & (~round_bit) & (~sticky_bit) & (sig_a[0] ^ sig_b[0]))) + addition = (~sub_op) & guard_bit & (round_bit | sticky_bit | (sig_a[0] ^ sig_b[0])) + m.d.av_comb += nxs_rtne.eq(subtraction | addition) - subtraction = sub_op & ((~guard_bit) ^ ((~round_bit) & (~sticky_bit))) + subtraction = sub_op & (((~guard_bit) ^ ((~round_bit) & (~sticky_bit))) | (~rgs_any)) addition = (~sub_op) & guard_bit - m.d.av_comb += NXS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( - subtraction | addition - ) - - m.d.av_comb += ORS_list[RoundingModes.ROUND_UP].eq( - (~r_sign) & ((sig_a[0] ^ sig_b[0]) | rgs_any) - ) - m.d.av_comb += ORS_list[RoundingModes.ROUND_DOWN].eq( - r_sign & ((sig_a[0] ^ sig_b[0]) | rgs_any) - ) - m.d.av_comb += ORS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) - m.d.av_comb += ORS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( - (sig_a[0] ^ sig_b[0]) & (rgs_any | (sig_a[1] ^ sig_b[1])) - ) - m.d.av_comb += ORS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( - sig_a[0] ^ sig_b[0] - ) - - m.d.av_comb += OLS_list[RoundingModes.ROUND_UP].eq( - ((~r_sign) & (~guard_bit)) | (r_sign & (~rgs_any)) - ) - m.d.av_comb += OLS_list[RoundingModes.ROUND_DOWN].eq( - (r_sign & (~guard_bit)) | ((~r_sign) & (~rgs_any)) - ) - m.d.av_comb += OLS_list[RoundingModes.ROUND_ZERO].eq(sub_op & (~rgs_any)) - m.d.av_comb += OLS_list[RoundingModes.ROUND_NEAREST_EVEN].eq( - (~guard_bit) & ((~round_bit) | (~sticky_bit)) - ) - m.d.av_comb += OLS_list[RoundingModes.ROUND_NEAREST_AWAY].eq( - (~guard_bit) & ((~round_bit) | (~sticky_bit)) - ) - - m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_UP].eq( + m.d.av_comb += nxs_rtna.eq(subtraction | addition) + + m.d.av_comb += ors_up.eq((~r_sign) & ((sig_a[0] ^ sig_b[0]) | rgs_any)) + m.d.av_comb += ors_down.eq(r_sign & ((sig_a[0] ^ sig_b[0]) | rgs_any)) + m.d.av_comb += ors_zero.eq(sub_op & (~rgs_any)) + m.d.av_comb += ors_rtne.eq((sig_a[0] ^ sig_b[0]) & (rgs_any | (sig_a[1] ^ sig_b[1]))) + m.d.av_comb += ors_rtna.eq(sig_a[0] ^ sig_b[0]) + + m.d.av_comb += ols_up.eq(((~r_sign) & (~guard_bit)) | (r_sign & (~rgs_any))) + m.d.av_comb += ols_down.eq((r_sign & (~guard_bit)) | ((~r_sign) & (~rgs_any))) + m.d.av_comb += ols_zero.eq(sub_op & (~rgs_any)) + m.d.av_comb += ols_rtne.eq((~guard_bit) & ((~round_bit) | (~sticky_bit))) + m.d.av_comb += ols_rtna.eq((~guard_bit) & ((~round_bit) | (~sticky_bit))) + m.d.av_comb += shift_in_bit_up.eq( ((~r_sign) & guard_bit) - | ( - r_sign - & ( - (guard_bit & (~round_bit) & (~sticky_bit)) - | ((~guard_bit) & (round_bit | sticky_bit)) - ) - ) + | (r_sign & ((guard_bit & (~round_bit) & (~sticky_bit)) | ((~guard_bit) & (round_bit | sticky_bit)))) ) - m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_DOWN].eq( + m.d.av_comb += shift_in_bit_down.eq( (r_sign & guard_bit) - | ( - (~r_sign) - & ( - (guard_bit & (~round_bit) & (~sticky_bit)) - | ((~guard_bit) & (round_bit | sticky_bit)) - ) - ) - ) - m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_ZERO].eq( - ((~guard_bit) & (round_bit | sticky_bit)) - | (guard_bit & (~round_bit) & (~sticky_bit)) + | ((~r_sign) & ((guard_bit & (~round_bit) & (~sticky_bit)) | ((~guard_bit) & (round_bit | sticky_bit)))) ) - m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_NEAREST_EVEN].eq( - ((~guard_bit) & round_bit & sticky_bit) | (guard_bit & (~round_bit)) + m.d.av_comb += shift_in_bit_zero.eq( + ((~guard_bit) & (round_bit | sticky_bit)) | (guard_bit & (~round_bit) & (~sticky_bit)) ) - m.d.av_comb += Shift_in_bit[RoundingModes.ROUND_NEAREST_AWAY].eq( - ((~guard_bit) & round_bit & sticky_bit) - | (guard_bit & (~(round_bit & sticky_bit))) + m.d.av_comb += shift_in_bit_rtne.eq(((~guard_bit) & round_bit & sticky_bit) | (guard_bit & (~round_bit))) + m.d.av_comb += shift_in_bit_rtna.eq( + ((~guard_bit) & round_bit & sticky_bit) | (guard_bit & (~(round_bit & sticky_bit))) ) - m.d.av_comb += g.eq( - (ORS & ORS_list[rounding_mode]) - | (NXS & NXS_list) - | (OLS & OLS_list[rounding_mode]) + with m.Switch(rounding_mode): + with m.Case(RoundingModes.ROUND_UP): + m.d.av_comb += g.eq((ors & ors_up) | (nxs & nxs_up) | (ols & ols_up)) + m.d.av_comb += shift_in_bit.eq(shift_in_bit_up) + with m.Case(RoundingModes.ROUND_DOWN): + m.d.av_comb += g.eq((ors & ors_down) | (nxs & nxs_down) | (ols & ols_down)) + m.d.av_comb += shift_in_bit.eq(shift_in_bit_down) + with m.Case(RoundingModes.ROUND_ZERO): + m.d.av_comb += g.eq((ors & ors_zero) | (nxs & nxs_zero) | (ols & ols_zero)) + m.d.av_comb += shift_in_bit.eq(shift_in_bit_zero) + + with m.Case(RoundingModes.ROUND_NEAREST_EVEN): + m.d.av_comb += g.eq((ors & ors_rtne) | (nxs & nxs_rtne) | (ols & ols_rtne)) + m.d.av_comb += shift_in_bit.eq(shift_in_bit_rtne) + + with m.Case(RoundingModes.ROUND_NEAREST_AWAY): + m.d.av_comb += g.eq((ors & ors_rtna) | (nxs & nxs_rtna) | (ols & ols_rtna)) + m.d.av_comb += shift_in_bit.eq(shift_in_bit_rtna) + + m.d.av_comb += round_up_inc_1.eq( + (rounding_mode == RoundingModes.ROUND_UP) + & nrs + & (~g) + & (~(sig_a[0] ^ sig_b[0])) + & ((~r_sign) & (rgs_any)) + ) + m.d.av_comb += round_down_inc_1.eq( + (rounding_mode == RoundingModes.ROUND_DOWN) + & nrs + & (~g) + & (~(sig_a[0] ^ sig_b[0])) + & (r_sign & (rgs_any)) ) - - m.d.av_comb += round_up_inc_1.eq(rounding_mode.ROUND_UP & NRS & (~g) & (~(sig_a[0] ^ sig_b[0])) & ((~r_sig) & (rgs_any))) - m.d.av_comb += round_down_inc_1.eq(rounding_mode.ROUND_DOWN & NRS & (~g) & (~(sig_a[0] ^ sig_b[0])) & (r_sig & (rgs_any))) - with m.If(g): m.d.av_comb += output_sig.eq(output_sig_add_1) with m.Else(): - m.d.av_comb += output_sig.eq(output_sig_add_0) + with m.If(round_down_inc_1 | round_up_inc_1): + m.d.av_comb += output_sig.eq(output_sig_add_0 | 1) + with m.Else(): + m.d.av_comb += output_sig.eq(output_sig_add_0) m.d.av_comb += output_exp.eq(exp) - with m.If(round_down_inc_1 | round_down_inc_1): - m.d.av_comb += output_sig.eq(output_sig | 1) - with m.If(sub_op): - m.d.av_comb += final_guard_bit.eq( - (~guard_bit) ^ ((~round_bit) & (~sticky_bit)) - ) + m.d.av_comb += final_guard_bit.eq((~guard_bit) ^ ((~round_bit) & (~sticky_bit))) m.d.av_comb += final_round_bit.eq((~round_bit) ^ (~sticky_bit)) m.d.av_comb += final_sticky_bit.eq(sticky_bit) @@ -276,29 +269,39 @@ def _( m.d.av_comb += final_round_bit.eq(round_bit) m.d.av_comb += final_sticky_bit.eq(sticky_bit) - with m.If(ORS): - m.d.av_comb += output_sticky_bit.eq( - final_guard_bit | final_round_bit | final_sticky_bit - ) + with m.If(ors): + m.d.av_comb += output_sticky_bit.eq(final_guard_bit | final_round_bit | final_sticky_bit) m.d.av_comb += output_round_bit.eq(sig_a[0] ^ sig_b[0]) - with m.Elif(OLS): + with m.Elif(ols): m.d.av_comb += output_sticky_bit.eq(final_sticky_bit) m.d.av_comb += output_round_bit.eq(final_round_bit) with m.Else(): m.d.av_comb += output_sticky_bit.eq(final_round_bit | final_sticky_bit) m.d.av_comb += output_round_bit.eq(final_guard_bit) - with m.If((~sub_op) & output_sig[-1]): - m.d.av_comb += output_sig.eq(output_sig >> 1) - m.d.av_comb += output_exp.eq(output_exp + 1) + with m.If((~sub_op) & (output_sig[-1])): + m.d.av_comb += output_final_sig.eq(output_sig >> 1) + m.d.av_comb += output_final_exp.eq(output_exp + 1) - with m.If(sub_op & (~output_sig[-2]) & out_exp > 0): - m.d.av_comb += output_sig.eq((output_sig << 1) | Shift_in_bit[rounding_mode]) - m.d.av_comb += output_exp.eq(output_exp - 1) + with m.Elif((sub_op & (~output_sig[-2])) & (output_exp > 0)): + with m.If(output_exp == 1): + m.d.av_comb += output_final_sig.eq(output_sig) + with m.Else(): + m.d.av_comb += output_final_sig.eq((output_sig << 1) | shift_in_bit) + m.d.av_comb += output_final_exp.eq(output_exp - 1) + + with m.Else(): + m.d.av_comb += output_final_sig.eq(output_sig) + with m.If((output_exp == 0) & ((output_sig[-2]))): + m.d.av_comb += output_final_exp.eq(1) + with m.Else(): + m.d.av_comb += output_final_exp.eq(output_exp) return { - "out_exp": output_exp, - "out_sig": output_sig, - "output_round_bit": output_round_bit, - "output_sticky_bit": output_sticky_bit, + "out_exp": output_final_exp, + "out_sig": output_final_sig, + "output_round": output_round_bit, + "output_sticky": output_sticky_bit, } + + return m diff --git a/test/func_blocks/fu/fpu/test_far_path.py b/test/func_blocks/fu/fpu/test_far_path.py index 939919f69..94bb09ad5 100644 --- a/test/func_blocks/fu/fpu/test_far_path.py +++ b/test/func_blocks/fu/fpu/test_far_path.py @@ -5,7 +5,6 @@ ) from transactron import TModule from transactron.lib import AdapterTrans -from parameterized import parameterized from transactron.testing import * from amaranth import * @@ -21,16 +20,14 @@ def elaborate(self, platform): m.submodules.compute = self.far_path_request_adapter = TestbenchIO(AdapterTrans(fp.far_path_request)) return m - params = FPUParams(sig_width=24, exp_width=8) - def test_far_path_addition(self): params = FPUParams(sig_width=24, exp_width=8) far_path = TestFarPath.FarPathModule(params) - async def test_ORS(sim:TestbenchContext): + + async def test_ors(sim: TestbenchContext): test_cases = [ - #one right_shift 000000000000000000000000 { "r_sign": 0, "sig_a": 0b111110000000000000000001, @@ -38,28 +35,1230 @@ async def test_ORS(sim:TestbenchContext): "exp": 10, "sub_op": 0, "rounding_mode": RoundingModes.ROUND_UP, - "guard_bit":0, - "round_bit":1, - "sticky_bit":0, - } - ] + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000001, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000001, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000011, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000010000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + ] expected_results = [ { - "out_exp":11, - "out_sig":0b100000000000000000000000, - "output_round":1, - "output_sticky":1, - } - ] + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000010, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000001, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 11, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 1, + }, + ] + for i in range(len(test_cases)): + resp = await far_path.far_path_request_adapter.call(sim, test_cases[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] + + async def test_nrs(sim: TestbenchContext): + test_cases = [ + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000000000000000, + "sig_b": 0b000000000000000000000001, + "exp": 10, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 1, + }, + ] + + expected_results = [ + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000010, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000010, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000000, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000010, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000000, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000010, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b111110000000000000000001, + "output_round": 0, + "output_sticky": 1, + }, + ] + for i in range(len(test_cases)): + resp = await far_path.far_path_request_adapter.call(sim, test_cases[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] + + async def test_ols(sim: TestbenchContext): + test_cases = [ + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 1, + }, + # ROUND_DOWN + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 1, + }, + # ROUND_ZERO + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + # ROUND_TO_NEAREST_TIE_TO_EVEN + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 1, + }, + # ROUND_TO_NEAREST_TIES_TO_AWAY + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b111110000000111010101000, + "sig_b": 0b100000000000010101000001, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + ] + expected_results = [ + { + "out_exp": 9, + "out_sig": 0b111100000010011111010010, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 1, + "output_sticky": 1, + }, + # ROUND_DOWN + { + "out_exp": 9, + "out_sig": 0b111100000010011111010010, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 1, + "output_sticky": 1, + }, + # ROUND_ZERO + { + "out_exp": 9, + "out_sig": 0b111100000010011111010010, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 0, + "output_sticky": 0, + }, + # ROUND_TO_NEAREST_TIE_TO_AWAY + { + "out_exp": 9, + "out_sig": 0b111100000010011111010010, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 1, + "output_sticky": 1, + }, + # ROUND_TO_NEAREST_TIES_TO_AWAY + { + "out_exp": 9, + "out_sig": 0b111100000010011111010010, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010011, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 9, + "out_sig": 0b111100000010011111010100, + "output_round": 1, + "output_sticky": 0, + }, + ] + for i in range(len(test_cases)): + resp = await far_path.far_path_request_adapter.call(sim, test_cases[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] + + async def test_nls(sim: TestbenchContext): + test_cases = [ + # ROUND_UP + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 0, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + # ROUND_DOWN + { + "r_sign": 0, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 0, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + # ROUND_ZERO + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_ZERO, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + # ROUND_TO_NEAREST_TIES_TO_EVEN + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111110, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + # ROUND_TO_NEAREST_TIES_TO_AWAY + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111110, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b111111111111111111111111, + "exp": 10, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_NEAREST_AWAY, + "guard_bit": 0, + "round_bit": 1, + "sticky_bit": 0, + }, + ] + + expected_results = [ + { + "out_exp": 10, + "out_sig": 0b101111111111111111111111, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + # ROUND_DOWN + { + "out_exp": 10, + "out_sig": 0b101111111111111111111111, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + # ROUND_ZERO + { + "out_exp": 10, + "out_sig": 0b101111111111111111111111, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + # ROUND_TO_NEAREST_TIES_TO_EVEN + { + "out_exp": 10, + "out_sig": 0b101111111111111111111110, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 1, + "output_sticky": 0, + }, + # ROUND_TO_NEAREST_TIES_TO_AWAY + { + "out_exp": 10, + "out_sig": 0b101111111111111111111110, + "output_round": 0, + "output_sticky": 1, + }, + { + "out_exp": 10, + "out_sig": 0b110000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + ] + + for i in range(len(test_cases)): + resp = await far_path.far_path_request_adapter.call(sim, test_cases[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] + + async def test_special(sim: TestbenchContext): + test_cases = [ + # overflow + { + "r_sign": 1, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b100000000000000000000000, + "exp": (2 ** (self.params.exp_width) - 2), + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + # add zero + { + "r_sign": 1, + "sig_a": 0b000000000000000000000000, + "sig_b": 0b000000000000000000000000, + "exp": 0, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + # Subnormal become normalized + { + "r_sign": 1, + "sig_a": 0b010000000000000000000000, + "sig_b": 0b001111111111111111111111, + "exp": 0, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_NEAREST_EVEN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 0, + }, + # add subnormals + { + "r_sign": 0, + "sig_a": 0b010000000000000000000000, + "sig_b": 0b000000000000010100000000, + "exp": 0, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_UP, + "guard_bit": 1, + "round_bit": 0, + "sticky_bit": 0, + }, + # add subnormal to normal + { + "r_sign": 0, + "sig_a": 0b110000000000000000000000, + "sig_b": 0b000000000000010100000000, + "exp": 1, + "sub_op": 0, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 1, + "round_bit": 1, + "sticky_bit": 1, + }, + # sub subnormal from normal + { + "r_sign": 0, + "sig_a": 0b100000000000000000000001, + "sig_b": 0b111111111111111111111110, + "exp": 3, + "sub_op": 1, + "rounding_mode": RoundingModes.ROUND_DOWN, + "guard_bit": 0, + "round_bit": 0, + "sticky_bit": 0, + }, + ] + + expected_results = [ + { + "out_exp": (2 ** (self.params.exp_width) - 1), + "out_sig": 0b101000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 0, + "out_sig": 0b000000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + { + "out_exp": 1, + "out_sig": 0b100000000000000000000000, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 0, + "out_sig": 0b010000000000010100000001, + "output_round": 1, + "output_sticky": 0, + }, + { + "out_exp": 1, + "out_sig": 0b110000000000010100000000, + "output_round": 1, + "output_sticky": 1, + }, + { + "out_exp": 3, + "out_sig": 0b100000000000000000000000, + "output_round": 0, + "output_sticky": 0, + }, + ] + for i in range(len(test_cases)): - resp = await far_path.far_path_request_adapter.call(sim,input_dict[i]) - assert resp.out_exp == expected_results[i]["out_exp"] - assert resp.out_sig == expected_results[i]["out_sig"] - assert resp.output_round == expected_results[i]["output_round"] - assert resp.output_sticky == expected_results[i]["output_sticky"] + resp = await far_path.far_path_request_adapter.call(sim, test_cases[i]) + assert resp.out_exp == expected_results[i]["out_exp"] + assert resp.out_sig == expected_results[i]["out_sig"] + assert resp.output_round == expected_results[i]["output_round"] + assert resp.output_sticky == expected_results[i]["output_sticky"] - async def test_process(sim:TestbenchContext): - await test_ORS(sim) + async def test_process(sim: TestbenchContext): + await test_ors(sim) + await test_nrs(sim) + await test_ols(sim) + await test_nls(sim) + await test_special(sim) - with self.run_simulation(fpurt) as sim: + with self.run_simulation(far_path) as sim: sim.add_testbench(test_process) From 2266234aa2429409a371a1476667964b46b357ad Mon Sep 17 00:00:00 2001 From: Mateusz Marszalek Date: Sun, 26 Jan 2025 22:57:16 +0100 Subject: [PATCH 4/4] Added/changed docstrings and small refactor --- coreblocks/func_blocks/fu/fpu/far_path.py | 30 +++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/coreblocks/func_blocks/fu/fpu/far_path.py b/coreblocks/func_blocks/fu/fpu/far_path.py index 055fe4584..d52abdc6f 100644 --- a/coreblocks/func_blocks/fu/fpu/far_path.py +++ b/coreblocks/func_blocks/fu/fpu/far_path.py @@ -13,7 +13,18 @@ class FarPathMethodLayout: """ def __init__(self, *, fpu_params: FPUParams): - + """ + r_sign - result sign + sig_a - significand of first operand (for effective subtraction in two's complement form) + sig_b - significand of second operand (for effective subtraction in two's complement form) + exp - exponent of result before shift + sub_op - effective operation. 1 for subtraction 0 for addition + rounding_mode - rounding mode + guard_bit - guard bit (pth bit of second significand where p is precision) + round_bit - round bit ((p+1)th bit of second significand where p is precision) + sticky_bit - sticky_bit + (OR of all bits with index >=p of second significand where p is precision) + """ self.far_path_in_layout = [ ("r_sign", 1), ("sig_a", fpu_params.sig_width), @@ -35,6 +46,15 @@ def __init__(self, *, fpu_params: FPUParams): class FarPathModule(Elaboratable): """Far Path module + Based on: https://userpages.cs.umbc.edu/phatak/645/supl/lza/lza-survey-arith01.pdf. + This module implement far path of adder/subtractor. + It performs subtraction for operands whose exponent differs by more than 1 and addition + for all combination of operand. Besides addition it also perform rounding at the same time + as addition using two adder (one producing a+b and second one producing a+b+1). The correct + output is chosen by flags that differ for each rounding module. To deal with certain + complication that may arise during addition in certaing roudning modes the input of second + may be either input operand or (a & b)<<1 and (a^b). This allows second adder to compute + a+b+2 in special cases that are better explained in paper linked above. Parameters ---------- @@ -67,7 +87,6 @@ def elaborate(self, platform): input_sig_add_1_b = Signal(self.params.sig_width) output_sig_add_0 = Signal(self.params.sig_width + 1) output_sig_add_1 = Signal(self.params.sig_width + 1) - output_sig_add_1_check = Signal(self.params.sig_width + 1) output_sig = Signal(self.params.sig_width + 1) output_exp = Signal(self.params.exp_width + 1) output_final_exp = Signal(self.params.exp_width) @@ -144,7 +163,6 @@ def _( m.d.av_comb += carry_add1.eq(carry_sig[-1]) m.d.av_comb += rgs_any.eq(guard_bit | round_bit | sticky_bit) m.d.av_comb += rgs_all.eq(guard_bit & round_bit & sticky_bit) - m.d.av_comb += output_sig_add_1_check.eq(sig_a + sig_b + 1) m.d.av_comb += round_to_inf_special_case.eq( (~sub_op) & ((rounding_mode == RoundingModes.ROUND_DOWN) | (rounding_mode == RoundingModes.ROUND_UP)) ) @@ -164,11 +182,9 @@ def _( m.d.av_comb += nrs.eq((~sub_op) & (~output_sig_add_0[-1])) m.d.av_comb += ors.eq((~sub_op) & (output_sig_add_0[-1])) - m.d.av_comb += nls.eq( - sub_op & (((~rgs_any) & output_sig_add_1_check[-2]) | (rgs_any & output_sig_add_0[-2])) - ) + m.d.av_comb += nls.eq(sub_op & (((~rgs_any) & output_sig_add_1[-2]) | (rgs_any & output_sig_add_0[-2]))) m.d.av_comb += ols.eq( - sub_op & (((~rgs_any) & (~output_sig_add_1_check[-2])) | (rgs_any & (~output_sig_add_0[-2]))) + sub_op & (((~rgs_any) & (~output_sig_add_1[-2])) | (rgs_any & (~output_sig_add_0[-2]))) ) m.d.av_comb += nxs.eq(nls | nrs)