Index: sid/component/gdb/gdb.cxx =================================================================== RCS file: /cvs/src/src/sid/component/gdb/gdb.cxx,v retrieving revision 1.17 diff -c -p -r1.17 gdb.cxx *** sid/component/gdb/gdb.cxx 1 Mar 2006 21:07:00 -0000 1.17 --- sid/component/gdb/gdb.cxx 15 Sep 2006 20:27:52 -0000 *************** *** 1,6 **** // gdb.cxx - GDB stub implementation. -*- C++ -*- ! // Copyright (C) 1999-2002, 2004, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // gdb.cxx - GDB stub implementation. -*- C++ -*- ! // Copyright (C) 1999-2002, 2004, 2005, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** process_detach_hook (struct gdbserv *gdb *** 232,237 **** --- 232,244 ---- return g->process_detach (); } + extern "C" int + set_exec_direction_hook (struct gdbserv *gdbserv, const char *direction) + { + gdb* g = static_cast (gdbserv_target_data (gdbserv)); + return g->set_exec_direction (direction); + } + *************** gdb::gdbsid_target_attach (struct gdbser *** 278,283 **** --- 285,291 ---- gdbtarget->rangestep_program = rangestep_program_hook; gdbtarget->sigkill_program = sigkill_program_hook; gdbtarget->continue_program = continue_program_hook; + gdbtarget->set_exec_direction = set_exec_direction_hook; gdbtarget->remove_breakpoint = remove_breakpoint_hook; gdbtarget->set_breakpoint = set_breakpoint_hook; gdbtarget->detach = process_detach_hook; *************** gdb::add_sw_breakpoint (host_int_8 addre *** 1329,1334 **** --- 1337,1359 ---- } + int + gdb::set_exec_direction (const char *direction) + { + if (trace_gdbsid) + cerr << "set_exec_direction " << endl; + + assert (cpu != 0); + component::status s = cpu->set_attribute_value ("exec-direction", direction); + if (s != component::ok) + { + cerr << "Cannot set exec-direction attribute in cpu: status " << (int)s << endl; + } + + return 0; + } + + bool gdb::add_hw_watchpoint (host_int_8 address, host_int_4 length) { Index: sid/component/gdb/gdb.h =================================================================== RCS file: /cvs/src/src/sid/component/gdb/gdb.h,v retrieving revision 1.11 diff -c -p -r1.11 gdb.h *** sid/component/gdb/gdb.h 14 Nov 2005 20:04:53 -0000 1.11 --- sid/component/gdb/gdb.h 15 Sep 2006 20:27:52 -0000 *************** *** 1,6 **** // gdb.h - description. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2001, 2002, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // gdb.h - description. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** public: *** 216,221 **** --- 216,222 ---- int Z_breakpoint_ok_p (unsigned long type, struct gdbserv_reg *addr, struct gdbserv_reg *len); int remove_breakpoint (unsigned long type, struct gdbserv_reg *addr, struct gdbserv_reg *len); int set_breakpoint (unsigned long type, struct gdbserv_reg *addr, struct gdbserv_reg *len); + int set_exec_direction (const char* direction); void process_detach (); }; Index: sid/component/gdb/gdbserv-state.c =================================================================== RCS file: /cvs/src/src/sid/component/gdb/gdbserv-state.c,v retrieving revision 1.3 diff -c -p -r1.3 gdbserv-state.c *** sid/component/gdb/gdbserv-state.c 12 Feb 2005 16:25:46 -0000 1.3 --- sid/component/gdb/gdbserv-state.c 15 Sep 2006 20:27:52 -0000 *************** *** 1,7 **** /* * gdbserv-state.c -- part of GDB remote server * ! * Copyright (C) 2000, 2002 Red Hat. * This file is part of SID and is licensed under the GPL. * See the file COPYING.SID for conditions for redistribution. */ --- 1,7 ---- /* * gdbserv-state.c -- part of GDB remote server * ! * Copyright (C) 2000, 2002, 2006 Red Hat. * This file is part of SID and is licensed under the GPL. * See the file COPYING.SID for conditions for redistribution. */ *************** gdbserv_fromclient_data (struct gdbserv *** 123,134 **** --- 123,151 ---- void gdbserv_data_packet (struct gdbserv *gdbserv) { + const char *exec_direction = "forward"; char packet_type = gdbserv_input_char (gdbserv); if (gdbserv_state_trace) fprintf (gdbserv_state_trace, "\n", packet_type); /* NB: default is for this to send an empty packet */ + /* Check for a 'b' (backward) prefix for S, s, C and c. This indicates that + the direction of execution is to be backward. */ + if (packet_type == 'b') + { + char next = gdbserv_input_peek (gdbserv); + switch (next) + { + case 'S': case 's': case 'C': case 'c': + exec_direction = "backward"; + packet_type = gdbserv_input_char (gdbserv); + break; + default: + break; + } + } + switch (packet_type) { *************** gdbserv_data_packet (struct gdbserv *gdb *** 461,467 **** gdbserv->target->sigkill_program (gdbserv); return; } ! /* Set machine state to force a single step. */ if (packet_type == 's' || packet_type == 'S') { --- 478,487 ---- gdbserv->target->sigkill_program (gdbserv); return; } ! ! /* Set the direction. */ ! gdbserv->target->set_exec_direction (gdbserv, exec_direction); ! /* Set machine state to force a single step. */ if (packet_type == 's' || packet_type == 'S') { Index: sid/component/gdb/gdbserv-target.h =================================================================== RCS file: /cvs/src/src/sid/component/gdb/gdbserv-target.h,v retrieving revision 1.2 diff -c -p -r1.2 gdbserv-target.h *** sid/component/gdb/gdbserv-target.h 12 Feb 2002 21:58:58 -0000 1.2 --- sid/component/gdb/gdbserv-target.h 15 Sep 2006 20:27:52 -0000 *************** *** 1,7 **** /* * gdbserv-target.h -- part of GDB remote server. * ! * Copyright (C) 2000, 2002 Red Hat. * This file is part of SID and is licensed under the GPL. * See the file COPYING.SID for conditions for redistribution. */ --- 1,7 ---- /* * gdbserv-target.h -- part of GDB remote server. * ! * Copyright (C) 2000, 2002, 2006 Red Hat. * This file is part of SID and is licensed under the GPL. * See the file COPYING.SID for conditions for redistribution. */ *************** struct gdbserv_target { *** 125,130 **** --- 125,131 ---- void (*cyclestep_program) (struct gdbserv *); void (*sigkill_program) (struct gdbserv *); int (*continue_program) (struct gdbserv *); + int (*set_exec_direction) (struct gdbserv *, const char *direction); #endif /* Breakpoint methods */ Index: sid/component/memory/generic.cxx =================================================================== RCS file: /cvs/src/src/sid/component/memory/generic.cxx,v retrieving revision 1.8 diff -c -p -r1.8 generic.cxx *** sid/component/memory/generic.cxx 10 Jun 2003 18:27:10 -0000 1.8 --- sid/component/memory/generic.cxx 15 Sep 2006 20:27:52 -0000 *************** *** 1,6 **** // generic.cxx - a class of generic memories. -*- C++ -*- ! // Copyright (C) 1999-2001,2003 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // generic.cxx - a class of generic memories. -*- C++ -*- ! // Copyright (C) 1999-2001, 2003, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** generic_memory::generic_memory() throw ( *** 54,59 **** --- 54,61 ---- imagestore_pin (this, & generic_memory::imagestore_handler), imagemmap_pin (this, & generic_memory::imagemmap_handler), imagemsync_pin (this, & generic_memory::imagemsync_handler), + sched (0), + change_log (0x60000), read_latency (0), write_latency (0) { *************** generic_memory::generic_memory() throw ( *** 86,91 **** --- 88,95 ---- add_attribute_virtual ("state-snapshot", this, & generic_memory::save_state, & generic_memory::restore_state); + + add_uni_relation ("sim-sched", & sched); } *************** generic_memory::imagemmap_handler (host_ *** 263,271 **** --- 267,341 ---- } + // Record a change in this memory region, so that it may be restored later. + void + generic_memory::record_update (host_int_4 address, const void *bytes, unsigned width) + { + // This function is only used during reverse debugging at the moment. + assert (reversible_p); + + // Make sure we can get the current time + if (! sched) + return; + string tick_attr = sched->attribute_value ("time"); + host_int_4 tick; + component::status s = parse_attribute (tick_attr, tick); + if (s != component::ok) + return; + + // Make sure that the time is not 0. + if (tick == 0) + return; + + // Assemble the change log entry + char change[4 + 8]; // max buffer size + *(sid::host_int_4 *)change = address; + memcpy (change + 4, this->buffer + address, width); + + // The change log record contains the current tick, the address and the + // original data. + change_log.push (& tick, sizeof (tick)); + change_log.add (change, 4 + width); + change_log.finish (); + } + // Restore this mrmory region to the state it was at the given time (tick). + void + generic_memory::restore_state_to_time (sid::host_int_4 tick) + { + // Call up to the base class. + reversible_component::restore_state_to_time (tick); + // Undo all updates back to the given time. + while (! change_log.empty ()) + { + sid::host_int_4 length; + const unsigned char *record = (const unsigned char *)change_log.top (length); + + // The time (tick) of the change is the first item in the record. + // If this record occurred previous to our target time, then we are done. + sid::host_int_4 new_tick = *(sid::host_int_4*)record; + if (new_tick < tick) + break; + + record += sizeof (new_tick); + length -= sizeof (new_tick); + + // The next item in the record is the address which was changed. + sid::host_int_4 address = *(sid::host_int_4*)record; + record += sizeof (address); + length -= sizeof (address); + + // The remainder of the record contains the original data. + // Restore the change. + memcpy (this->buffer + address, record, length); + + // Done with this record. + change_log.pop (); + } + } + // ---------------------------------------------------------------------------- Index: sid/component/memory/generic.h =================================================================== RCS file: /cvs/src/src/sid/component/memory/generic.h,v retrieving revision 1.5 diff -c -p -r1.5 generic.h *** sid/component/memory/generic.h 3 Aug 2001 06:02:46 -0000 1.5 --- sid/component/memory/generic.h 15 Sep 2006 20:27:52 -0000 *************** *** 1,6 **** // generic.h - Header for the generic_memory class. -*- C++ -*- ! // Copyright (C) 1999-2001 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // generic.h - Header for the generic_memory class. -*- C++ -*- ! // Copyright (C) 1999-2001, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** using sid::big_int_8; *** 50,57 **** using sidutil::fixed_pin_map_component; using sidutil::no_accessor_component; using sidutil::fixed_attribute_map_component; ! using sidutil::no_relation_component; using sidutil::fixed_bus_map_component; using sidutil::std_error_string; using sidutil::callback_pin; using sidutil::output_pin; --- 50,58 ---- using sidutil::fixed_pin_map_component; using sidutil::no_accessor_component; using sidutil::fixed_attribute_map_component; ! using sidutil::fixed_relation_map_component; using sidutil::fixed_bus_map_component; + using sidutil::reversible_component; using sidutil::std_error_string; using sidutil::callback_pin; using sidutil::output_pin; *************** using sidutil::output_pin; *** 61,71 **** class generic_memory: public virtual component, ! protected fixed_pin_map_component, protected no_accessor_component, ! protected fixed_attribute_map_component, ! protected no_relation_component, ! protected fixed_bus_map_component { public: generic_memory() throw (bad_alloc); --- 62,73 ---- class generic_memory: public virtual component, ! protected virtual fixed_pin_map_component, protected no_accessor_component, ! protected virtual fixed_attribute_map_component, ! protected fixed_relation_map_component, ! protected fixed_bus_map_component, ! protected reversible_component { public: generic_memory() throw (bad_alloc); *************** protected: *** 94,99 **** --- 96,108 ---- host_int_4 max_buffer_length; bool attempt_resize (host_int_4 new_length) throw(); + protected: + // Change logging for the purpose of reverse simulation. + component *sched; + sidutil::change_log change_log; + void record_update (host_int_4 address, const void *bytes, unsigned width); + virtual void restore_state_to_time (sid::host_int_4 tick); + private: string get_size_attr (); component::status set_size_attr (const string& s); *************** generic_read_write_bus::write_any(host_i *** 211,216 **** --- 220,227 ---- if (LIKELY((address >= 0) && ((address+width) <= target->buffer_length))) { typename DataType::value_type mem_image = data.target_memory_value(); + if (UNLIKELY (target->reversible_p)) + target->record_update (address, & mem_image, width); memcpy (& target->buffer[address], & mem_image, width); bus::status st (bus::ok); st.latency = target->write_latency; Index: sid/component/sched/compSched.cxx =================================================================== RCS file: /cvs/src/src/sid/component/sched/compSched.cxx,v retrieving revision 1.14 diff -c -p -r1.14 compSched.cxx *** sid/component/sched/compSched.cxx 1 Mar 2006 21:07:02 -0000 1.14 --- sid/component/sched/compSched.cxx 15 Sep 2006 20:27:52 -0000 *************** *** 1,6 **** // compSched.cxx - the scheduler component. -*- C++ -*- ! // Copyright (C) 1999-2003, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. #include "config.h" --- 1,6 ---- // compSched.cxx - the scheduler component. -*- C++ -*- ! // Copyright (C) 1999-2003, 2005, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. #include "config.h" *************** operator >> (istream& i, exact_host_time *** 639,645 **** this->refill_regular_events_table(); // deliver event assert (victim); ! victim->drive (0); } --- 639,645 ---- this->refill_regular_events_table(); // deliver event assert (victim); ! victim->drive (rnext->when); } *************** operator >> (istream& i, exact_host_time *** 656,662 **** this->irregular_events.pop_back(); // deliver event assert (victim); ! victim->drive (0); } --- 656,662 ---- this->irregular_events.pop_back(); // deliver event assert (victim); ! victim->drive (irnext->when); } *************** operator >> (istream& i, exact_host_time *** 721,727 **** evpair = this->next_event (); } while ((evpair.first != 0) // still an event && (evpair.first->when <= now) // still due ! && (due_count < due_limit)); // not too many iterations // cout << "sid-sched: delivered " << due_count << " due/overdue events." << endl; --- 721,728 ---- evpair = this->next_event (); } while ((evpair.first != 0) // still an event && (evpair.first->when <= now) // still due ! && (due_count < due_limit) // not too many iterations ! && ! this->yield_step_loop_p); // cout << "sid-sched: delivered " << due_count << " due/overdue events." << endl; *************** operator >> (istream& i, exact_host_time *** 871,876 **** --- 872,886 ---- } + // Cancel all pending events. + void + cancel_all () + { + this->irregular_events.clear (); + this->regular_table_iter = this->regular_events_table.end(); + this->yield_step_loop_p = true; + } + // Add a pin<->string mapping void clear_pin_mappings () *************** class scheduler_component: public schedu *** 1357,1362 **** --- 1367,1373 ---- output_pin time_low_pin; output_pin time_high_pin; output_pin active_pin; + output_pin time_set_pin; public: *************** private: *** 1379,1391 **** tick_t then; component::status s = parse_attribute(t, then); if (UNLIKELY(s != component::ok)) return s; ! this->sched.set_now (then); tick_t now; this->sched.get_now (now); ! if (then != now) return component::bad_value; ! else ! return component::ok; } protected: --- 1390,1403 ---- tick_t then; component::status s = parse_attribute(t, then); if (UNLIKELY(s != component::ok)) return s; ! this->sched.set_now (then - 1); tick_t now; this->sched.get_now (now); ! if (then - 1 != now) return component::bad_value; ! this->sched.cancel_all (); ! time_set_pin.drive (then); ! return component::ok; } protected: *************** scheduler_component::schedule *** 1486,1491 **** --- 1498,1504 ---- add_pin ("time-low", & this->time_low_pin); add_pin ("yield", & this->yield_pin); add_pin ("active", & this->active_pin); + add_pin ("time-set", & this->time_set_pin); add_attribute ("yield", & this->yield_pin, "pin"); add_attribute ("enable-threshold", & this->enable_threshold, "setting"); add_attribute ("enabled?", & this->enable_p, "setting"); Index: sid/include/sidattrutil.h =================================================================== RCS file: /cvs/src/src/sid/include/sidattrutil.h,v retrieving revision 1.9 diff -c -p -r1.9 sidattrutil.h *** sid/include/sidattrutil.h 27 Mar 2006 20:30:06 -0000 1.9 --- sid/include/sidattrutil.h 15 Sep 2006 20:27:53 -0000 *************** *** 2,8 **** // mappings between application objects and their string // representations. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2003, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 2,8 ---- // mappings between application objects and their string // representations. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2003, 2005, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** protected: *** 1127,1132 **** --- 1127,1156 ---- } }; + + // A mix-in for components which need to save and restore state + // at given time indices. + class reversible_component : + public virtual fixed_pin_map_component, + public virtual fixed_attribute_map_component + { + public: + reversible_component () : + reversible_p (false), + restore_to_time_pin (this, & reversible_component::restore_state_to_time) + { + add_pin ("restore-to-time!", & this->restore_to_time_pin); + add_attribute ("reversible?", & reversible_p, "setting"); + } + + ~reversible_component () throw() {} + + protected: + bool reversible_p; + + virtual void restore_state_to_time (sid::host_int_4) {} + callback_pin restore_to_time_pin; + }; } #endif // SIDATTRUTIL_H Index: sid/include/sidcpuutil.h =================================================================== RCS file: /cvs/src/src/sid/include/sidcpuutil.h,v retrieving revision 1.38 diff -c -p -r1.38 sidcpuutil.h *** sid/include/sidcpuutil.h 26 Jun 2006 21:04:00 -0000 1.38 --- sid/include/sidcpuutil.h 15 Sep 2006 20:27:53 -0000 *************** *** 16,21 **** --- 16,22 ---- #include using std::string; + using std::pair; namespace sidutil { *************** namespace sidutil *** 106,112 **** protected virtual fixed_attribute_map_component, protected virtual fixed_relation_map_component, protected virtual fixed_bus_map_component, ! protected virtual configurable_component { // custom memory allocators for poisioning freshly-allocated memory public: --- 107,114 ---- protected virtual fixed_attribute_map_component, protected virtual fixed_relation_map_component, protected virtual fixed_bus_map_component, ! protected virtual configurable_component, ! protected virtual reversible_component { // custom memory allocators for poisioning freshly-allocated memory public: *************** namespace sidutil *** 308,319 **** bool enable_step_trap_p; cpu_trace_stream trace_stream; ! virtual void step_pin_handler (sid::host_int_4) { recursion_record limit (& this->step_limit); if (UNLIKELY(! limit.ok())) return; this->yield_p = false; // Check for triggerpoints due right now; may set yield_p! this->triggerpoint_manager.check_and_dispatch (); --- 310,334 ---- bool enable_step_trap_p; cpu_trace_stream trace_stream; ! virtual void step_pin_handler (sid::host_int_4 tick) { recursion_record limit (& this->step_limit); if (UNLIKELY(! limit.ok())) return; this->yield_p = false; + this->current_tick = tick; + + // Executing backward? + if (UNLIKELY (exec_direction == "backward")) + { + step_backward (); + this->stepped (1); + return; + } + + this->current_step_insn_count = 0; + if (UNLIKELY (reversible_p)) + this->init_change_logging (); // Check for triggerpoints due right now; may set yield_p! this->triggerpoint_manager.check_and_dispatch (); *************** namespace sidutil *** 339,346 **** --- 354,428 ---- insn_cycles >= max_num_cycles ? max_num_cycles : insn_cycles; + if (UNLIKELY (reversible_p)) + this->finish_change_logging (); this->stepped (num_cycles); } + + virtual void step_backward () + { + // Make sure the infrastructure for reverse execution is in place. + if (UNLIKELY (! sim_sched || ! reversible_p)) + { + std::cerr << "unable to execute in reverse" << endl; + this->signal_trap (cpu_trap_breakpoint, 0); + return; + } + + // Check whether we're at the start of the program. + if (UNLIKELY (change_log_end <= change_log_begin)) + { + // We're at the start of the program. See if there are previous + // instances to step backward into. + if (change_log_boundaries.empty ()) + { + std::cerr << "No previous program instances to return to" << endl; + this->signal_trap (cpu_trap_breakpoint, 0); + return; + } + std::cerr << "Stepping back into the previous program instance" << endl; + + // Switch to the previous program instance. + change_log_begin = change_log_boundaries.back (); + change_log_boundaries.pop_back (); + assert (change_log_begin < change_log_end); + } + + // Unwind the change log until a triggerpoint is reached. + // + bool single_stepping = this->enable_step_trap_p; + while (change_log_end > change_log_begin) + { + // Restore the state to the previous tick. + --this->current_tick; + restore_state_to_time (this->current_tick); + + // We've restored all the changes which take us back to the start of the + // previous insn. Now notify the scheduler to reset the rest of + // the system to this time. + if (LIKELY (sim_sched)) + sim_sched->set_attribute_value ("time", make_numeric_attribute (this->current_tick)); + + // Check for single stepping. + if (single_stepping) + { + this->signal_trap (sidutil::cpu_trap_stepped); + break; + } + + // Check for triggerpoints due right now; may set yield_p! + this->triggerpoint_manager.check_and_dispatch (); + if (this->yield_p) + break; + } + + // Let GDB know if we run out of state to reverse. + if (UNLIKELY (change_log_end <= change_log_begin)) + { + std::cerr << "Program start reached while executing in reverse" << endl; + this->signal_trap (cpu_trap_breakpoint, 0); + } + } void yield () { this->yield_p = true; *************** namespace sidutil *** 504,510 **** private: callback_pin reset_pin; virtual void reset () = 0; ! void reset_pin_handler(sid::host_int_4 v) { this->reset (); this->stepped(1); } // Flush internal abstract icache (if any) private: --- 586,603 ---- private: callback_pin reset_pin; virtual void reset () = 0; ! void reset_pin_handler(sid::host_int_4 v) ! { ! // If there's a change log, then start a new one. ! if (change_log_end != 0) ! { ! change_log_boundaries.push_back (change_log_begin); ! change_log_begin = change_log_end; ! } ! exec_direction = "forward"; ! this->reset (); ! this->stepped(1); ! } // Flush internal abstract icache (if any) private: *************** namespace sidutil *** 719,724 **** --- 812,893 ---- } } + // Reversible implementation + protected: + sidutil::change_log change_log; + unsigned change_log_begin; + unsigned change_log_end; + vector change_log_boundaries; + std::string change_string; + string exec_direction; + component *sim_sched; + sid::host_int_4 current_tick; + sid::host_int_4 last_tick; + + virtual void init_change_logging () {} + virtual void finish_change_logging () {} + + // Log any changes since the last change was logged. Target specific + // changes are logged in change_log.finish (). + virtual void log_change (const void* change, sid::host_int_4 length) + { + assert (reversible_p); + change_log.push (& current_tick, sizeof (current_tick)); + change_log.add (change, length); + change_log.finish (); + ++change_log_end; + } + + // Restore the state represented by the given change log record. + virtual void restore_change (const char* record, sid::host_int_4 length) + { + } + + // Restore our state to what it was at the given time. + virtual void restore_state_to_time (sid::host_int_4 tick) + { + // Call up to the base class. + reversible_component::restore_state_to_time (tick); + + // Nothing to restore? + if (UNLIKELY (change_log_end == 0)) + return; + + // Rewind the change log to the given time. + unsigned found = change_log_end; + while (change_log_end >= 1) + { + // Obtain the most recent change log record. + sid::host_int_4 length; + const char *record = (const char *)change_log.top (length); + + // The first item in the record is the time (tick) of the change. + // If it's before our target time, then we're done. + sid::host_int_4 new_tick = *(sid::host_int_4*)record; + if (new_tick < tick) + break; + + record += sizeof (new_tick); + length -= sizeof (new_tick); + + // Restore the state represented by the record. + restore_change (record, length); + + // We're done with this record. + change_log.pop (); + --change_log_end; + + // Adjust program instance boundaries, if necessary. + if (change_log_end < change_log_begin) + { + assert (! change_log_boundaries.empty ()); + change_log_begin = change_log_boundaries.back (); + change_log_boundaries.pop_back (); + assert (change_log_end >= change_log_begin); + } + } + } + virtual component::status dynamic_config(const string& spec) { // Call up to the base class *************** public: *** 930,936 **** gprof_unconfigured_p (false), gprof_prev_cycle (0), core_probe (0), ! main (0) { // buses this->data_bus = 0; --- 1099,1112 ---- gprof_unconfigured_p (false), gprof_prev_cycle (0), core_probe (0), ! main (0), ! change_log (), ! change_log_begin (0), ! change_log_end (0), ! change_log_boundaries (), ! last_tick (~(sid::host_int_4)0), ! exec_direction ("forward"), ! sim_sched (0) { // buses this->data_bus = 0; *************** public: *** 997,1002 **** --- 1173,1180 ---- add_attribute_notify ("final-insn-count?", & this->final_insn_count_p, this, & basic_cpu::update_final_insn_count_p, "setting"); + add_attribute ("exec-direction", &exec_direction, "setting"); + add_uni_relation("sim-sched", &this->sim_sched); // For dynamic configuration add_uni_relation("gprof", &this->gprof); Index: sid/include/sidmiscutil.h =================================================================== RCS file: /cvs/src/src/sid/include/sidmiscutil.h,v retrieving revision 1.8 diff -c -p -r1.8 sidmiscutil.h *** sid/include/sidmiscutil.h 17 Dec 2003 19:51:02 -0000 1.8 --- sid/include/sidmiscutil.h 15 Sep 2006 20:27:53 -0000 *************** *** 1,6 **** // sidmiscutil.h - Useful utility classes. -*- C++ -*- ! // Copyright (C) 1999-2003 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // sidmiscutil.h - Useful utility classes. -*- C++ -*- ! // Copyright (C) 1999-2003, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** namespace sidutil *** 531,536 **** --- 531,614 ---- } }; + // This class is intended for the implementation of change logging and + // change reversing. It is optimized for a potentially large number of + // elements and for growth, shrinkage and access as a LIFO stack. It is + // also optimized for growing again after shrinking. + class change_log + { + public: + change_log (sid::host_int_4 g = 0x100000) : + growth_rate (g), + buffer (0), + buf_index (0), + buf_size (0), + current_length (0) + {} + ~change_log () + { + if (buffer) + delete buffer; + } + + // Begin a new record and add the given data. + void push (const void *data, sid::host_int_4 length) + { + current_length = 0; + add (data, length); + } + + // Add the given data to the current record. + void add (const void *data, sid::host_int_4 length) + { + if (buf_index + length > buf_size) + { + buf_size += growth_rate * length; + unsigned char* new_buf = new unsigned char[buf_size]; + if (buffer) + { + memcpy (new_buf, buffer, buf_index); + delete buffer; + } + buffer = new_buf; + } + + memcpy (buffer + buf_index, data, length); + buf_index += length; + current_length += length; + } + + // Complete the current record by writing its length. + void finish () + { + unsigned char l = current_length; + add (& l, 1); + } + + // Remove the last record. + void pop () + { + unsigned len = buffer[--buf_index]; + buf_index -= len; + } + + // Return a pointer to the last record. + const void *top (sid::host_int_4 &length) const + { + length = buffer[buf_index - 1]; + return buffer + buf_index - length - 1; + } + + // Is the change log emtpy? + bool empty () const { return buf_index <= 0; } + + private: + sid::host_int_4 growth_rate; + unsigned char* buffer; + sid::host_int_4 buf_index; + sid::host_int_4 buf_size; + unsigned char current_length; + }; } #endif // SIDMISCUTIL_H Index: sid/main/dynamic/commonCfg.cxx =================================================================== RCS file: /cvs/src/src/sid/main/dynamic/commonCfg.cxx,v retrieving revision 1.16 diff -c -p -r1.16 commonCfg.cxx *** sid/main/dynamic/commonCfg.cxx 14 Jul 2006 19:45:51 -0000 1.16 --- sid/main/dynamic/commonCfg.cxx 15 Sep 2006 20:27:53 -0000 *************** CpuCfg::CpuCfg (const string name, *** 346,351 **** --- 346,352 ---- sess->sim_sched->add_subscription (this, "step!", "step-cycles", "time-query", "time-high", "time-low"); + relate (this, "sim-sched", sess->sim_sched); } *************** SessionCfg::SessionCfg (const string nam *** 581,586 **** --- 582,588 ---- tcl_bridge (NULL), loader (NULL), verbose (false), + reversible_p (false), use_stdio (true), need_gprof (false), need_core_probe (false), *************** void SessionCfg::write_load (Writer &w) *** 659,664 **** --- 661,678 ---- host_sched->set_time (n, 150); use_stdio = false; } + + // Setup all memory regions to be reversible, if specified. + if (reversible_p) + for (vector::iterator it = memory.begin (); + it != memory.end (); + ++it) + { + set (*it, "reversible?", "true"); + relate (*it, "sim-sched", sim_sched); + conn_pin (sim_sched, "time-set", *it, "restore-to-time!"); + } + AggregateCfg::write_load (w); } *************** void BoardCfg::write_config (Writer &w) *** 1360,1365 **** --- 1374,1386 ---- PinConnection (cpu, "trap-code", gdb, "trap-code").write_to(w); } } + + // Set up the cpu to be reversible, if requested. + if (sess->reversible_p) + { + Setting (cpu, "reversible?", "true").write_to (w); + PinConnection (sess->sim_sched, "time-set", cpu, "restore-to-time!").write_to(w); + } } void BoardCfg::set_gprof (const string filename, gprof_type type, int interval) Index: sid/main/dynamic/commonCfg.h =================================================================== RCS file: /cvs/src/src/sid/main/dynamic/commonCfg.h,v retrieving revision 1.10 diff -c -p -r1.10 commonCfg.h *** sid/main/dynamic/commonCfg.h 11 May 2006 20:27:02 -0000 1.10 --- sid/main/dynamic/commonCfg.h 15 Sep 2006 20:27:53 -0000 *************** struct SessionCfg : *** 233,238 **** --- 233,239 ---- void use_tksm(); void use_tcl_bridge(); void use_no_stdio (); + void set_reversible () { reversible_p = true; } virtual void set_loader (LoaderCfg *l); LoaderCfg *get_loader () const { return loader; } AtomicCfg *audio; *************** struct SessionCfg : *** 241,246 **** --- 242,248 ---- AtomicCfg *tcl_bridge; bool verbose; bool use_stdio; + bool reversible_p; bool need_gprof; bool need_core_probe; void add_ulog_file (const string filename); *************** struct SessionCfg : *** 248,253 **** --- 250,257 ---- map ulog_map; void add_gdb () { ++gdb_count; } void add_board (ComponentCfg *b) { ++board_count; add_child (b); } + void add_memory (MemCfg *mem) { memory.push_back (mem); } + vector memory; virtual void write_config (Writer &w); // Support for dynamic configuration profiles vector wrapped_components; Index: sid/main/dynamic/mainDynamic.cxx =================================================================== RCS file: /cvs/src/src/sid/main/dynamic/mainDynamic.cxx,v retrieving revision 1.8 diff -c -p -r1.8 mainDynamic.cxx *** sid/main/dynamic/mainDynamic.cxx 23 Aug 2005 21:09:48 -0000 1.8 --- sid/main/dynamic/mainDynamic.cxx 15 Sep 2006 20:27:53 -0000 *************** *** 1,6 **** // mainDynamic.cxx - high-tech mainline. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. --- 1,6 ---- // mainDynamic.cxx - high-tech mainline. -*- C++ -*- ! // Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. *************** usage () *** 73,78 **** --- 73,79 ---- cout << "--profile-config=NAME,OPTIONS" << endl; cout << " Specify options for a named profiling configuration" << endl; cout << "--rc Pass stop code as simulator exit rc" << endl; + cout << "--reversible Configure for reversible simulation" << endl; cout << "--save-temps=FILE Write config to FILE, '-' for stdout." << endl; cout << "--wrap=COMPONENT Turn on SID API tracing for COMPONENT" << endl; cout << "--verbose Turn on run-time verbosity settings" << endl; *************** void try_add_memory (const string memspe *** 412,417 **** --- 413,420 ---- if (! (mmap_p || read_only_p)) sess->shutdown_seq->add_output (6, mem, "image-store"); } + + sess->add_memory (mem); } *************** main(int argc, char* argv[]) *** 549,555 **** enum option_num { opt_help, opt_version, opt_save_temps, opt_wrap, opt_verbose, opt_tksched, opt_enable_warnings, opt_persistent, opt_profile_config, ! opt_rc, opt_no_run, opt_sidrtc, opt_sidcodec, opt_tksm, opt_board, opt_cpu, opt_gdb, opt_gloss, opt_engine, opt_insn_count, opt_load, opt_icache, opt_dcache, opt_memory_region, opt_profile_func, --- 552,558 ---- enum option_num { opt_help, opt_version, opt_save_temps, opt_wrap, opt_verbose, opt_tksched, opt_enable_warnings, opt_persistent, opt_profile_config, ! opt_rc, opt_reversible, opt_no_run, opt_sidrtc, opt_sidcodec, opt_tksm, opt_board, opt_cpu, opt_gdb, opt_gloss, opt_engine, opt_insn_count, opt_load, opt_icache, opt_dcache, opt_memory_region, opt_profile_func, *************** main(int argc, char* argv[]) *** 578,583 **** --- 581,587 ---- {"persistent", no_argument, & curr_opt, opt_persistent }, {"profile-config", required_argument, &curr_opt, opt_profile_config }, {"rc", no_argument, & curr_opt, opt_rc }, + {"reversible", no_argument, & curr_opt, opt_reversible }, {"tksm", no_argument, & curr_opt, opt_tksm }, *************** main(int argc, char* argv[]) *** 880,885 **** --- 884,907 ---- rc_p = true; break; + case opt_reversible: + if (sess) + { + sess->set_reversible (); + // --insn-count must be 1 for this to work correctly + if (curr_board) + { + curr_board->set_step_insn_count("1"); + board_start_config += " --insn-count=1"; + } + else + { + defaults.step_insn_count = "1"; + defaults.start_config += " --insn-count=1"; + } + } + break; + case opt_sidrtc: option_requires_board (curr_board, "sidrtc"); curr_board->add_sidrtc (optaddr("sidrtc"));