From 88600716c65797a22d122640bcd3c24af2f8f3e5 Mon Sep 17 00:00:00 2001 From: dev-aditya-hub Date: Thu, 21 May 2026 17:25:15 +0530 Subject: [PATCH] frm coverpoints: sweep all 5 fcsr.frm values for dyn rounding mode --- .../testgen/coverpoints/cp_fp_reg_edges.py | 24 +++++++--- .../testgen/src/testgen/coverpoints/cp_frm.py | 20 ++++++--- .../testgen/coverpoints/cr_fp_reg_edges.py | 45 ++++++++++++++----- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/generators/testgen/src/testgen/coverpoints/cp_fp_reg_edges.py b/generators/testgen/src/testgen/coverpoints/cp_fp_reg_edges.py index 29361287d5..738b02d7ad 100644 --- a/generators/testgen/src/testgen/coverpoints/cp_fp_reg_edges.py +++ b/generators/testgen/src/testgen/coverpoints/cp_fp_reg_edges.py @@ -30,14 +30,28 @@ def make_fs1_edges(instr_name: str, instr_type: str, coverpoint: str, test_data: cross_frm = "_frm" in coverpoint - frm_modes = ("dyn", "rdn", "rmm", "rne", "rtz", "rup") if cross_frm else [None] + # For dyn we sweep all 5 legal fcsr.frm values explicitly; relying on a random pick + # lands on rne 20% of the time and hides a DUT that ignores fcsr.frm. + if cross_frm: + frm_variants: list[tuple[str | None, int | None]] = [("dyn", v) for v in range(5)] + frm_variants += [(m, None) for m in ("rdn", "rmm", "rne", "rtz", "rup")] + else: + frm_variants = [(None, None)] test_chunks: list[TestChunk] = [] for edge_val in edges: - for frm_mode in frm_modes: - params = generate_random_params(test_data, instr_type, exclude_regs=[0], fs1val=edge_val, frm=frm_mode) - bin_name = f"b{edge_val:#x}{f'_{frm_mode}' if frm_mode is not None else ''}" - desc = f"{coverpoint} (Test source fs1 value = {test_data.flen_format_str.format(edge_val)}{f', frm = {frm_mode}' if frm_mode is not None else ''})" + for frm_mode, csr_val in frm_variants: + params = generate_random_params( + test_data, instr_type, exclude_regs=[0], fs1val=edge_val, frm=frm_mode, csr_frm_val=csr_val + ) + frm_tag = "" + if frm_mode is not None: + frm_tag = f"_{frm_mode}{csr_val}" if csr_val is not None else f"_{frm_mode}" + bin_name = f"b{edge_val:#x}{frm_tag}" + desc_tag = "" + if frm_mode is not None: + desc_tag = f", frm = {frm_mode}" + (f", fcsr.frm = {csr_val}" if csr_val is not None else "") + desc = f"{coverpoint} (Test source fs1 value = {test_data.flen_format_str.format(edge_val)}{desc_tag})" tc = format_single_testcase(instr_name, instr_type, test_data, params, desc, bin_name, coverpoint) test_chunks.append(tc) return_test_regs(test_data, params) diff --git a/generators/testgen/src/testgen/coverpoints/cp_frm.py b/generators/testgen/src/testgen/coverpoints/cp_frm.py index 60d86bf53e..57c76573f9 100644 --- a/generators/testgen/src/testgen/coverpoints/cp_frm.py +++ b/generators/testgen/src/testgen/coverpoints/cp_frm.py @@ -21,12 +21,22 @@ def make_frm(instr_name: str, instr_type: str, coverpoint: str, test_data: TestD if coverpoint not in ["cp_frm_2", "cp_frm_3", "cp_frm_4"]: # TODO: Why are these variants needed? raise ValueError(f"Unknown cp_frm coverpoint variant: {coverpoint} for {instr_name}") - frm_modes = ("dyn", "rdn", "rmm", "rne", "rtz", "rup") + # Static modes encode rm in the instruction. For dyn, rm=111 in the encoding and the + # actual rounding comes from fcsr.frm, so we sweep all 5 legal frm values explicitly + # rather than relying on a random pick that lands on rne (the power-on default) 20% of + # the time and silently agrees with a DUT that ignores fcsr.frm. + frm_variants: list[tuple[str, int | None]] = [("dyn", v) for v in range(5)] + frm_variants += [(m, None) for m in ("rdn", "rmm", "rne", "rtz", "rup")] + test_chunks: list[TestChunk] = [] - for frm_mode in frm_modes: - params = generate_random_params(test_data, instr_type, exclude_regs=[0], frm=frm_mode) - desc = f"{coverpoint} (Test frm, mode = {frm_mode})" - tc = format_single_testcase(instr_name, instr_type, test_data, params, desc, f"b{frm_mode}", coverpoint) + for frm_mode, csr_val in frm_variants: + params = generate_random_params( + test_data, instr_type, exclude_regs=[0], frm=frm_mode, csr_frm_val=csr_val + ) + bin_name = f"b{frm_mode}{csr_val}" if csr_val is not None else f"b{frm_mode}" + desc_suffix = f", fcsr.frm = {csr_val}" if csr_val is not None else "" + desc = f"{coverpoint} (Test frm, mode = {frm_mode}{desc_suffix})" + tc = format_single_testcase(instr_name, instr_type, test_data, params, desc, bin_name, coverpoint) test_chunks.append(tc) return_test_regs(test_data, params) diff --git a/generators/testgen/src/testgen/coverpoints/cr_fp_reg_edges.py b/generators/testgen/src/testgen/coverpoints/cr_fp_reg_edges.py index aecc340dc1..e27ebae8d1 100644 --- a/generators/testgen/src/testgen/coverpoints/cr_fp_reg_edges.py +++ b/generators/testgen/src/testgen/coverpoints/cr_fp_reg_edges.py @@ -34,18 +34,29 @@ def make_cr_fs1_fs2_edges(instr_name: str, instr_type: str, coverpoint: str, tes cross_frm = "_frm" in coverpoint - frm_modes = ("dyn", "rdn", "rmm", "rne", "rtz", "rup") if cross_frm else [None] + # For dyn we sweep all 5 legal fcsr.frm values explicitly rather than picking one + # randomly, so a DUT that ignores fcsr.frm can't slip past on the rne case. + if cross_frm: + frm_variants: list[tuple[str | None, int | None]] = [("dyn", v) for v in range(5)] + frm_variants += [(m, None) for m in ("rdn", "rmm", "rne", "rtz", "rup")] + else: + frm_variants = [(None, None)] test_chunks: list[TestChunk] = [] for edge_val1 in edges1: for edge_val2 in edges2: - # Explicit rounding modes (if needed) - for frm_mode in frm_modes: + for frm_mode, csr_val in frm_variants: params = generate_random_params( - test_data, instr_type, exclude_regs=[0], fs1val=edge_val1, fs2val=edge_val2, frm=frm_mode + test_data, instr_type, exclude_regs=[0], + fs1val=edge_val1, fs2val=edge_val2, + frm=frm_mode, csr_frm_val=csr_val, ) - bin_name = f"fs1val={edge_val1:#x}, fs2val={edge_val2:#x}, frm={frm_mode}" - desc = f"{coverpoint} (Test source fs1 = {test_data.flen_format_str.format(edge_val1)} fs2 = {test_data.flen_format_str.format(edge_val2)}{f', frm = {frm_mode}' if frm_mode is not None else ''})" + frm_label = "none" if frm_mode is None else (f"{frm_mode}{csr_val}" if csr_val is not None else frm_mode) + bin_name = f"fs1val={edge_val1:#x}, fs2val={edge_val2:#x}, frm={frm_label}" + desc_tag = "" + if frm_mode is not None: + desc_tag = f", frm = {frm_mode}" + (f", fcsr.frm = {csr_val}" if csr_val is not None else "") + desc = f"{coverpoint} (Test source fs1 = {test_data.flen_format_str.format(edge_val1)} fs2 = {test_data.flen_format_str.format(edge_val2)}{desc_tag})" tc = format_single_testcase(instr_name, instr_type, test_data, params, desc, bin_name, coverpoint) test_chunks.append(tc) return_test_regs(test_data, params) @@ -71,18 +82,28 @@ def make_cr_fs1_fs3_edges(instr_name: str, instr_type: str, coverpoint: str, tes cross_frm = "_frm" in coverpoint - frm_modes = ("dyn", "rdn", "rmm", "rne", "rtz", "rup") if cross_frm else [None] + # See note in make_cr_fs1_fs2_edges — dyn is expanded into 5 explicit fcsr.frm values. + if cross_frm: + frm_variants: list[tuple[str | None, int | None]] = [("dyn", v) for v in range(5)] + frm_variants += [(m, None) for m in ("rdn", "rmm", "rne", "rtz", "rup")] + else: + frm_variants = [(None, None)] test_chunks: list[TestChunk] = [] for edge_val1 in edges1: for edge_val2 in edges2: - # Explicit rounding modes (if needed) - for frm_mode in frm_modes: + for frm_mode, csr_val in frm_variants: params = generate_random_params( - test_data, instr_type, exclude_regs=[0], fs1val=edge_val1, fs3val=edge_val2, frm=frm_mode + test_data, instr_type, exclude_regs=[0], + fs1val=edge_val1, fs3val=edge_val2, + frm=frm_mode, csr_frm_val=csr_val, ) - desc = f"{coverpoint} (Test source fs1 = {test_data.flen_format_str.format(edge_val1)} fs3 = {test_data.flen_format_str.format(edge_val2)}{f', frm = {frm_mode}' if frm_mode is not None else ''})" - bin_name = f"fs1val={edge_val1:#x}, fs3val={edge_val2:#x}, frm={frm_mode}" + frm_label = "none" if frm_mode is None else (f"{frm_mode}{csr_val}" if csr_val is not None else frm_mode) + bin_name = f"fs1val={edge_val1:#x}, fs3val={edge_val2:#x}, frm={frm_label}" + desc_tag = "" + if frm_mode is not None: + desc_tag = f", frm = {frm_mode}" + (f", fcsr.frm = {csr_val}" if csr_val is not None else "") + desc = f"{coverpoint} (Test source fs1 = {test_data.flen_format_str.format(edge_val1)} fs3 = {test_data.flen_format_str.format(edge_val2)}{desc_tag})" tc = format_single_testcase(instr_name, instr_type, test_data, params, desc, bin_name, coverpoint) test_chunks.append(tc) return_test_regs(test_data, params)