vvp: handle tranif enable changes that result from island resolution.

The tran island resolution tests and caches the state of all branch
enable inputs before resolving the branch endpoint values. If a
branch enable is connected directly to a branch endpoint, we need
to update the cached stete and rerun the island resolution if any
enable state changed.

This fixes issue #1122.
This commit is contained in:
Martin Whitaker 2024-05-06 21:37:37 +01:00
parent 615a01c6cd
commit 3b61c0088d
1 changed files with 44 additions and 1 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008-2022 Stephen Williams (steve@icarus.com) * Copyright (c) 2008-2024 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -47,6 +47,7 @@ struct vvp_island_branch_tran : public vvp_island_branch {
unsigned width__, unsigned part__, unsigned width__, unsigned part__,
unsigned offset__, bool resistive__); unsigned offset__, bool resistive__);
void run_test_enabled(); void run_test_enabled();
bool rerun_test_enabled();
void run_resolution(); void run_resolution();
void run_output(); void run_output();
@ -91,6 +92,7 @@ void vvp_island_tran::run_island()
tmp->run_test_enabled(); tmp->run_test_enabled();
} }
rerun:
// Now resolve all the branches in the island. // Now resolve all the branches in the island.
for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) { for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur); vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur);
@ -104,6 +106,15 @@ void vvp_island_tran::run_island()
assert(tmp); assert(tmp);
tmp->run_output(); tmp->run_output();
} }
// Now check if the enable inputs have been affected by the resolution.
bool enable_changed = false;
for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
vvp_island_branch_tran*tmp = dynamic_cast<vvp_island_branch_tran*>(cur);
assert(tmp);
enable_changed |= tmp->rerun_test_enabled();
}
if (enable_changed) goto rerun;
} }
static void count_drivers_(vvp_branch_ptr_t cur, bool other_side_visited, static void count_drivers_(vvp_branch_ptr_t cur, bool other_side_visited,
@ -230,6 +241,38 @@ void vvp_island_branch_tran::run_test_enabled()
} }
} }
bool vvp_island_branch_tran::rerun_test_enabled()
{
vvp_island_port*ep = en? dynamic_cast<vvp_island_port*> (en->fun) : NULL;
if (ep == 0)
return false;
// We are only looking for changes resulting from running the island
// resolution. If the outvalue is nil, we know that the enable port
// is an .import, so won't be affected.
if (ep->outvalue.size() == 0)
return false;
vvp_bit4_t enable_val = ep->outvalue.value(0).value();
tran_state_t old_state = state;
switch (enable_val) {
case BIT4_0:
state = active_high ? tran_disabled : tran_enabled;
break;
case BIT4_1:
state = active_high ? tran_enabled : tran_disabled;
break;
default:
state = tran_unknown;
break;
}
return state != old_state;
}
// The IEEE standard does not specify the behaviour when a tranif control // The IEEE standard does not specify the behaviour when a tranif control
// input is 'x' or 'z'. We use the rules that are given for MOS switches. // input is 'x' or 'z'. We use the rules that are given for MOS switches.
inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a, inline vvp_vector8_t resolve_ambiguous(const vvp_vector8_t&a,