From 084497f58ffd27349fd1796ec046a0e09666022c Mon Sep 17 00:00:00 2001 From: Stephen More Date: Tue, 19 May 2026 00:22:26 -0400 Subject: [PATCH 1/3] added bram tests, some small fixes to get mtj able to run --- src/common/spice_parser.py | 28 ++ tests/conftest.py | 1 + tests/test_stratix_iv.py | 163 ++++++- .../spice_models/ptm_22nm_bulk_hp_mtj.l | 425 ++++++++++++++++++ 4 files changed, 616 insertions(+), 1 deletion(-) create mode 100644 third_party/spice_models/ptm_22nm_bulk_hp_mtj.l diff --git a/src/common/spice_parser.py b/src/common/spice_parser.py index ad6555d..f2c0ff2 100644 --- a/src/common/spice_parser.py +++ b/src/common/spice_parser.py @@ -173,6 +173,34 @@ def init_atomic_libs() -> Dict[str, rg_ds.SpSubCkt]: "PSEO" : f"{pfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", "PDEO" : f"{pfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", } + ), + "nmos_lp_mtj" : rg_ds.SpSubCkt( + name = "nmos_lp_mtj", + element = "mnfet", + ports = mfet_ports, + params = { + "L" : "gate_length", + "M" : "1", + "nfin" : f"{nfet_width_param}", + "ASEO" : f"{nfet_width_param} * min_tran_width * trans_diffusion_length", + "ADEO" : f"{nfet_width_param} * min_tran_width * trans_diffusion_length", + "PSEO" : f"{nfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", + "PDEO" : f"{nfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", + } + ), + "pmos_lp_mtj" : rg_ds.SpSubCkt( + name = "pmos_lp_mtj", + element = "mpfet", + ports = mfet_ports, + params = { + "L" : "gate_length", + "M" : "1", + "nfin" : f"{pfet_width_param}", + "ASEO" : f"{pfet_width_param} * min_tran_width * trans_diffusion_length", + "ADEO" : f"{pfet_width_param} * min_tran_width * trans_diffusion_length", + "PSEO" : f"{pfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", + "PDEO" : f"{pfet_width_param} * (min_tran_width + 2 * trans_diffusion_length)", + } ) } return sp_subckt_atomic_lib diff --git a/tests/conftest.py b/tests/conftest.py index f091ab7..cc236ce 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -80,6 +80,7 @@ def pytest_collection_modifyitems(session: pytest.Session, config: pytest.Config data['originalname'] = item.originalname data['file'] = item.location[0] data['markers'] = [marker.name for marker in item.own_markers] + data['fixturenames'] = list(getattr(item, 'fixturenames', []) or []) data_list.append(data) print(json.dumps(data_list)) # Remove all items (we don't want to execute the tests) diff --git a/tests/test_stratix_iv.py b/tests/test_stratix_iv.py index b1adef3..e7bf7d7 100644 --- a/tests/test_stratix_iv.py +++ b/tests/test_stratix_iv.py @@ -295,8 +295,169 @@ def test_stratix_iv_bram_passthrough(stratix_iv_bram_passthrough_tb: rg_ds.RadGe def test_stratix_iv_bram(stratix_iv_bram_tb, request: pytest.FixtureRequest): rg_args = copy.deepcopy(stratix_iv_bram_tb) ret_val: Any = tests_common.run_rad_gen( - rg_args, + rg_args, + tests_common.get_rg_home(), + ) + + +# --------------------------------------------------------------------------- +# Parametrized BRAM unit tests (22nm process) +# --------------------------------------------------------------------------- +# Each entry: (yaml_basename, label_for_obj_dir, pytest_markers) +# These mirror the BRAM configurations from legacy COFFE's input_files/BRAM/ +# (Chiasson/Betz, FPT 2013) and exercise different paths through the BRAM +# generation code: varying memory geometry, SRAM vs MTJ technology, and +# pass_transistor vs transmission_gate switches. +# Parameter tuples: (yaml_basename, label_for_obj_dir) +# Each entry is wrapped in pytest.param() so we can attach distinct markers. +# Two case lists: +# * _BRAM_22NM_PASSTHROUGH_CASES — exercises the full COFFE BRAM netlist +# generation path in pass-through mode (slower, ~3-4 min per case). +# * _BRAM_22NM_CONF_INIT_CASES — just parses the yaml + initializes the +# Coffe dataclass (sub-second per case). Includes one extra case +# (pass_transistor switch) that the passthrough flow can't currently +# handle due to an unrelated assertion in src/coffe/mux.py:209. +# The MTJ case carries an extra `slow` marker because the MTJ-specific +# sub-circuits dominate sizing-iteration time; users can deselect with +# `pytest -m "not slow"`. +_BRAM_22NM_PASSTHROUGH_CASES = [ + pytest.param( + ("stratix_iv_rrg_bram_ram32.yml", "ram32_sram_tgate"), + marks = [pytest.mark.bram], + id = "ram32_sram_tgate", + ), + pytest.param( + ("stratix_iv_rrg_bram_ram64.yml", "ram64_sram_tgate"), + marks = [pytest.mark.bram], + id = "ram64_sram_tgate", + ), + pytest.param( + ("stratix_iv_rrg_bram_ram128.yml", "ram128_sram_tgate"), + marks = [pytest.mark.bram], + id = "ram128_sram_tgate", + ), + pytest.param( + ("stratix_iv_rrg_bram_mtj32.yml", "mtj32_tgate"), + marks = [pytest.mark.bram, pytest.mark.mtj, pytest.mark.slow], + id = "mtj32_tgate", + ), +] + +_BRAM_22NM_CONF_INIT_CASES = _BRAM_22NM_PASSTHROUGH_CASES + [ + pytest.param( + ("stratix_iv_rrg_bram_pt_switch.yml", "ram32_sram_ptran"), + marks = [pytest.mark.bram], + id = "ram32_sram_ptran", + ), +] + + +@pytest.fixture +def stratix_iv_bram_22nm_tb(stratix_iv, request: pytest.FixtureRequest) -> rg_ds.RadGenArgs: + """ + Parametrized fixture that points the stratix_iv driver at one of the + 22nm BRAM yaml configs and gives it a unique output directory. + + Indirect-parametrize this fixture with a (yaml_basename, label) tuple. + """ + yaml_basename, label = request.param + + tests_tree: rg_ds.Tree + tests_tree, test_grp_name, test_name, test_out_dpath, rg_home = tests_common.get_test_info() + cur_test_input_dpath: str = tests_tree.search_subtrees( + f"tests.data.{test_grp_name}.inputs", + is_hier_tag = True, + )[0].path + + bram_yaml_fpath: str = os.path.join(cur_test_input_dpath, yaml_basename) + assert os.path.exists(bram_yaml_fpath), f"BRAM yaml path {bram_yaml_fpath} does not exist" + + rg_args: rg_ds.RadGenArgs = copy.deepcopy(stratix_iv) + rg_args.subtool_args.fpga_arch_conf_path = bram_yaml_fpath + # pass_through skips the actual hspice simulations during sizing but still + # exercises the full COFFE BRAM netlist generation path. Combined with the + # inherited max_iterations = 1 this keeps each test to a single sizing pass. + rg_args.subtool_args.pass_through = True + rg_args.manual_obj_dir = os.path.join( + tests_tree.search_subtrees(f"tests.data.{test_grp_name}.outputs", is_hier_tag = True)[0].path, + f"stratix_iv_rrg_bram_22nm_{label}_passthrough_debug", + ) + tests_common.write_fixture_json(rg_args) + + return rg_args + + +@pytest.mark.stratix_iv +@pytest.mark.custom_fpga +@pytest.mark.parametrize( + "stratix_iv_bram_22nm_tb", + _BRAM_22NM_PASSTHROUGH_CASES, + indirect = True, +) +@skip_if_fixtures_only +def test_stratix_iv_bram_22nm_passthrough( + stratix_iv_bram_22nm_tb: rg_ds.RadGenArgs, request: pytest.FixtureRequest +): + """ + Runs the COFFE BRAM flow end-to-end in pass-through mode for each + legacy COFFE BRAM configuration at 22nm. + + Pass-through skips the actual hspice simulations but still runs: + - YAML config parsing & arch_params validation + - FPGA + BRAM subcircuit object instantiation + - SPICE netlist generation for every BRAM subcircuit (memory cell, + row/col/conf decoders, sense amp, write driver, precharge, + wordline driver, RAM local mux, output crossbar, etc.) + - VPR architecture file emission with the BRAM block + + These together cover the BRAM-specific code paths an + --enable_bram_module=1 run touches. + + Note: the MTJ case is marked `slow` because its mtj-specific + sub-circuits add substantially to sizing-iteration time even in + pass-through mode. Deselect with `pytest -m "not slow"`. + """ + rg_args = copy.deepcopy(stratix_iv_bram_22nm_tb) + tests_common.run_rad_gen( + rg_args, + tests_common.get_rg_home(), + ) + + +# Separate conf-init fixture/test: just verifies the BRAM yamls parse into +# valid CoffeArgs / Coffe data structures without invoking the COFFE flow. +@pytest.fixture +def stratix_iv_bram_22nm_conf_init_tb(stratix_iv_bram_22nm_tb) -> rg_ds.RadGenArgs: + rg_args = copy.deepcopy(stratix_iv_bram_22nm_tb) + rg_args.just_config_init = True + rg_args.subtool_args.pass_through = False + return rg_args + + +@pytest.mark.init +@pytest.mark.custom_fpga +@pytest.mark.parametrize( + "stratix_iv_bram_22nm_tb", + _BRAM_22NM_CONF_INIT_CASES, + indirect = True, +) +@skip_if_fixtures_only +def test_stratix_iv_bram_22nm_conf_init( + stratix_iv_bram_22nm_conf_init_tb: rg_ds.RadGenArgs, request: pytest.FixtureRequest +): + """ + Fast smoke test: confirms each BRAM yaml can be parsed and yields a + valid rad_gen Coffe configuration without running the rest of the flow. + """ + rg_args = copy.deepcopy(stratix_iv_bram_22nm_conf_init_tb) + rg_info, _ = tests_common.run_rad_gen( + rg_args, tests_common.get_rg_home(), ) + # Basic sanity: the parsed config should have BRAM enabled and gate_length 22nm. + coffe_struct = rg_info["coffe"] + arch_params = coffe_struct.fpga_arch_conf["fpga_arch_params"] + assert arch_params["enable_bram_module"] == 1, "enable_bram_module not set to 1" + assert arch_params["gate_length"] == 22, "gate_length is not 22nm" diff --git a/third_party/spice_models/ptm_22nm_bulk_hp_mtj.l b/third_party/spice_models/ptm_22nm_bulk_hp_mtj.l new file mode 100644 index 0000000..d9c57cc --- /dev/null +++ b/third_party/spice_models/ptm_22nm_bulk_hp_mtj.l @@ -0,0 +1,425 @@ +* SPICE models for used for COFFE's 'bulk_example.txt' +* The models are from PTM (http://ptm.asu.edu/) +* Please don't forget to acknowledge/cite PTM if you use these models. + +* PTM High Performance 22nm Metal Gate / High-K / Strained-Si +* nominal Vdd = 0.8V + +* 22NM_BULK_HP is the COFFE 'model_library' parameter. +.LIB 22NM_BULK_HP + +.model nmos nmos level = 54 + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.05e-009 toxp = 8e-010 toxm = 1.05e-009 ++dtox = 2.5e-010 epsrox = 3.9 wint = 5e-009 lint = 2e-009 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.05e-009 ++xl = -9e-9 + ++vth0 = 0.50308 k1 = 0.4 k2 = 0 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = 0 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.1 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 5.5e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.13 nfactor = 2.3 eta0 = 0.004 etab = 0 ++vfb = -0.55 u0 = 0.04 ua = 6e-010 ub = 1.2e-018 ++uc = 0 vsat = 250000 a0 = 1 ags = 0 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = 0.04 dwg = 0 dwb = 0 pclm = 0.02 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = -0.005 drout = 0.5 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007 ++fprout = 0.2 pdits = 0.01 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 145 rsw = 75 rdw = 75 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.0213 bigc = 0.0025889 ++cigc = 0.002 aigsd = 0.0213 bigsd = 0.0025889 cigsd = 0.002 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + + + +.model pmos pmos level = 54 + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.1e-009 toxp = 8e-010 toxm = 1.1e-009 ++dtox = 3e-010 epsrox = 3.9 wint = 5e-009 lint = 2e-009 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.1e-009 ++xl = -9e-9 + ++vth0 = -0.4606 k1 = 0.4 k2 = -0.01 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.05 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 4.4e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.126 nfactor = 2.1 eta0 = 0.0038 etab = 0 ++vfb = 0.55 u0 = 0.0095 ua = 2e-009 ub = 5e-019 ++uc = 0 vsat = 210000 a0 = 1 ags = 1e-020 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = -0.047 dwg = 0 dwb = 0 pclm = 0.12 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = 3.4e-008 drout = 0.56 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007 ++fprout = 0.2 pdits = 0.08 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 145 rsw = 72.5 rdw = 72.5 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.0213 bigc = 0.0025889 ++cigc = 0.002 aigsd = 0.0213 bigsd = 0.0025889 cigsd = 0.002 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + + + +.model nmos_lp nmos level = 54 + + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.4e-009 toxp = 1.1e-009 toxm = 1.4e-009 ++dtox = 3e-010 epsrox = 3.9 wint = 5e-009 lint = 0 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009 + ++vth0 = 0.58858 k1 = 0.4 k2 = 0 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = 0 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.1 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 5.5e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.1092 nfactor = 1.6 eta0 = 0.0105 etab = 0 ++vfb = -0.55 u0 = 0.035 ua = 6e-010 ub = 1.2e-018 ++uc = 0 vsat = 170000 a0 = 1 ags = 0 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = 0.04 dwg = 0 dwb = 0 pclm = 0.02 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = -0.005 drout = 0.5 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007 ++fprout = 0.2 pdits = 0.01 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 180 rsw = 75 rdw = 75 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.015211 bigc = 0.0027432 ++cigc = 0.002 aigsd = 0.015211 bigsd = 0.0027432 cigsd = 0.002 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + + +.model pmos_lp pmos level = 54 + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.4e-009 toxp = 1.08e-009 toxm = 1.42e-009 ++dtox = 3.2e-010 epsrox = 3.9 wint = 5e-009 lint = 0 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.42e-009 + ++vth0 = -0.53745 k1 = 0.4 k2 = -0.01 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.05 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 4.4e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.09 nfactor = 1.8 eta0 = 0.0105 etab = 0 ++vfb = 0.55 u0 = 0.011 ua = 2e-009 ub = 5e-019 ++uc = 0 vsat = 170000 a0 = 1 ags = 1e-020 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = -0.047 dwg = 0 dwb = 0 pclm = 0.12 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = 3.4e-008 drout = 0.56 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007 ++fprout = 0.2 pdits = 0.08 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 230 rsw = 72.5 rdw = 72.5 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.0097 bigc = 0.00125 ++cigc = 0.0008 aigsd = 0.0097 bigsd = 0.00125 cigsd = 0.0008 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + + + +.model nmos_lp_mtj nmos level = 54 + + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.4e-009 toxp = 1.1e-009 toxm = 1.4e-009 ++dtox = 3e-010 epsrox = 3.9 wint = 5e-009 lint = 0 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009 + ++vth0 = 0.48858 k1 = 0.4 k2 = 0 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = 0 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.1 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 5.5e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.1092 nfactor = 1.6 eta0 = 0.0105 etab = 0 ++vfb = -0.55 u0 = 0.035 ua = 6e-010 ub = 1.2e-018 ++uc = 0 vsat = 170000 a0 = 1 ags = 0 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = 0.04 dwg = 0 dwb = 0 pclm = 0.02 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = -0.005 drout = 0.5 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007 ++fprout = 0.2 pdits = 0.01 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 180 rsw = 75 rdw = 75 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.015211 bigc = 0.0027432 ++cigc = 0.002 aigsd = 0.015211 bigsd = 0.0027432 cigsd = 0.002 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + + +.model pmos_lp_mtj pmos level = 54 + ++version = 4.0 binunit = 1 paramchk= 1 mobmod = 0 ++capmod = 2 igcmod = 1 igbmod = 1 geomod = 1 ++diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1 ++permod = 1 acnqsmod= 0 trnqsmod= 0 + ++tnom = 27 toxe = 1.4e-009 toxp = 1.08e-009 toxm = 1.42e-009 ++dtox = 3.2e-010 epsrox = 3.9 wint = 5e-009 lint = 0 ++ll = 0 wl = 0 lln = 1 wln = 1 ++lw = 0 ww = 0 lwn = 1 wwn = 1 ++lwl = 0 wwl = 0 xpart = 0 toxref = 1.42e-009 + ++vth0 = -0.43745 k1 = 0.4 k2 = -0.01 k3 = 0 ++k3b = 0 w0 = 2.5e-006 dvt0 = 1 dvt1 = 2 ++dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0 ++dsub = 0.1 minv = 0.05 voffl = 0 dvtp0 = 1e-011 ++dvtp1 = 0.05 lpe0 = 0 lpeb = 0 xj = 7.2e-009 ++ngate = 1e+023 ndep = 4.4e+018 nsd = 2e+020 phin = 0 ++cdsc = 0 cdscb = 0 cdscd = 0 cit = 0 ++voff = -0.09 nfactor = 1.8 eta0 = 0.0105 etab = 0 ++vfb = 0.55 u0 = 0.011 ua = 2e-009 ub = 5e-019 ++uc = 0 vsat = 170000 a0 = 1 ags = 1e-020 ++a1 = 0 a2 = 1 b0 = 0 b1 = 0 ++keta = -0.047 dwg = 0 dwb = 0 pclm = 0.12 ++pdiblc1 = 0.001 pdiblc2 = 0.001 pdiblcb = 3.4e-008 drout = 0.56 ++pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007 ++fprout = 0.2 pdits = 0.08 pditsd = 0.23 pditsl = 2300000 ++rsh = 5 rdsw = 230 rsw = 72.5 rdw = 72.5 ++rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0 ++prwb = 0 wr = 1 alpha0 = 0.074 alpha1 = 0.005 ++beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002 ++egidl = 0.8 aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002 ++nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004 ++eigbinv = 1.1 nigbinv = 3 aigc = 0.0097 bigc = 0.00125 ++cigc = 0.0008 aigsd = 0.0097 bigsd = 0.00125 cigsd = 0.0008 ++nigc = 1 poxedge = 1 pigcd = 1 ntox = 1 ++xrcrg1 = 12 xrcrg2 = 5 + ++cgso = 6.5e-011 cgdo = 6.5e-011 cgbo = 2.56e-011 cgdl = 2.653e-010 ++cgsl = 2.653e-010 ckappas = 0.03 ckappad = 0.03 acde = 1 ++moin = 15 noff = 0.9 voffcv = 0.02 + ++kt1 = -0.11 kt1l = 0 kt2 = 0.022 ute = -1.5 ++ua1 = 4.31e-009 ub1 = 7.61e-018 uc1 = -5.6e-011 prt = 0 ++at = 33000 + ++fnoimod = 1 tnoimod = 0 + ++jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1 ++ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1 ++jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1 ++ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1 ++pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1 ++cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 3e-010 ++mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5 ++pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1 ++cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001 ++tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001 ++xtis = 3 xtid = 3 + ++dmcg = 0 dmci = 0 dmdg = 0 dmcgt = 0 ++dwj = 0 xgw = 0 xgl = 0 + ++rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15 ++rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1 + +.ENDL 22NM_HP From 0a8d8c0c3d868210d4526c6e9bbfb89adaac82e4 Mon Sep 17 00:00:00 2001 From: Stephen More Date: Tue, 19 May 2026 01:53:12 -0400 Subject: [PATCH 2/3] modified ERF section of trans sizing to gracefully error on HSPICE failure and just set a high cost for failing datapoints --- src/coffe/legacy_tran_sizing.py | 60 +++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/src/coffe/legacy_tran_sizing.py b/src/coffe/legacy_tran_sizing.py index 8f6fc5d..d4d75ab 100644 --- a/src/coffe/legacy_tran_sizing.py +++ b/src/coffe/legacy_tran_sizing.py @@ -989,13 +989,25 @@ def erf_inverter(sp_path, inv_trise_str = spice_meas["meas_" + inv_name + "_trise"][0] # Check if the HSPICE measurement failed. If it did, this might mean that the level - # restorers are too strong which messes up one of the transitions. Making the gate - # length for the level restorers larger could solve this problem. - # Note that it's also possible that something else is causing the failure... + # restorers are too strong which messes up one of the transitions, or that the + # inverter is sized too small to drive its load within the simulation window. + # Instead of aborting the whole run, skip ERF for this inverter and leave it at the + # symmetric (un-balanced) size. The combo will be naturally penalized in cost + # evaluation because run_combo / erf_combo also handle "failed" gracefully below. if inv_tfall_str == "failed" or inv_trise_str == "failed": - print("ERROR: HSPICE measurement failed.") - print("Consider increasing level-restorers gate length by increasing the 'rest_length_factor' parameter in the input file.") - exit(1) + print("WARNING: HSPICE measurement failed for " + inv_name + " at N=P=" + str(inv_size) + ".") + print(" This usually means the inverter is too weak to drive its load,") + print(" or that level-restorers are too strong (try increasing 'rest_length_factor').") + print(" Leaving " + inv_name + " un-ERFed; this combo will lose to others via cost ranking.") + # Keep fpga_inst.transistor_sizes consistent with parameter_dict (already at N=P=inv_size). + if not fpga_inst.specs.use_finfet: + fpga_inst.transistor_sizes[nmos_name] = inv_size / fpga_inst.specs.min_tran_width + fpga_inst.transistor_sizes[pmos_name] = inv_size / fpga_inst.specs.min_tran_width + else: + fpga_inst.transistor_sizes[nmos_name] = inv_size + fpga_inst.transistor_sizes[pmos_name] = inv_size + sys.stdout.flush() + return inv_tfall = float(inv_tfall_str) inv_trise = float(inv_trise_str) @@ -1115,10 +1127,20 @@ def erf(sp_path, if not circuit_element.startswith("inv_"): continue - # Get the tfall and trise delays for the inverter from the spice measurements - tfall = float(spice_meas["meas_" + circuit_element + "_tfall"][0]) - trise = float(spice_meas["meas_" + circuit_element + "_trise"][0]) - erf_error = abs((tfall - trise)/tfall) + # Get the tfall and trise delays for the inverter from the spice measurements. + # A "failed" value means HSPICE could not measure the .MEAS condition (signal did + # not cross supply_v/2 in time). Treat as a large delay so the ERF loop bails out + # via ERF_MAX_ITERATIONS rather than crashing in float(). + tfall_str = spice_meas["meas_" + circuit_element + "_tfall"][0] + trise_str = spice_meas["meas_" + circuit_element + "_trise"][0] + if tfall_str == "failed" or trise_str == "failed": + tfall = 1.0 + trise = 1.0 + erf_error = 1.0 + else: + tfall = float(tfall_str) + trise = float(trise_str) + erf_error = abs((tfall - trise)/tfall) if not fpga_inst.specs.use_finfet : nmos_nm_size = int(parameter_dict[circuit_element + "_nmos"][0]/1e-9) @@ -1223,14 +1245,18 @@ def run_combo(fpga_inst, sp_path, element_names, combo, erf_ratios, spice_interf parameter_dict[wire_name + "_cap"] = [rc_data[1]*1e-15] # Run HSPICE with the current transistor size - spice_meas = spice_interface.run(sp_path, parameter_dict) + spice_meas = spice_interface.run(sp_path, parameter_dict) + + # run returns a dict of measurements. For each key, we have a list of meaasurements. + # That;s why we add the [0] + # Extract total delay from measurements. A "failed" string means HSPICE could not + # measure the .MEAS condition; treat as 1.0 so the cost function deprioritizes this + # combo instead of crashing. + tfall_str = spice_meas["meas_total_tfall"][0] + trise_str = spice_meas["meas_total_trise"][0] + tfall = 1.0 if tfall_str == "failed" else float(tfall_str) + trise = 1.0 if trise_str == "failed" else float(trise_str) - # run returns a dict of measurements. For each key, we have a list of meaasurements. - # That;s why we add the [0] - # Extract total delay from measurements - tfall = float(spice_meas["meas_total_tfall"][0]) - trise = float(spice_meas["meas_total_trise"][0]) - return tfall, trise From f50dd442116a2b50cb50ef5ff459c842031c9a14 Mon Sep 17 00:00:00 2001 From: Stephen More Date: Thu, 21 May 2026 14:57:49 -0400 Subject: [PATCH 3/3] fixes bug in get_eval_area call in tran_sizing that causes coffe to crash during brams --- src/coffe/tran_sizing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coffe/tran_sizing.py b/src/coffe/tran_sizing.py index 4e5a2a3..4e69233 100644 --- a/src/coffe/tran_sizing.py +++ b/src/coffe/tran_sizing.py @@ -2672,7 +2672,7 @@ def size_bram_ckt( past_cost = current_cost current_cost = cost_lib.cost_function( - cost_lib.get_eval_area(fpga_inst, "global", fpga_inst.cb_mux, 1, 0), + cost_lib.get_eval_area(fpga_inst, "global", None, 1, 0), get_current_delay(fpga_inst, 1), area_opt_weight, delay_opt_weight