Hi,
The attached patches implement
1) Infrastructure for reverse execution of in SID
2) Target specific implementation for xstormy16
This work is intended to be used in conjunction with Michael
Snyder's
work on reverse debugging in GDB, but I suppose that the
idea of
executing in reverse need not necessarily be restricted only
to this
purpose.
I'm submitting the general infrastructure work for approval
to commit.
The xstormy16 specific implementation was done mainly as an
example, and
perhaps should also be committed.
Here is an overview of the changes and how they work:
o The changes the the scheduling components are mainly to
have them
drive the value of 'now' for each scheduled event.
Currently they drive
the value zero which is not used on the receiving end. This
provides a
mechanism for a scheduled component to know what 'time'
each scheduled
event occurs. Components, like memory, which are not
scheduled, but
which need to know at what 'time' an event occurred can
query the
scheduler's time attribute to obtain the same information.
The
scheduler's set_time method has also been updated so that
it cancels all
pending events. This change was probably already necessary,
but the need
was exposed during testing of this feature.
o A new component class mix-in called reversible_component
has been
created to consolidate the common needs of a component which
may have to
step back in 'time'. The main features are a reversible?
attribute which
tells the component that it should be keeping track of
events and a
restore-to-time! pin which tells the component to restore
it's state to
a given 'time'.
o A new utility class called change_log has been added to
aid those
components which choose to implement this using change
logging techniques.
o The basic_cpu class has been given specific knowledge of
what it means
to execute in reverse. This is controlled by it's new
exec-direction
attribute which can be set to "forward" or
"backward". This attribute is
checked when the step-insns pin is driven. If the direction
is forward,
then it's business as usual. If it's backward, then the
cpu does what is
necessary to step backward and then resets the scheduler to
that 'time'.
The scheduler in turn drives its time-set pin to notify
other components
in the system to restore themselves to that 'time'. Note
that reverse
execution need not be one insn at a time. I did this for the
xstormy16
example so that stepi would work in reverse with gdb. Note
that in the
xstormy16 example, breakpoints and watchpoints are also
supported while
executing in reverse.
The idea is that components in the system which have state
implement
some method of restoring their state to what it was at a
given 'time'.
Whatever makes the most sense for each particular component.
The cpu is
an obvious example as is memory. More complex systems may
have other
components with this requirement. For the xstormy16, cpu and
memory are
the only components requiring this capability.
In particular, the xstormy16 cpu component needed only to
track changes
in the pc and the gr registers. Using specific knowlege of
the kinds of
changes that are possible to the pc, in particular I was
able to
implement a change logging system that uses only 1 byte for
small pc
changes (i.e. less than 128 bytes) and 3 bytes otherwise.
Similarly for
the gr registers, a 2 byte mask indicates which registers
have changed
and then only the changed registers are added to the change
log record.
Many change log records are therefore 5 bytes or less.
One interesting 'feature' of the current implementation is
that if a
program has been debugged to completion and then debugging
has started
again (i.e. the gdb 'target' command establishes a new
connection with
SID), one can debug backward past the beginning of the
program (with a
warning from SID) and back into the previous execution
instance. The
feature is handy in the case that you use the GDB continue
command and
end up at the end of the program by mistake.
Comments, ideas, and, of course, approval to commit the
infrastructure
patch please. I can also commit the xstormy16 specific parts
if desired.
Dave
sid/main/dynamic/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* mainDynamic.cxx (usage): Document --reversible.
(try_add_memory): Call sess->add_memory.
(option_num): add opt_reversible.
(long_options): Add "reversible".
(main): Handle opt_reversible.
* commonCfg.h (set_reversible): New method of SessionCfg.
(add_memory): Likewise.
(reversible_p): New member of SessionCfg.
(memory): Likewise.
* commonCfg.cxx (CpuCfg): Establish sim-sched relation.
(SessionCfg): Initialize reversible_p.
(SessionCfg::write_load): Set up all memory regions as
reversible,
if requested.
(BoardCfg::write_config): Set up the cpu to be reversible,
if
requested.
sid/include/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* sidmiscutil.h (change_log): New utility class.
* sidcpuutil.h (basic_cpu): Now inherits from
reversible_component.
(step_pin_handler): Parameter now named 'tick'. Save the
current
tick. Handle exec_direction == "backward".
Initialize change logging,
if reversible. Finish change logging, if reversible.
(step_backward): New method of basic_cpu.
(reset_pin_handler): Terminte the current change log, if
any.
Set exec_direction to "forward".
(change_log,change_log_begin,change_log_end,change_log_boun
daries)
(change_string,exec_direction,sim_sched,current_tick,last_t
ick): New
members of basic_cpu.
(init_change_logging,finish_change_logging,log_change)
(restore_state_to_time): New virtual methods of basic_cpu.
(basic_cpu): Initialize change_log, change_log_begin,
change_log_end, change_log_boundaries, last_tick,
exec_direction,
and sim_sched. Add the exec-direction and sim-sched
attributes.
* sidattrutil.h (reversible_component): New mix-in class.
sid/component/sched/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* compSched.cxx (deliver_regular): Drive rnext->when.
(deliver_irregular): Drive irnext->when.
(advancy_any): Check yield_step_loop_p.
(cancel_all): New method of generic_scheduler.
(time_set_pin): New member of scheduler_component.
(scheduler_component::set_time): Call set_now with 'then -
1'.
Call sched.cancel_all. Drive time_set_pin.
(scheduler_component_ctor_1): Add time-set pin.
sid/component/memory/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* generic.h: Remove 'using
sidutil::no_relation_component'. Add
'using sidutil::fixed_relation_map_component'.
(generic_memory): New inherits from reversible_component
and
fixed_relation_map_component. Now inherits virtually from
fixed_pin_map_component and fixed_attribute_map_component.
(sched): New member of generic_memory.
(change_log): Likewise.
(record_update): New method of generic_memory.
(restore_state_to_time): Likewise.
(generic_read_write_bus::write_any): call record_update if
this
memory is reversible.
* generic.cxx (generic_memory): Initialize sched and
change_log. Add sim-sched relation.
(record_update): New method of generic_memory.
(restore_state_to_time): Likewise.
sid/component/gdb/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* gdbserv-target.h (set_exec_direction): New member of
gdbserv_target.
* gdbserv-state.c (gdbserv_data_packet): Initialize
exec_direction.
Check for a 'b' prefix for the S, s, C, and c packets.
Call
gdbserv->target->set_exec_direction.
* gdb.h (set_exec_direction): New function prototype.
* gdb.cxx (set_exec_direction_hook): New function.
(gdbsid_target_attach): Set
gdbtarget->set_exec_direction.
(set_exec_direction): New function.
cgen/cpu/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* cpu/xstormy16.cpu (h-pc): Add a set handler.
(h-gr): Likewise.
sid/component/cgen-cpu/xstormy16/ChangeLog:
2006-09-15 Dave Brolley <brolley redhat.com>
* xstormy16.h (xstormy16_cpu_cgen): Now inherits from
cgen_bi_endian_cpu.
(h_pc_set_handler): New method of xstormy16_cpu_cgen.
(h_gr_set_handler,init_change_logging,finish_change_logging
)
(log_pc_change,log_gr_change,restore_change) Likewise.
(PC_UNCHANGED,PC_RESET,gr_changed,pc_changed,old_gr,old_h_p
c):
New members of xstormy16_cpu_cgen.
(xstormy16_cpu): Now inherits only from xstormy16_cpu_cgen.
* xstormy16.cxx (init_change_logging): New method of
xstormy16_cpu_cgen.
(finish_change_logging,log_pc_change,log_gr_change,restore_
change):
Likewise.
* xstormy16-cpu.h: Regenerated.
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<gdb*> (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,
"<gdbserv_data_packet:%c>\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<Scheduler>::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<reversible_component>
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 <sidschedutil.h>
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<basic_cpu> 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<basic_cpu> 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<unsigned> 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<MemCfg *>::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<const string, AtomicCfg *> 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<MemCfg *> memory;
virtual void write_config (Writer &w);
// Support for dynamic configuration profiles
vector<AtomicCfg *> 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"));
Index: cgen/cpu/xstormy16.cpu
============================================================
=======
RCS file: /cvs/src/src/cgen/cpu/xstormy16.cpu,v
retrieving revision 1.12
diff -c -p -r1.12 xstormy16.cpu
*** cgen/cpu/xstormy16.cpu 22 Jul 2004 01:49:27 -0000 1.12
--- cgen/cpu/xstormy16.cpu 15 Sep 2006 20:27:47 -0000
***************
*** 1,5 ****
; xstormy16 CPU core description. -*- Scheme -*-
! ; Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
; This file is part of CGEN.
; See file COPYING.CGEN for details.
--- 1,5 ----
; xstormy16 CPU core description. -*- Scheme -*-
! ; Copyright (C) 2001, 2002, 2003, 2006 Red Hat, Inc.
; This file is part of CGEN.
; See file COPYING.CGEN for details.
***************
*** 68,74 ****
; Hardware elements.
! (dsh h-pc "program counter" (PC) (pc))
(define-keyword
(name gr-names)
--- 68,80 ----
; Hardware elements.
! (define-hardware
! (name h-pc)
! (comment "program counter")
! (attrs PC)
! (type pc)
! (set (newval) (c-call "h_pc_set_handler"
newval))
! )
(define-keyword
(name gr-names)
***************
*** 92,98 ****
(type register WI (16))
(indices extern-keyword gr-names)
(get (index) (and #xFFFF (raw-reg h-gr index)))
! (set (index newval) (set (raw-reg h-gr index) (and
#xFFFF newval)))
)
(define-hardware
--- 98,104 ----
(type register WI (16))
(indices extern-keyword gr-names)
(get (index) (and #xFFFF (raw-reg h-gr index)))
! (set (index newval) (c-call
"h_gr_set_handler" index newval))
)
(define-hardware
Index: sid/component/cgen-cpu/xstormy16/xstormy16.cxx
============================================================
=======
RCS file:
/cvs/src/src/sid/component/cgen-cpu/xstormy16/xstormy16.cxx,
v
retrieving revision 1.3
diff -c -p -r1.3 xstormy16.cxx
*** sid/component/cgen-cpu/xstormy16/xstormy16.cxx 18 Feb
2003 22:57:29 -0000 1.3
--- sid/component/cgen-cpu/xstormy16/xstormy16.cxx 15 Sep
2006 20:27:52 -0000
***************
*** 1,7 ****
// xstormy16.cxx - Implementations of hand-written
functions for the Xstormy16
// simulator. -*- C++ -*-
! // Copyright (C) 2000 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 ----
// xstormy16.cxx - Implementations of hand-written
functions for the Xstormy16
// simulator. -*- C++ -*-
! // Copyright (C) 2000, 2006 Red Hat.
// This file is part of SID and is licensed under the GPL.
// See the file COPYING.SID for conditions for
redistribution.
*************** xstormy16_cpu::parity (int reg)
*** 363,365 ****
--- 363,507 ----
tmp ^= tmp >> 1;
return tmp & 1;
}
+
+ // Called before execution of an insn. Perform any tasks
associated with
+ // logging changes in the state of this cpu during
execution of an insn.
+ void
+ xstormy16_cpu_cgen::init_change_logging ()
+ {
+ // Call up to the base class.
+ cgen_bi_endian_cpu::init_change_logging ();
+
+ // We will be tracking changes to the pc and to the gr
registers.
+ gr_changed = 0;
+ pc_changed = PC_UNCHANGED;
+ }
+
+ // Called after execution of an insn. Log the changes
which occurred during
+ // execution of the insn.
+ void
+ xstormy16_cpu_cgen::finish_change_logging ()
+ {
+ // Call up to the base class.
+ cgen_bi_endian_cpu::finish_change_logging ();
+
+ // The largest possible record would contain:
+ // 1 byte representing the type of pc change
+ // A 16 bit mask indicating which gr registers changed
+ // Possibly the old pc value
+ // Old gr register values (if any)
+ char buffer[1 + 2 + sizeof (old_h_pc) + sizeof
(old_h_gr)];
+
+ // Record the nature of any pc or gr changes.
+ *(sid::host_int_1 *)(buffer + 0) = pc_changed;
+ *(sid::host_int_2 *)(buffer + 1) = gr_changed;
+
+ // If the pc change was too large to represent in the
byte written above, then
+ // record the old pc value.
+ unsigned bufix = 3;
+ if (pc_changed == PC_RESET)
+ {
+ *(USI *)(buffer + bufix) = old_h_pc;
+ bufix += sizeof (old_h_pc);
+ }
+
+ // Record the old values of any gr registers that
changed.
+ sid::host_int_2 mask = 1;
+ for (int i = 0; i < 16; ++i)
+ {
+ if ((gr_changed & mask) != 0)
+ {
+ *(SI *)(buffer + bufix) = old_h_gr[i];
+ bufix += sizeof (old_h_gr[i]);
+ // std::cout << ' ' << std::hex
<< old_h_gr[i] << std::dec;
+ }
+ mask <<= 1;
+ }
+
+ // Save the change log record we have just created.
+ log_change (buffer, bufix);
+ }
+
+ // Keep track of any changes to the pc.
+ void
+ xstormy16_cpu_cgen::log_pc_change (USI new_pc)
+ {
+ // If this is the first change, then save the original
pc value.
+ if (LIKELY (pc_changed == PC_UNCHANGED))
+ old_h_pc = this->hardware.h_pc;
+
+ // Most of the time, pc changes are small enough to
represented by one byte.
+ // Save these changes in 'pc_changed'.
+ //
+ // The value of PC_UNCHANGED is zero and so this
condition will be represented
+ // with no special handling.
+ //
+ // The special value PC_RESET is an odd number and
cannot occur under normal
+ // circumstances. It indicates a larger pc change.
+ SI diff = new_pc - old_h_pc;
+ if (LIKELY (-128 <= diff && diff <= 127))
+ pc_changed = diff;
+ else
+ pc_changed = PC_RESET;
+ }
+
+ // Keep track of any changes to gr registers. It is only
necessary to
+ // save the original value of a register the first time it
is changed.
+ void
+ xstormy16_cpu_cgen::log_gr_change (UINT regno, SI newval)
+ {
+ if (! (gr_changed & (1 << regno)))
+ {
+ gr_changed |= 1 << regno;
+ old_h_gr[regno] = this->hardware.h_gr[regno];
+ }
+ }
+
+ // Given a change log record, restore the state that it
represents.
+ void
+ xstormy16_cpu_cgen::restore_change (const char *data,
sid::host_int_4 length)
+ {
+ // The first byte indicates the nature of any change to
the pc.
+ assert (length >= 1);
+ sid::signed_host_int_1 pc_changed = *(sid::host_int_1
*)data;
+ ++data;
+ --length;
+
+ // The second two bytes are a bit mask indicating
changes to gr registers.
+ assert (length >= 2);
+ sid::host_int_2 gr_changed = *(sid::host_int_2 *)data;
+ data += 2;
+ length -= 2;
+
+ // Restore the pc.
+ if (UNLIKELY (pc_changed == PC_RESET))
+ {
+ // For large changes to the pc, the previous pc
value is recorded in the
+ // change log record.
+ this->hardware.h_pc = *(USI *)data;
+ data += sizeof (USI);
+ length -= sizeof (USI);
+ }
+ else
+ {
+ // Smaller changes to the pc are represented by a
one byte delta.
+ this->hardware.h_pc -= pc_changed;
+ }
+
+ // Restore any gr registers which changed.
+ sid::host_int_2 mask = 1;
+ for (int i = 0; i < 16; ++i)
+ {
+ if ((gr_changed & mask) != 0)
+ {
+ assert (length >= sizeof (SI));
+ this->hardware.h_gr[i] = *(SI *)data;
+ data += sizeof (SI);
+ length -= sizeof (SI);
+ }
+ mask <<= 1;
+ }
+
+ // The entire record must be consumed.
+ assert (length == 0);
+ }
Index: sid/component/cgen-cpu/xstormy16/xstormy16.h
============================================================
=======
RCS file:
/cvs/src/src/sid/component/cgen-cpu/xstormy16/xstormy16.h,v
retrieving revision 1.3
diff -c -p -r1.3 xstormy16.h
*** sid/component/cgen-cpu/xstormy16/xstormy16.h 26 Jun 2006
21:06:41 -0000 1.3
--- sid/component/cgen-cpu/xstormy16/xstormy16.h 15 Sep 2006
20:27:52 -0000
***************
*** 1,6 ****
// xstormy16.h - Hand-written code for the Sanyo Xstormy16
CPU. -*- C++ -*-
! // Copyright (C) 1999, 2000 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 ----
// xstormy16.h - Hand-written code for the Sanyo Xstormy16
CPU. -*- C++ -*-
! // Copyright (C) 1999, 2000, 2006 Red Hat.
// This file is part of SID and is licensed under the GPL.
// See the file COPYING.SID for conditions for
redistribution.
***************
*** 11,32 ****
namespace xstormy16
{
! class xstormy16_cpu_cgen
{
// Include cgen generated elements.
#include "xstormy16-cpu.h"
public:
inline void cgen_rtx_error(const char* msg) const
{
cerr << "xstormy16-cpu rtx error: "
<< msg << endl;
}
protected:
USI syscall_trap_num;
};
! class xstormy16_cpu: public xstormy16_cpu_cgen, public
cgen_bi_endian_cpu
{
private:
scache_engine<xstormy16_scache> engine;
--- 11,72 ----
namespace xstormy16
{
! class xstormy16_cpu_cgen: public cgen_bi_endian_cpu
{
// Include cgen generated elements.
#include "xstormy16-cpu.h"
public:
+ xstormy16_cpu_cgen () {}
+ ~xstormy16_cpu_cgen () throw() { };
+
+ protected:
+ // Log any changes to the pc, if we're reversible.
+ void h_pc_set_handler (USI newval)
+ {
+ if (UNLIKELY (this->reversible_p))
+ log_pc_change (newval);
+ this->hardware.h_pc = newval;
+ }
+
+ // Log any changes to the gr registers, if we're
reversible.
+ void h_gr_set_handler (UINT regno, SI newval)
+ {
+ if (UNLIKELY (this->reversible_p))
+ log_gr_change (regno, newval);
+ this->hardware.h_gr[regno] = (0xffff & newval);
+ }
+
+ // Stateful (reversible) component implementation
methods.
+ virtual void init_change_logging ();
+ virtual void finish_change_logging ();
+
+ void log_pc_change (USI new_pc);
+ void log_gr_change (UINT regno, SI newval);
+
+ virtual void restore_change (const char *data,
sid::host_int_4 length);
+
+ protected:
inline void cgen_rtx_error(const char* msg) const
{
cerr << "xstormy16-cpu rtx error: "
<< msg << endl;
}
+
protected:
USI syscall_trap_num;
+ // The values of these constants are significant and
must not be changed.
+ static const sid::signed_host_int_1 PC_UNCHANGED =
0x00;
+ static const sid::signed_host_int_1 PC_RESET = 0x01;
+
+ // State for change logging.
+ sid::host_int_2 gr_changed;
+ sid::signed_host_int_1 pc_changed;
+ SI old_h_gr[16];
+ USI old_h_pc;
};
! class xstormy16_cpu: public xstormy16_cpu_cgen
{
private:
scache_engine<xstormy16_scache> engine;
|