diff --git a/sim/src/main/cc/fasedtests/fasedtests_top.cc b/sim/src/main/cc/fasedtests/fasedtests_top.cc index a7a2e770..f360803d 100644 --- a/sim/src/main/cc/fasedtests/fasedtests_top.cc +++ b/sim/src/main/cc/fasedtests/fasedtests_top.cc @@ -117,7 +117,7 @@ int fasedtests_top_t::run() { fprintf(stderr, "Commencing simulation.\n"); record_start_times(); - while (!simulation_complete() && !has_timed_out()) { + while (!simulation_complete() && !finished_scheduled_tasks()) { run_scheduled_tasks(); step(get_largest_stepsize(), false); while(!done() && !simulation_complete()){ @@ -129,13 +129,19 @@ int fasedtests_top_t::run() { fprintf(stderr, "\nSimulation complete.\n"); uint64_t end_cycle = actual_tcycle(); + int exitcode = exit_code(); - if (exitcode) { - fprintf(stderr, "*** FAILED *** (code = %d) after %llu cycles\n", exitcode, end_cycle); - } else if (!simulation_complete() && has_timed_out()) { - fprintf(stderr, "*** FAILED *** (timeout) after %llu cycles\n", end_cycle); + + // If the simulator is idle and we've gotten here without any bridge + // indicating doneness, we've advanced to the +max_cycles limit in the fastest target clock domain. + bool max_cycles_timeout = !simulation_complete() && done() && finished_scheduled_tasks(); + + if (exitcode != 0) { + fprintf(stderr, "*** FAILED *** (code = %d) after %" PRIu64 " cycles\n", exitcode, get_end_tcycle()); + } else if (max_cycles_timeout) { + fprintf(stderr, "*** FAILED *** +max_cycles specified timeout after %" PRIu64 " cycles\n", get_end_tcycle()); } else { - fprintf(stderr, "*** PASSED *** after %llu cycles\n", end_cycle); + fprintf(stderr, "*** PASSED *** after %" PRIu64 " cycles\n", get_end_tcycle()); } print_simulation_performance_summary(); @@ -148,7 +154,7 @@ int fasedtests_top_t::run() { e->finish(); } this->host_finish(); - return (exitcode || has_timed_out()) ? EXIT_SUCCESS : EXIT_FAILURE; + return ((exitcode != 0) || max_cycles_timeout) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/sim/src/main/cc/firesim/firesim_top.cc b/sim/src/main/cc/firesim/firesim_top.cc index 8549fc50..df9de1a5 100644 --- a/sim/src/main/cc/firesim/firesim_top.cc +++ b/sim/src/main/cc/firesim/firesim_top.cc @@ -568,7 +568,7 @@ void firesim_top_t::run() { fprintf(stderr, "Commencing simulation.\n"); record_start_times(); - while (!simulation_complete() && !has_timed_out()) { + while (!simulation_complete() && !finished_scheduled_tasks()) { run_scheduled_tasks(); take_steps(get_largest_stepsize(), false); while(!done() && !simulation_complete()){ @@ -582,10 +582,15 @@ void firesim_top_t::run() { int firesim_top_t::teardown() { int exitcode = exit_code(); - if (exitcode) { + + // If the simulator is idle and we've gotten here without any bridge + // indicating doneness, we've advanced to the +max_cycles limit in the fastest target clock domain. + bool max_cycles_timeout = !simulation_complete() && done() && finished_scheduled_tasks(); + + if (exitcode != 0) { fprintf(stderr, "*** FAILED *** (code = %d) after %" PRIu64 " cycles\n", exitcode, get_end_tcycle()); - } else if (!simulation_complete() && has_timed_out()) { - fprintf(stderr, "*** FAILED *** (timeout) after %" PRIu64 " cycles\n", get_end_tcycle()); + } else if (max_cycles_timeout) { + fprintf(stderr, "*** FAILED *** +max_cycles specified timeout after %" PRIu64 " cycles\n", get_end_tcycle()); } else { fprintf(stderr, "*** PASSED *** after %" PRIu64 " cycles\n", get_end_tcycle()); } @@ -601,5 +606,5 @@ int firesim_top_t::teardown() { } this->host_finish(); - return (exitcode || has_timed_out()) ? EXIT_SUCCESS : EXIT_FAILURE; + return ((exitcode != 0) || max_cycles_timeout) ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/sim/src/main/cc/firesim/systematic_scheduler.h b/sim/src/main/cc/firesim/systematic_scheduler.h index 08028a66..35731b67 100644 --- a/sim/src/main/cc/firesim/systematic_scheduler.h +++ b/sim/src/main/cc/firesim/systematic_scheduler.h @@ -8,6 +8,15 @@ // Maximum step size in MIDAS's master is capped to width of the simulation bus constexpr uint64_t MAX_MIDAS_STEP = (1LL << sizeof(data_t) * 8) - 1; +// Schedules a series of tasks that must run a specific cycles on the FPGA, but +// may be associated with multiple bridges / touch non-bridge simulator +// collateral (e.g, reservoir sampling for strober.) +// +// This class does that by providing cycle deltas (i.e., a credit) that can be +// fed into some mechanism (e.g., peek/poke or a bridge) to advance the +// simulator to the time of the desired task. The onus is on the parent class / +// instantiator to ensure the simulator has advanced to the desired cycle +// before running the scheduled task. class systematic_scheduler_t { typedef std::function task_t; @@ -24,9 +33,10 @@ class systematic_scheduler_t // Assumption: The simulator is idle. (simif::done() == true) // Invokes all tasks that wish to be executed on our current target cycle void run_scheduled_tasks(); + // Unless overriden, assume the simulator will run (effectively) forever uint64_t max_cycles = -1; - // As above, assumes the simulator is idle. - bool has_timed_out() { return current_cycle == max_cycles; }; + // Returns true if no further tasks are scheduled before specified horizon (max_cycles). + bool finished_scheduled_tasks() { return current_cycle == max_cycles; }; private: uint64_t default_step_size = MAX_MIDAS_STEP;